home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Modul : phase2.c *
- * Zweck : Phase II des Simplexalgorithmus *
- * Autor : Stefan Förster *
- * *
- * Datum | Version | Bemerkung *
- * -----------|---------|--------------------------------------------------- *
- * 06.02.1989 | 0.0 | *
- * 07.02.1989 | 0.1 | Anpassung an PHASE_I *
- * 25.02.1989 | 0.2 | CHUZR(), WRETA(), 1. Testlauf erfolgreich *
- * 26.02.1989 | 0.3 | PRICE() verbessert *
- * 26.02.1989 | 0.4 | VERBOSE-Option, Reinvertierung von AB1 *
- * 02.03.1989 | 0.5 | Bug in CHUZR(): dqi<-EPS_NULL statt dqi<EPS_NULL *
- * | | Bug in PRICE(): sum-=pi[qs-nm] statt sum-=pi[qs] *
- * | | Bug in PRICE(): Bei PHASE_I hat A phys. nm Spalten *
- * | | Bug in FTRAN(): Bei PHASE_I hat A phys. nm Spalten *
- * | | Bug in WRETA(): M(A,phase==PHASE_I?nm:n,i,j,phase) *
- * 03.03.1989 | | Bug in CHUZR(): Abfrage if(lambdaX==INFINITE||...) *
- * | 1.0 | Bug in FTRAN(): ptr1 += m statt *ptr1 += m !!!! *
- * | | Abfrage auf Invertierbarkeit von AB *
- * 04.03.1989 | 1.1 | Bug in WRETA(): c0-Änderung, wenn Nq[s-1]<0 ist *
- * 06.03.1989 | 1.2 | Bug in WRETA(): else ptr1+=m; bei AB1-Update *
- * | | Neustrukturierung von WRETA() *
- * 10.03.1989 | 1.3 | c0start, lower zusätzlich übergeben *
- *****************************************************************************/
-
-
- IMPORT VOID Mult();
- IMPORT USHORT Invers();
- IMPORT DOUBLE M();
- IMPORT VOID SetM();
-
- GLOBAL DOUBLE INFINITE;
- GLOBAL BOOL minimize;
- GLOBAL FILE *file[2];
-
-
- /*****************************************************************************
- * USHORT PhaseII() *
- * - OPTIMAL, falls optimale Lösung gefunden *
- * - UNBOUNDED, falls das Problem unbeschränkt ist *
- * - NOT_INVERTABLE, falls (unzulässigerweise!) AB nicht invertierbar ist *
- * *
- * Input: B, Nq, *
- * A, AB1, *
- * b, b2q, *
- * c, c0, c0start, *
- * flag, *
- * upper, lower bzw. NULL (für Phase1()) *
- * Output: x, c0, B, Nq *
- *****************************************************************************/
-
- USHORT PhaseII(m,n,B,Nq,A,AB1,b,b2q,c,c0,c0start,flags,upper,lower,x,cq,pi,dq,
- Nminus,help,iter)
-
- SHORT m,n; /* m = Zeilenzahl, n = Spaltenzahl des Problems */
- SHORT *B; /* (m)-Vektor - Basis */
- SHORT *Nq; /* (n-m)-Vektor - E-Nichtbasis */
- DOUBLE *A; /* (m,n)-Matrix - Matrix A */
- DOUBLE *AB1; /* (m,m)-Matrix - Inverse von AB */
- DOUBLE *b; /* (m)-Vektor - RHS (rechte Seite) */
- DOUBLE *b2q; /* (m)-Vektor - bq-AB1*AN*uN_ */
- DOUBLE *c; /* (n)-Vektor - Vektor c */
- DOUBLE *c0; /* Zahl (Zeiger!) - Zielfunktionswert */
- DOUBLE c0start; /* Korrekturwert für Zielfunktionswert *
- USHORT flags; /* Flags - PHASE_I/PHASE_II,VERBOSE */
- DOUBLE *upper; /* (n)-Vektor - Obergrenzen für x */
- DOUBLE *lower; /* (n)-Vektor - Untergrenzen für x */
- DOUBLE *x; /* (n)-Vektor - Lösung (falls existiert) */
- DOUBLE *cq; /* (n-m)-Vektor - reduzierte Kosten */
- DOUBLE *pi; /* (m)-Vektor - pi = cB*AB1 */
- DOUBLE *dq; /* (m)-Vektor - dq = AB1*A.qs */
- SHORT *Nminus; /* (n-m)-Vektor - Negativer Anteil von Nq */
- DOUBLE *help; /* (m)-Vektor - Hilfsvektor */
- ULONG *iter; /* Zeiger auf "Anzahl Iterationen" */
-
- {
- USHORT method = STEEPEST_ASCENT, rowflag = LAMBDA_0;
- USHORT phase = flags & (PHASE_I | PHASE_II), verbose = flags & VERBOSE;
- SHORT r ,s ,nm = n-m, i, qs, lastpos = nm-1; /* lastpos: 0,...,(n-m)-1 */
- DOUBLE c0_old;
- VOID BTRAN(), FTRAN();
- USHORT PRICE(), CHUZR(), WRETA();
- ULONG count = 1L;
-
-
- for( ; ; count++) {
-
- c0_old = *c0;
-
- if(rowflag!=LAMBDA_2) BTRAN(m,AB1,B,c,pi,x);
-
- if(PRICE(m,n,A,Nq,c,cq,pi,&s,method|phase,&lastpos)==OPTIMAL) {
- for(i=0; i<nm; ++i) {
- qs = ABS(Nq[i])-1;
- if(lower) x[qs] = Nq[i]>0 ? lower[qs] : upper[qs]+lower[qs];
- else x[qs] = Nq[i]>0 ? 0.0 : upper[qs];
- }
- for(i=0; i<m; ++i) {
- if(lower) x[B[i]-1] = b2q[i]+lower[qs];
- else x[B[i]-1] = b2q[i];
- }
- *iter = count;
- return(OPTIMAL);
- }
-
- FTRAN(m,n,AB1,A,Nq[s-1],dq,phase);
-
- if(CHUZR(m,dq,b2q,upper,B,Nq[s-1],s,&r,&rowflag)==UNBOUNDED) {
- *iter = count;
- return(UNBOUNDED);
- }
-
- /* x als eta-Vektor mißbrauchen */
- if(WRETA(m,n,B,Nq,A,AB1,b,b2q,c,cq,c0,c0start,dq,upper,r,s,x,help,
- Nminus,rowflag|phase|verbose,count) == NOT_INVERTABLE)
- return(NOT_INVERTABLE);
-
- if(verbose) {
- printf("@@ ");
- if(phase == PHASE_I) printf("phase I : ");
- else printf("phase II: ");
- printf("iter# %5ld : s =%4d, r =",count,s);
- if(rowflag == LAMBDA_2) printf(" np , ");
- else printf("%4d, ",r);
- printf("c0 = %16.10lg\n",minimize ? -(*c0) : *c0);
- if(method==STEEPEST_ASCENT) puts(" steepest-ascent-rule");
- else puts(" cyclic smallest-index-rule");
- if(file[1]) {
- fprintf(file[1],"@@ ");
- if(phase == PHASE_I) fprintf(file[1],"phase I : ");
- else fprintf(file[1],"phase II: ");
- fprintf(file[1],"iter# %5ld : s =%4d, r =",count,s);
- if(rowflag == LAMBDA_2) fprintf(file[1]," np , ");
- else fprintf(file[1],"%4d, ",r);
- fprintf(file[1],"c0 = %16.10lg\n",minimize ? -(*c0) : *c0);
- if(method==STEEPEST_ASCENT) fputs(" steepest-ascent-rule\n",file[1]);
- else fputs(" cyclic smallest-index-rule\n",file[1]);
- }
- }
-
- if(fabs(c0_old)>EPS_NULL)
- method = (*c0-c0_old)/fabs(c0_old) <= PERCENT ? STEEPEST_ASCENT :
- SMALLEST_INDEX;
- }
- }
-
-
-
- /*****************************************************************************
- * VOID BTRAN() *
- * Backward Transformation *
- *****************************************************************************/
-
- VOID BTRAN(m,AB1,B,c,pi,dummy)
-
- SHORT m;
- DOUBLE *AB1;
- SHORT *B;
- DOUBLE *c, *pi, *dummy; /* dummy : (m)-Hilfsvektor */
-
- {
- DOUBLE *ptr=dummy;
- SHORT i;
-
- for(i=0; i<m; ++i) *ptr++ = c[B[i]-1];
- Mult(dummy,AB1,pi,1,m,m);
-
- }
-
-
-
- /*****************************************************************************
- * USHORT PRICE() -> OPTIMAL/NOT_OPTIMAL *
- * method & STEEPEST_ASCENT => Steilster-Anstieg-Regel *
- * method & SMALLEST_INDEX => (zyklische) Kleinster-Index-Regel *
- *****************************************************************************/
-
- USHORT PRICE(m,n,A,Nq,c,cq,pi,s,flags,lastpos)
-
- SHORT m, n;
- DOUBLE *A;
- SHORT *Nq;
- DOUBLE *c, *cq, *pi;
- SHORT *s;
- USHORT flags; /* PHASE_I/PHASE_II, SMALLEST_INDEX/STEEPEST_ASCENT */
- SHORT *lastpos;
-
- {
- REGISTER DOUBLE *ptr1, *ptr2, sum;
- REGISTER SHORT j, i;
- SHORT qs, nm = n-m, pos;
- USHORT flag = OPTIMAL;
- USHORT phase = flags & (PHASE_I | PHASE_II);
- USHORT method = flags & (SMALLEST_INDEX | STEEPEST_ASCENT);
- SHORT columns = phase==PHASE_I ? nm : n;
- DOUBLE dummy;
-
- if(method == STEEPEST_ASCENT) {
- for(i=0; i<nm; ++i) {
- ptr1 = pi;
- qs = ABS(Nq[i])-1;
- sum = c[qs];
- if(phase == PHASE_I && qs>=nm) sum -= pi[qs-nm];
- else {
- ptr2 = A+qs;
- for(j=0; j<m; ++j) {
- sum -= (*ptr1++)*(*ptr2);
- ptr2 += columns;
- }
- }
- cq[i] = sum;
- }
- for(i=0; i<nm; ++i) {
- if((dummy=fabs(cq[i])) > EPS_NULL && cq[i]*Nq[i] > 0.0) {
- if(flag==OPTIMAL) {
- flag = NOT_OPTIMAL;
- *s = i+1; /* Index s : 1,...,n-m */
- sum = dummy;
- }
- else {
- if(dummy>sum) {
- *s = i+1;
- sum = dummy;
- }
- }
- }
- }
- }
-
- else { /* method == SMALLEST_INDEX */
- pos = ((*lastpos)+1) % nm; /* lastpos+1 modulo nm */
- for(i=0; i<nm; ++i) {
- ptr1 = pi;
- qs = ABS(Nq[pos])-1;
- sum = c[qs];
- if(phase == PHASE_I && qs>=nm) sum -= pi[qs-nm];
- else {
- ptr2 = A+qs;
- for(j=0; j<m; ++j) {
- sum -= (*ptr1++)*(*ptr2);
- ptr2 += columns;
- }
- }
- if(fabs(sum)>EPS_NULL && sum*Nq[pos]>0.0) {
- cq[pos] = sum;
- *s = pos+1; /* s: Index 1,...,nm */
- *lastpos = pos;
- return(NOT_OPTIMAL);
- }
- ++pos;
- pos %= nm;
- }
- }
-
- return(flag);
- }
-
-
-
- /*****************************************************************************
- * VOID FTRAN() *
- * Forward Transformation *
- *****************************************************************************/
-
- VOID FTRAN(m,n,AB1,A,qs,dq,phase)
-
- SHORT m, n;
- DOUBLE *AB1, *A;
- SHORT qs;
- DOUBLE *dq;
- USHORT phase;
-
- {
- REGISTER DOUBLE *ptr1, sum;
- REGISTER SHORT j, i;
- SHORT nm = n-m, columns = phase==PHASE_I ? nm : n;
-
- qs = ABS(qs)-1;
- if(phase == PHASE_I && qs>=nm) {
- ptr1 = AB1 + (qs-nm);
- for(i=0; i<m; ++i) {
- dq[i] = *ptr1;
- ptr1 += m;
- }
- }
- else {
- for(i=0; i<m; ++i) {
- ptr1 = A+qs;
- sum = 0.0;
- for(j=0; j<m; ++j) {
- sum += (*AB1++)*(*ptr1);
- ptr1 += columns;
- }
- dq[i] = sum;
- }
- }
-
- }
-
-
-
- /*****************************************************************************
- * USHORT CHUZR() -> UNBOUNDED/NOT_UNBOUNDED *
- * Ergebnis: Zeile r, rowflag (Art des Pivotschritts) *
- *****************************************************************************/
-
- USHORT CHUZR(m,dq,b2q,upper,B,qs,s,r,rowflag)
-
- SHORT m;
- DOUBLE *dq, *b2q, *upper;
- SHORT *B, qs, s, *r; /* qs: 0,...,n-1 s: 1,...,n-m r: 1,...,m */
- USHORT *rowflag; /* LAMBDA_0, LAMBDA_1 oder LAMBDA_2 */
-
- {
- REGISTER DOUBLE lambda0 = INFINITE, lambda1 = INFINITE;
- REGISTER SHORT i;
- DOUBLE lambda2 = upper[ABS(qs)-1];
- REGISTER DOUBLE dqi, dummy, min = lambda2;
- SHORT sigma = SGN(qs), min_i;
-
- *rowflag = LAMBDA_2;
-
- for(i=0; i<m; ++i) {
- dqi = sigma*dq[i];
- if(dqi > EPS_NULL) {
- dummy = b2q[i]/dqi;
- if(lambda0 == INFINITE || dummy<lambda0) lambda0 = dummy;
- if(min==INFINITE || dummy<min || dummy==min &&
- fabs(dqi)>fabs(dq[min_i-1])) {
- lambda0 = min = dummy;
- min_i = i+1;
- *rowflag = LAMBDA_0;
- }
- }
- else if(dqi < -EPS_NULL && (dummy = upper[B[i]-1])!=INFINITE) {
- dummy = (b2q[i]-dummy)/dqi;
- if(lambda1 == INFINITE || dummy<lambda1) lambda1 = dummy;
- if(min==INFINITE || dummy<min || dummy==min &&
- fabs(dqi)>fabs(dq[min_i-1])) {
- lambda1 = min = dummy;
- min_i = i+1;
- *rowflag = LAMBDA_1;
- }
- }
- }
-
- *r = min_i;
-
- if(lambda0==INFINITE && lambda1==INFINITE && lambda2==INFINITE)
- return(UNBOUNDED);
-
- return(NOT_UNBOUNDED);
- }
-
-
-
- /*****************************************************************************
- * USHORT WRETA() -> INVERTABLE/NOT_INVERTABLE *
- * je nachdem, ob AB invertierbar ist (sollte es zumindest) oder nicht *
- *****************************************************************************/
-
- USHORT WRETA(m,n,B,Nq,A,AB1,b,b2q,c,cq,c0,c0start,dq,upper,r,s,eta,
- help,Nminus,flags,iter)
-
- SHORT m, n;
- SHORT *B, *Nq;
- DOUBLE *A, *AB1, *b, *b2q, *c, *cq, *c0, c0start, *dq, *upper;
- SHORT r, s;
- DOUBLE *eta, *help; /* eta : (n)-Vektor (=x), als (m)-Vektor verw. */
- SHORT *Nminus; /* Nminus (n-m)-Vektor, negativer Anteil von Nq */
- USHORT flags; /* PHASE_I/PHASE_II, rowflag, verbose */
- ULONG iter; /* Zahl der bewältigten Iterationen */
-
- {
- REGISTER DOUBLE *ptr1, *ptr2, eta_r = 1.0/dq[r-1], eta_dummy;
- REGISTER SHORT j, i;
- LONG offset = (LONG)(r-1)*(LONG)m;
- SHORT anzneg = 0; /* Anzahl negativer Elemente in Nq */
- SHORT nm = n-m, swap;
- USHORT phase = flags & (PHASE_I | PHASE_II);
- USHORT rowflag = flags & (LAMBDA_0 | LAMBDA_1 | LAMBDA_2);
- SHORT columns = phase==PHASE_I ? nm : n;
-
-
- iter %= INVERT_FREQUENCY;
-
- if(rowflag != LAMBDA_2) {
-
- /* Falls Nq[s-1]<0 ist, ändert sich c0 zusätzlich !!!! */
- /* Falls AB1 reinvertiert wird, wird c0 jedoch völlig neu berechnet */
- if(Nq[s-1]<0) *c0 -= cq[s-1]*upper[ABS(Nq[s-1])-1];
-
- swap = B[r-1];
- B[r-1] = ABS(Nq[s-1]);
- Nq[s-1] = rowflag == LAMBDA_0 ? swap : -swap;
-
- for(j=0; j<nm; ++j) {
- if(Nq[j]<0) Nminus[anzneg++] = ABS(Nq[j]);
- }
-
- if(!iter) { /* AB1 reinvertieren */
-
- if(flags & VERBOSE) {
- printf("@@ ");
- if(phase == PHASE_I) printf("phase I : ");
- else printf("phase II: ");
- puts("reinversion");
- if(file[1]) {
- fprintf(file[1],"@@ ");
- if(phase == PHASE_I) fprintf(file[1],"phase I : ");
- else fprintf(file[1],"phase II: ");
- fputs("reinversion\n",file[1]);
- }
- }
-
- for(j=1; j<=m; ++j) {
- swap = B[j-1]; /* B[j].te Spalte von A */
- for(i=1; i<=m; ++i) SetM(AB1,m,i,j,M(A,columns,i,swap,phase));
- }
- /* x==eta als (SHORT *)-Permutationsvektor !! */
- if(Invers(AB1,m,(SHORT *)eta) == NOT_INVERTABLE) return(NOT_INVERTABLE);
- }
-
- else { /* AB1 nicht reinvertieren, sondern nur mit eta mult. */
-
- ptr1 = eta;
- ptr2 = dq;
-
- for(j=1; j<=m; ++j) {
- *ptr1++ = j==r ? eta_r : -(*ptr2)*eta_r;
- ++ptr2;
- }
-
- ptr1 = AB1;
-
- for(i=0; i<m; ++i) {
- ptr2 = AB1+offset;
- if(i+1==r) ptr1 += m; /* r.te Zeile überspringen */
- else {
- if((eta_dummy = eta[i]) != 0.0) {
- for(j=0; j<m; ++j) *ptr1++ += eta_dummy*(*ptr2++);
- }
- else ptr1 += m;
- }
- }
-
- ptr2 = AB1+offset;
-
- for(j=0; j<m; ++j) *ptr2++ *= eta_r; /* r.te Spalte mit eta_r mult. */
- }
-
-
- for(i=0; i<m; ++i) {
- eta_dummy = b[i];
- for(j=0; j<anzneg; ++j)
- eta_dummy -= M(A,columns,i+1,Nminus[j],phase)*upper[Nminus[j]-1];
- eta[i] = eta_dummy;
- }
-
- Mult(AB1,eta,b2q,m,m,1); /* eta-Vektor als Zwischenspeicher */
-
- if(iter) *c0 += cq[s-1]*b2q[r-1];
- else {
- eta_dummy = 0.0;
- ptr1 = b2q;
- for(i=0; i<m; ++i) eta_dummy += c[B[i]-1]*(*ptr1++);
- for(i=0; i<anzneg; ++i) {
- j = Nminus[i]-1;
- eta_dummy += c[j]*upper[j];
- }
- *c0 = eta_dummy+c0start;
- }
-
- }
-
-
-
- else { /* rowflag == LAMBDA_2 */
-
- if(!iter) { /* AB1 reinvertieren */
-
- if(flags & VERBOSE) {
- printf("@@ ");
- if(phase == PHASE_I) printf("phase I : ");
- else printf("phase II: ");
- puts("reinversion");
- if(file[1]) {
- fprintf(file[1],"@@ ");
- if(phase == PHASE_I) fprintf(file[1],"phase I : ");
- else fprintf(file[1],"phase II: ");
- fputs("reinversion\n",file[1]);
- }
- }
-
- for(j=1; j<=m; ++j) {
- swap = B[j-1]; /* B[j].te Spalte von A */
- for(i=1; i<=m; ++i) SetM(AB1,m,i,j,M(A,columns,i,swap,phase));
- }
- /* x==eta als (SHORT *)-Permutationsvektor !! */
- if(Invers(AB1,m,(SHORT *)eta) == NOT_INVERTABLE) return(NOT_INVERTABLE);
- }
-
- swap = Nq[s-1]; /* swap : qs_quer */
- anzneg = ABS(swap); /* anzneg : qs */
- eta_dummy = upper[anzneg-1]; /* eta_dummy : u(qs) */
-
- ptr1 = eta;
- for(i=1; i<=m; ++i) *ptr1++ = M(A,columns,i,anzneg,phase)*eta_dummy;
-
- Mult(AB1,eta,help,m,m,1);
-
- ptr1 = b2q;
- ptr2 = help;
-
- if(swap>0) { /* wenn also das alte qs_quer positiv war */
- for(i=0; i<m; ++i) *ptr1++ -= *ptr2++;
- *c0 += cq[s-1]*upper[anzneg-1];
- }
- else {
- for(i=0; i<m; ++i) *ptr1++ += *ptr2++;
- *c0 -= cq[s-1]*upper[anzneg-1];
- }
-
- Nq[s-1] *= -1; /* qs_quer auf neuen Stand bringen */
- }
-
- return(INVERTABLE);
- }
-