⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 _simplex.c

📁 数据类型和算法库LEDA 数据类型和算法库LEDA
💻 C
字号:
/*******************************************************************************
+
+  LEDA  3.0
+
+
+  _simplex.c
+
+
+  Copyright (c) 1992  by  Max-Planck-Institut fuer Informatik
+  Im Stadtwald, 6600 Saarbruecken, FRG     
+  All rights reserved.
+ 
*******************************************************************************/


/****************************************************************************
*                                                                           *
*    simplex.c                                                              *
*    *********                                                              *
*    ist ein Programm zur Loesung linearer Programme !                      *
*    *************************************************                      *
*                                                                           *
*    Die Implementierung basiert auf dem Zweiphasen-Simplex-Verfahren       *
*    aus Dinkelbach, Operations Research, Kapitel 1.                        *
*                                                                           *
*    Kommentare und die Wahl der Bezeichnernamen beziehen sich in der       *
*    Regel auf die entsprechenden Stellen im Buch.                          *
*                                                                           *
*    29.06.1992                                                             *
*                                                                           *
*    Sascha Portz und Johannes Helders                                      *
*                                                                           *
****************************************************************************/


#include <LEDA/simplex.h>


static void Init_Tableau (matrix A, matrix& M, vector c, vector b,int kl,int gr,
		   int gl, int *&B, int *&NB, int zeilen, int spalten, int n)
{
   int nb = n;                      // Zaehler zur Initialisierung der Menge NB

   for ( int s=0 ; s<n; s++ )
      M(0,s+1) = -c[s];

   for (int z=0; z<kl; z++ )
   {
      for ( int s=0; s < n; s++ )
	 M(z+1,s+1) = A(z,s);
      M(z+1,n+z+1) = 1;              // Schlupfvariablen setzen
      B[z] = n+z+1;                  // der z.te Basisvektor
   }

   for ( z=0; z<gr; z++ )
   {
      for ( int s=0; s < n; s++ )
	 M(kl+z+1,s+1) = A(kl+z,s);
      M(z+kl+1,n+z+kl+1) = -1;        // bei >= Nebenbedingungen neg. Schlupf
      M(z+kl+1,n+kl+gr+z+1) = 1;      // kuenstliche Variable
      B[kl+z] = n+kl+gr+z+1;          // der kl+gr+z.te Basisvektor
      NB[nb] = n+kl+z+1; nb++;        // n+kl+gr+z ist Nichtbasisvaiable
      M(zeilen-1,n+kl+gr+z+1) = 1;    // Initialisieren der Hilfszielfunktion
   }

   for ( z=0; z<gl; z++ )
   {
      for ( int s=0; s<n; s++ )
	 M(z+kl+gr+1,s+1) = A(z+kl+gr,s);
      M(z+kl+gr+1,n+kl+2*gr+z+1) = 1;  // kuenstliche Variable
      B[kl+gr+z] = kl+2*gr+n+z+1;      // der z.te Basisvektor
      M(zeilen-1,n+kl+2*gr+z+1) = 1;   //Initialisieren der Hilfszielfunktion
   }

   for ( z=0; z<b.dim(); z++)
      M(z+1,0) = b[z];

   for( s=0; s < n ; s++)               // 1,...,n sind Nichtbasisvariablen
      NB[s] = s+1;

   for ( z=kl+1; z<=kl+gr+gl; z++)      // Subtrahieren der Zeilen mit kuenstl.
      for ( s=0; s<spalten; s++)   	// Variablen von der letzten Zeile
	 M(zeilen-1,s) = M(zeilen-1,s) - M(z,s);

}


static void InitIntArray (int *&A, int *B, int l)

// Initialisiert das int-Array A der Laenge l mit dem int-Array B

{
   for (int i=0; i<l; i++)
      A[i] = B[i];
}


static void InitMatrix (matrix &A, matrix B, int dim1, int dim2)

// Initialisierung der Matrix A mit der Matrix B

{
   for (int l=0; l<dim1; l++)
      for (int m=0; m<dim2; m++)
	 A(l,m) = B(l,m);
}


static int PivotSpalte (matrix M, int *&NB, int z, int l, int m)

// in der Zeile z (z=0 oder z = m+1) wird die Pivotspalte gesucht

// l ist die Groesse der Menge der Nichtbasisvariablen

// accept = 1 impliziert die Gueltigkeit der gefundenen Pivotspalte, d.h.
// es gibt in dieser Zeile ein Element, das > 0 ist,
// ist dies nicht der Fall so wird nach einer neuen Pivotspalte gesucht
// iter zaehlt die Anzahl der Iterationen

{
   double eps = 0.00001;	// das Intervall [-eps..eps] entspricht NULL

   double min=-eps;
   double minmin=-10000;
   int mins = 0;
   int p, accept = 0;
   int iter = 1;

   while ( (accept == 0) && (iter <= l) )
   {
      for (int q=0; q<l; q++)
	 if ( ( M(z,NB[q]) <= min ) && ( M(z,NB[q]) > minmin ) )
	 {
	    min = M(z,NB[q]);
	    mins = NB[q];
	 }

      p = 1;                                // Test ob die gefundene Spalte
      while ( (p <= m) && (accept == 0) )   // als Pivotspalte akzeptiert
      {                                     // wird
	 if ( M(p,mins) > eps )
	    accept = 1;
	 p++;
      }

      if (accept == 0)                      // falls nicht
      {                                     // -> Suche nach der naechst-
	 minmin = min; 		            // besten Pivotspalte
	 min = -eps;
	 q = 0;
	 mins = 0;
      }
      iter++;
   }

   return mins;
}


static int D_PivotSpalte (matrix M, int *&NB, int z,int n,int kl,int gr)

// Liefert die Pivotspalte fuer einen Dualsimplexschritt in der Zeile z

{
   double eps = 0.00001;	// das Intervall [-eps..eps] entspricht NULL

   double min = 1000;
   int mins = 0;

   for(int q=0; q<n+gr; q++)
      if ( ( M(z,NB[q]) < -eps ) && ( NB[q] <= n+kl+gr ) )
	 if ( min >= -M(0,NB[q]) / M(z,NB[q]) )
	 {
	    min = -M(0,NB[q]) / M(z,NB[q]);
	    mins = NB[q];
	 }
   return mins;
}


static int PivotZeile (matrix M, int s, int m)

// Liefert die Pivotzeile fuer einen Primalsimplexschritt in der Spalte s

{
   double eps = 0.00001;	// das Intervall [-eps..eps] entspricht NULL

   int minz = 0;
   double min = 1000;

   for (int p=1; p<=m; p++)
      if ( M(p,s) > eps )
	  if (min > M(p,0)/M(p,s) )
	  {
	     min = M(p,0)/M(p,s);
	     minz = p;
	  }
   return minz;
}


static void Basiswechsel (matrix &M, int p, int q, int n,int kl, int gr, int gl)

// Basiswechsel : siehe Dinkelbach

{
   double pivot = M(p,q);
   double pivot2;
   int spalten = n+kl+2*gr+gl;
   int zeilen = kl+gr+gl;

   for (int s=0; s<=spalten; s++)
      M(p,s)= M(p,s)/pivot;
   for (int z=0; z<p; z++)
   {
      pivot2 = M(z,q);
      for (int s=0; s<=spalten; s++)
	 M(z,s) = M(z,s)-M(p,s)*pivot2;
   }
   for (z=p+1; z<=zeilen+1; z++)
   {
      pivot2 = M(z,q);
      for (int s=0; s<=spalten; s++)
	 M(z,s) = M(z,s)-M(p,s)*pivot2;
   }
}


static void NB_NNB_Update (int *&B, int *&NB, int p, int q, int l)

// Nach jedem Simplex-Schritt werden die Mengen der Basis- ( B ) und
// Nichtbasisvariablen ( NB ) neu berechnet

// p und q bezeichnen die Pivotzeile bzw die Pivotspalte

// l ist die Groesse der Menge der Nichtbasisvariablen (diese aendert
// sich im Laufe des Verfahrens)

{
   int h1, h2;

   for (int x=0; x<l; x++)
      if (NB[x] == q)
	 h1 = x;
   h2 = B[p-1];
   B [p-1] = q;
   NB [h1] = h2;
}


static void NNB_Update (int *&NB, int n, int kl, int gr, int gl)

// Veringerung der Menge der Nichtbasisvariablen um die k抧stlichen Variablen

{
   int *nnb = new int[n-gl];
   int m = 0;

   for (int l=0; l<n+gr; l++)
      if ( NB[l] <= n+kl+gr )
      {
	 nnb[m] = NB[l];
	 m++;
      }
   delete NB;
   NB = nnb;
}


static int nicht_optimal (matrix &M, int n, int kl, int gr)

// returniert 1, wenn das Simplextableau nicht optimal ist, sonst 0

{
   double eps = 0.00001;	// das Intervall [-eps..eps] entspricht NULL

   int not_opt = 0;
   for (int i=1; i<=n+gr+kl; i++)
      if ( M(0,i) < -eps )
	 not_opt = 1;
   return not_opt;
}


static void Eliminiere_kuenstl_Var (matrix M, int *&B, int *&NB, int &error,
			     int m, int n, int kl, int gr, int gl)

// die kuenstlichen Variablen, die noch Basisvariablen sind, werden zu
// Nichtbasisvariablen "pivotiert"

{
   int q;

   int l=0;
   while ( (l<m) && nicht_optimal(M,n,kl,gr) )
   {
      if (B[l] > n+kl+gr)
      {
	 q = D_PivotSpalte (M,NB,l+1,n,kl,gr);
         if ( (q != 0) && ( error == 0 ) )
	 {
	    Basiswechsel (M,l+1,q,n,kl,gr,gl);
	    NB_NNB_Update (B,NB,l+1,q,n+gr);
	 }
	 else
	    error = 1;
      }
      l++;
   }
   if ( (error==0) && nicht_optimal(M,n,kl,gr) )
      NNB_Update (NB,n,kl,gr,gl);
}


static vector Basisloesung (matrix M, int *B, int m, int n)

// returniert eine optimale Basisloesung

{
   vector X(n);

   for (int l=0; l<m; l++)
      if ( B[l] <= n )
	 X[B[l]-1] = M(l+1,0);

   return X;
}


static vector Extremalstrahl (matrix M, int *&B, int *&MF, int l, int m, int n)

// returniert die Steigung des Extremalstrahls

{
   vector s(n);

   for (int j=0; j<m; j++)
      if ( B[j] <= n )
	s[B[j]-1] = -M(j+1,MF[l]);

   if ( MF[l] <= n )
      s[MF[l]-1]=1;

   return s;
}


static int ZERO (vector v,int n)

// returniert 1, falls v gleich dem Nullvektor ist, sonst 0

{
   double eps = 0.00001;	// das Intervall [-eps..eps] entspricht NULL

   int zero = 1;

   for (int i=0; i<n; i++)
      if ( (v[i] < -eps) || (v[i] > eps) )
         zero = 0;

   return zero;
}


static void Init_Matrix (matrix &A, vector x, int n)

// initialisiert die (1xn)-Matrix mit dem Vektor x

{
   for (int i=0; i<n; i++)
      A(0,i) = x[i];
}


static void Enlarge_Matrix (matrix &A, vector v, int n)

// vergroessert die Matrix A um den Zeilenvektor v

{
   int dim1 = A.dim1();
   matrix B(dim1+1,A.dim2());

   InitMatrix (B,A,dim1,A.dim2());

   for (int i=0; i<n; i++)
      B(dim1,i) = v[i];

   A = B;
}


static void Test_auf_Extremalstrahl (matrix &M,int *&B,int *&NB,list<matrix>& L,
			      int *&MF, int *&PZ, int i, vector x, int m, 
                              int n, int kl, int gr)

// Berechnung und Ausgabe eines optimalen Extremalstrahls
// Aufbau der Liste L der optimalen Loesungen

{
   vector s(n);
   matrix A (1,n);

   Init_Matrix (A,x,n);

   for (int l=0; l<i; l++)
      if ( NB[l] <= n+gr+kl )             // Test ob im optimalen Tableau ein
	 if ( M(0,NB[l]) == 0 )        // Zielfunktionskoeffient einer Nicht-
	    MF[l] = NB[l];                // basisvariable = 0 ist
	 else
	    MF[l] = 0;
      else
         MF[l] = 0;

   for ( l=0; l<i; l++)
   {
      if ( MF[l] > 0 )
      {
	 PZ[l] = PivotZeile (M,MF[l],m);
	 if ( PZ[l] == 0 )
	 {
	    s = Extremalstrahl (M,B,MF,l,m,n);
	    if ( !ZERO(s,n) )
	       Enlarge_Matrix (A,s,n);
	 }
      }
   }

   L.append (A);
}


static
void Test_auf_Mehrfachloesungen(matrix &M,int *&B,int *&NB,list<matrix> &L,
				int x, vector v,int zeilen, int spalten,
				int m, int n, int kl, int gr, int gl)

// Berechnung von eventuell existierenden weiteren optimalen Basisloesungen
// x ist die Groesse der Menge der Nichtbasisvariablen

{
				    // Hilfsmatrix zur Berechnung weiterer
   matrix A (m+2,n+kl+2*gr+gl+1);   // optimaler Simplextableaus

   int *MF = new int[x];              // fuer die Indizes der Spalten in
				      // denen die 0.te Zeile =0 ist
   int *PZ = new int[x];              // die zugehoerigen Pivotzeilen

   int *H1 = new int[x];              // Hilfsarrays
   int *H2 = new int[x];

   int *b = new int [m];              // Hilfsarrays fuer B
   int *nb = new int [x];             // und NB


   Test_auf_Extremalstrahl (M,B,NB,L,MF,PZ,x,v,m,n,kl,gr);

   for (int l=0; l<x; l++)
   {
      if ( MF[l] > 0 )
	 if ( PZ[l] > 0 )
	 {
	    InitMatrix (A,M,zeilen,spalten);
	    InitIntArray (b,B,m);
	    InitIntArray (nb,NB,x);
	    Basiswechsel (A,PZ[l],MF[l],n,kl,gr,gl);
	    NB_NNB_Update (b,nb,PZ[l],MF[l],x);
	    v = Basisloesung (A,b,m,n);
	    Test_auf_Extremalstrahl (A,b,nb,L,H1,H2,x,v,m,n,kl,gr);
						 // H1, H2 sind Hilfsarrays
	 }
   }
   delete MF; delete PZ; delete H1;
   delete H2; delete b; delete nb;
}


static
void Run (matrix &M, int *&B, int *&NB, list<matrix> &L, int zeilen, 
          int spalten, int m, int n, int kl, int gr, int gl)

// Hauptprozedur

{
   double eps = 0.00001;	// das Intervall [-eps..eps] entspricht NULL

   int p, q;
   int error=0;
   vector x;

   q = PivotSpalte (M,NB,m+1,n+gr,m);
   while (q != 0)
   {
      p = PivotZeile (M,q,m);
      if (p != 0)
      {
	 Basiswechsel (M,p,q,n,kl,gr,gl);
	 NB_NNB_Update (B,NB,p,q,n+gr);
      }
      q = PivotSpalte (M,NB,m+1,n+gr,m);
   }

   if ( ( M(m+1,0) > -eps ) && ( M(m+1,0) < eps ) )
   {

      Eliminiere_kuenstl_Var (M,B,NB,error,m,n,kl,gr,gl);
      if ( nicht_optimal (M,n,kl,gr) )
      {

// falls error = 1 so konnte ein notwendiger Dualsimplexschritt nicht
// durchgefuehrt werden

	 if ( error == 0 )
	 {
	    q = PivotSpalte (M,NB,0,n-gl,m);
	    while (q != 0)
	    {
	       p = PivotZeile (M,q,m);
	       if (p != 0)
	       {
		  Basiswechsel (M,p,q,n,kl,gr,gl);
		  NB_NNB_Update (B,NB,p,q,n-gl);
	       }
	       q = PivotSpalte (M,NB,0,n-gl,m);
	    }
	    x = Basisloesung(M,B,m,n);
	    Test_auf_Mehrfachloesungen(M,B,NB,L,n-gl,x,zeilen,
				       spalten,m,n,kl,gr,gl);
	 }
      }
      else                              // das Tableau war schon optimal
      {
	  x = Basisloesung(M,B,m,n);
	  Test_auf_Mehrfachloesungen (M,B,NB,L,n+gr,x,zeilen,
				      spalten,m,n,kl,gr,gl);
      }
   }
}


list<matrix> SIMPLEX(matrix A, int i, int j, int k, vector b, vector c)
{
   int *B; int *NB;
 
   list<matrix> L;

   int kl =i,  gr=j, gl=k;
   int n = A.dim2(),m = A.dim1();		// setzen der globalen Variablen
   int zeilen = m+2, spalten = n+m+gr+1;

   matrix M(zeilen,spalten);
   B  = new int[m];
   NB = new int[n+gr];

   Init_Tableau(A,M,c,b,i,j,k,B,NB,zeilen,spalten,n);

   Run (M,B,NB,L,zeilen,spalten,m,n,kl,gr,gl);

   delete B; delete NB;

   return L;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -