home *** CD-ROM | disk | FTP | other *** search
- ;; Simplex-Algorithmus und dessen Demonstration
- ;; Bruno Haible 25.09.1986, 30.5.1991
- ;; Version für Common Lisp
-
- (provide 'simplex)
-
- ; Typ einer Zahl: hier rationale Zahlen
- (deftype Zahl () 'rational) ; abgekürzt: R
- (deftype Zahl-Vektor () '(simple-array Zahl 1)) ; abgekürzt: R^n
- (deftype Zahl-Matrix () '(simple-array Zahl 2)) ; abgekürzt: R^mxn
-
- ; Input: A, eine mxn-Matrix von Zahlen,
- ; b, ein m-Vektor von Zahlen,
- ; c, ein n-Vektor von Zahlen.
- ; Löst eine kanonische Optimierungsaufgabe :
- ; ( C ) Finde unter den y ∈ R^n mit A*y=b, y≥0 diejenigen mit <c,y> = Min
- ; ( C* ) Finde unter den z ∈ R^m mit x=A`*z+c≥0 diejenigen mit <b,z> = Min
- ; Siehe Koulikov, Algèbre et théorie des nombres, Chap. 6.1.
- ; Output: 1. Wert: ob lösbar, NIL oder T,
- ; falls lösbar:
- ; 2. Wert: Lösung von ( C ), dem LP: Liste, bestehend aus
- ; - der Lösung y
- ; - dem optimalen Wert von <c,y>
- ; 3. Wert: Lösung von ( C* ), dem Dualproblem DP: Liste, bestehend aus
- ; - der Lösung x
- ; - den konstanten Gliedern Z für die z's
- ; - den Abhängigkeiten ZZ zwischen den z's
- ; - dem optimalen Wert von <b,z>
- ; Die allgemeine Lösung ist so aufgebaut:
- ; Falls ZZ[i,i]=T, ist die Variable z_i frei wählbar.
- ; Sonst ist ZZ[i,i]=NIL, und die Variable z_i errechnet sich als
- ; z_i = Z[i] + Summe(j=1,...,m mit Z[j,j]=T , ZZ[i,j]*z_j) .
- ; 4. Wert: ob die angegebenen Lösungen die gesamte Lösungsmenge
- ; ausmachen (T) oder ob möglicherweise noch eine andere
- ; Lösung existiert.
- ; In jedem Fall ist die Lösungsmenge konvex.
- ; Methode:
- ; Methode von Dantzig, siehe Koulikov-Buch;
- ; Zusatz für entarteten Fall nach Bronstein/Semendjajew.
- (defun simplex (A b c)
- ; Input überprüfen:
- (let ((m (length b))
- (n (length c)))
- (declare (type fixnum m n))
- (assert (typep A `(array * (,m ,n))))
- ; m = die Höhe der Matrix, in der gearbeitet wird.
- ; n = die Breite der Matrix, in der gearbeitet wird.
- ; Initialisierung:
- (let ((AA (let ((h (make-array `(,m ,n))))
- (dotimes (i m)
- (dotimes (j n)
- (setf (aref h i j) (rational (aref A i j)))
- ) )
- h
- ) )
- (AB (let ((h (make-array m)))
- (dotimes (i m) (setf (aref h i) (rational (elt b i))))
- h
- ) )
- (AC (let ((h (make-array n)))
- (dotimes (j n) (setf (aref h j) (rational (elt c j))))
- h
- ) )
- (AD 0)
- ; AA ∈ R^mxn : das Tableau, in dem gearbeitet wird
- ; AB ∈ R^m : der rechte Rand
- ; AC ∈ R^n : der untere Rand
- ; AD ∈ R : die rechte untere Ecke
- (Extend nil)
- (AAE nil)
- (ACE nil)
- ; Extend ∈ Boolean : sind die Zusatzspalten (Entartungsfall) aktiv?
- ; AAE ∈ R^mxm : Zusatzspalten für den Entartungsfall
- ; ACE ∈ R^m : unterer Rand der Zusatzspalten
- (Zeile (let ((h (make-array m)))
- (dotimes (i m) (setf (aref h i) (cons 'ZO i)))
- h
- ) )
- (Spalte (let ((h (make-array n)))
- (dotimes (j n) (setf (aref h j) (cons 'XY j)))
- h
- ) )
- ; Zeile ∈ Cons^m : linke Markierungen
- ; Spalte ∈ Cons^n : obere Markierungen
- ;
- ; Skizze des Tableaus:
- ;
- ; | Zeile[0] Zeile[1] ... Zeile[n-1] |
- ; ------------+-------------------------------------+---------
- ; Spalte[0] | AA[0,0] AA[0,1] ... AA[0,n-1] | AB[0]
- ; Spalte[1] | AA[1,0] AA[1,1] ... AA[1,n-1] | AB[1]
- ; ... | ... ... ... | ...
- ; Spalte[m-1] | AA[m-1,0] AA[m-1,1] ... AA[m-1,n-1] | AB[m-1]
- ; ------------+-------------------------------------+---------
- ; | AC[0] AC[1] ... AC[n-1] | AD
- ;
- ; Markierung von Spalten: 0 oder Y
- ; ... ...
- ; Z X
- ;
- ; Markierung von Zeilen: Z ... 0 oder X ... -Y.
- ;
- ; für alle i=0,...,m-1:
- ; Summe(j=0,...,n-1; AA[i,j]*(0 oder Y[Spalte[j].Nr])) - AB[i] =
- ; = (0 oder -Y[Zeile[i].Nr])
- ; für alle j=0,...,n-1:
- ; Summe(i=0,...,m-1; AA[i,j]*(Z[Zeile[i].Nr] oder X[Zeile[i].Nr])) + AC[j] =
- ; = (Z[Spalte[j].Nr] oder X[Spalte[j].Nr])
- ; Summe(j=1,...,N; AC[j]*(0 oder Y[Spalte[j].Nr])) - AD = <c,y>
- ; Summe(i=1,...,M; AB[i]*(Z[Zeile[i].Nr] oder X[Zeile[i].Nr])) + AD = <b,z>
- ; Dieses ist als Gleichung mit den Unbekannten X,Y,Z zu verstehen.
- ;
- ; Die Zusatzspalten sind - wenn vorhanden - rechts anzufügen.
- ;
- (ZZ (let ((h (make-array `(,m ,m) :initial-element 0)))
- (dotimes (i m) (setf (aref h i i) nil))
- h
- ) )
- (Z (make-array m))
- (Y (make-array n))
- (X (make-array n))
- )
- (declare (type Zahl-Matrix AA) (type Zahl-Vektor AB AC) (type Zahl AD))
- (flet
- ((pivot (k l)
- (declare (type fixnum k l))
- ; pivotiert das Tableau das Element AA[k,l] mit 0≤k<m, 0≤l<n.
- ; Invariante ist, daß vor und nach dem Pivotieren die obigen
- ; Gleichungen gelten.
- (let ((r (/ (aref AA k l))))
- (declare (type Zahl r))
- ; Spalte l :
- (progn
- (dotimes (i m)
- (unless (eql i k)
- (setf (aref AA i l) (- (* r (aref AA i l))))
- ) ) )
- (setf (aref AC l) (- (* r (aref AC l))))
- ; alles außer Zeile k, Spalte l :
- (dotimes (j n)
- (unless (eql j l)
- (let ((s (aref AA k j)))
- (dotimes (i m)
- (unless (eql i k)
- (setf (aref AA i j) (+ (aref AA i j) (* s (aref AA i l))))
- ) )
- (setf (aref AC j) (+ (aref AC j) (* s (aref AC l))))
- ) ) )
- (let ((s (aref AB k)))
- (dotimes (i m)
- (unless (eql i k)
- (setf (aref AB i) (+ (aref AB i) (* s (aref AA i l))))
- ) )
- (setf AD (+ AD (* s (aref AC l))))
- )
- (when Extend
- (locally (declare (type Zahl-Matrix AAE) (type Zahl-Vektor ACE))
- (dotimes (j m)
- (let ((s (aref AAE k j)))
- (dotimes (i m)
- (unless (eql i k)
- (setf (aref AAE i j) (+ (aref AAE i j) (* s (aref AA i l))))
- ) )
- (setf (aref ACE j) (+ (aref ACE j) (* s (aref AC l))))
- ) ) ) )
- ; Zeile k :
- (progn
- (dotimes (j n)
- (unless (eql j l)
- (setf (aref AA k j) (* (aref AA k j) r))
- ) )
- (setf (aref AB k) (* (aref AB k) r))
- )
- (when Extend
- (locally (declare (type Zahl-Matrix AAE))
- (dotimes (j m)
- (setf (aref AAE k j) (* (aref AAE k j) r))
- ) ) )
- ; Element (k,l) :
- (setf (aref AA k l) r)
- ; Markierungen vertauschen:
- (rotatef (aref Zeile k) (aref Spalte l))
- )) )
- ; Variablen Z nach unten schaffen, evtl. Matrix verkleinern:
- (let ((elbar (make-array m :fill-pointer 0))
- (not-elbar (make-array m :fill-pointer 0)))
- ; elbar = Menge der eliminierbaren z,
- ; not-elbar = Menge der nicht eliminierbaren z.
- (dotimes (i m)
- ; Suche Betragsmaximum in Zeile i:
- (let ((hmax 0) (l nil))
- (dotimes (j n)
- (when (eq (car (aref Spalte j)) 'XY)
- (let ((h (abs (aref AA i j))))
- (when (> h hmax) (setq hmax h l j))
- ) ) )
- (if l
- ; AA[i,l] war betragsmäßig maximal
- (progn
- (vector-push i not-elbar)
- (pivot i l)
- )
- ; triviale Zeile
- (if (zerop (aref AB i))
- ; Führe diese Zeile noch pro forma weiter; sie wird sich
- ; aber nicht weiter ändern, weil stets nur um XY-Spalten
- ; pivotiert werden wird und in diesen Spalten in Zeile i
- ; überall 0 steht.
- ; Nicht-Null-Elemente stehen nur in ZO-Spalten, und die
- ; verändern sich nicht mehr.
- (vector-push i elbar)
- ; Zeile fürs LP widerspruchsvoll -> unlösbar
- (return-from simplex NIL)
- ) ) ) )
- ; eliminierbare Zeilen in der ZZ-Matrix vormerken:
- ; Die nicht eliminierbaren Zeilen haben mit den X ihre Plätze
- ; getauscht, so daß also Spalte[(cdr Zeile[i])] = (ZO . i) gilt,
- ; falls Zeile i nicht eliminierbar ( <==> (car Zeile[i]) = XY ).
- (dotimes (i0h (fill-pointer elbar))
- (let ((i0 (aref elbar i0h)))
- (setf (aref Z i0) 0) ; nur wenn man Z[i0]=0 setzt, stimmen die anderen Z's!
- (setf (aref ZZ i0 i0) T) ; z_i0 frei wählbar
- (dotimes (ih (fill-pointer not-elbar))
- (let* ((i (aref not-elbar ih)) ; es muß (car Zeile[i])=XY sein
- (j (cdr (aref Zeile i)))) ; Spalte, mit der Zeile i pivotiert wurde
- (setf (aref ZZ i i0) (aref AA i0 j))
- ) ) ) )
- ; Zeilen streichen: (benutze dabei, daß alle not-elbar[i]>=i)
- (dotimes (ih (fill-pointer not-elbar))
- (let ((i (aref not-elbar ih)))
- (unless (eql ih i)
- (dotimes (j n) (setf (aref AA ih j) (aref AA i j)))
- (setf (aref AB ih) (aref AB i))
- ) ) )
- (setq m (fill-pointer not-elbar)) ; neue Zeilenzahl = Anzahl der ZO-Spalten
- )
- ; Spalten umsortieren: XY links, ZO rechts bringen.
- ; Damit werden am Schluß die nicht eliminierbaren z aus den X errechnet.
- (let ((l 0) ; linke Spalte
- (r (1- n))) ; rechte Spalte
- (loop
- (unless (< l r) (return))
- (cond ((eq (car (aref Spalte l)) 'XY) (incf l))
- ((eq (car (aref Spalte r)) 'ZO) (decf r))
- (t ; Vertausche Spalten r und l
- (dotimes (i m) (rotatef (aref AA i l) (aref AA i r)))
- (rotatef (aref AC l) (aref AC r))
- (rotatef (aref Spalte l) (aref Spalte r))
- ) )
- ) )
- ; Verstecke diese M Spalten vor dem Pivotieren:
- (setq n (- n m))
- ; Die Elemente AA[0..m-1,n..n+m-1], AC[n..n+m-1], Spalte[n,n+m-1]
- ; werden erst am Schluß von Teil 6 wieder benötigt.
- (let ((Zeile_save (copy-seq Zeile)))
- (flet
- ((SuchePivotZeile (AWZM l)
- ; Bestimmt zur Auswahlmenge AWZM der zu untersuchenden Zeilen
- ; und zur Spalte l die Zeile k so:
- ; Vorausgesetzt ist, daß
- ; für i∈AWZM gilt 0≤i<m und AB[i]≥0 und AA[i,l]>0.
- ; k ist unter allen i∈AWZM dasjenige, für das der Quotient
- ; AB[i]/AA[i,l] minimal ist. Sollte er =0 sein oder ist sowieso
- ; Extend=true, so ist nachher Extend=true, und es wurde der Vek-
- ; tor (AB[i]/AA[i,l], AAE[i,1]/AA[i,l], ..., AAE[i,m-1]/AA[i,l])
- ; unter allen i∈AWZM lexikographisch minimiert. Falls AWZM leer
- ; ist, ist NIL das Ergebnis.
- (if (eql (fill-pointer AWZM) 0)
- NIL
- (let (k)
- (unless Extend ; versuche k passend zu wählen
- (let (hmax)
- (dotimes (ih (fill-pointer AWZM))
- (let* ((i (aref AWZM ih))
- (h (/ (aref AB i) (aref AA i l))))
- (when (or (eql ih 0) (< h hmax)) (setq hmax h k i))
- ) )
- (when (zerop hmax)
- ; entarteter Fall
- (setq Extend T)
- (setq AAE (make-array `(,m ,m) :initial-element 0))
- (dotimes (i m) (setf (aref AAE i i) 1))
- (setq ACE (make-array m :initial-element 0))
- ) ) )
- (when Extend
- ; Der Entartungsfall liegt entweder seit längerem vor
- ; oder ist erst jetzt aufgetreten (dann war das alte k
- ; vielleicht schlecht).
- (let (hmax hmaxe)
- (dotimes (ih (fill-pointer AWZM))
- (let ((i (aref AWZM ih)))
- (let ((h (/ (aref AA i l)))
- (he (make-array m)))
- (dotimes (j m) (setf (aref he j) (* (aref AAE i j) h)))
- (setq h (* (aref AB i) h))
- ; (h,he[1],...,he[M]) ist jetzt der Quotientenvektor
- (when (or (eql ih 0)
- ; statt (< h hmax) jetzt lexikographisch
- ; (h,he[1],...,he[M]) < (hmax,hmaxe[1],...,hmaxe[M])
- ; vergleichen:
- (or (< h hmax)
- (and (= h hmax)
- (dotimes (ie m NIL)
- (let* ((he_ie (aref he ie))
- (hmaxe_ie (aref hmaxe ie)))
- (when (< he_ie hmaxe_ie) (return T))
- (when (> he_ie hmaxe_ie) (return NIL))
- ) ) ) ) )
- (setq hmax h hmaxe he k i)
- ) ) ) ) ) )
- k
- )) ) )
- (let ((PZM (make-array m :fill-pointer 0)))
- ; PZM = Menge der i mit AB[i]≥0
- (loop ; Spalte AB mit positiven Zahlen füllen
- #|
- ; Rundungsfehler ausmerzen:
- (dotimes (ih (fill-pointer PZM))
- (let ((i (aref PZM ih)))
- (when (minusp (aref AB i)) (setq (aref AB i) 0))
- ) )
- |#
- (let ((NZM (make-array m :fill-pointer 0)))
- ; NZM = Menge der i mit AB[i]<0
- ; PZM und NZM neu berechnen:
- (let ((old-PZM-count (fill-pointer PZM))) ; alte Mächtigkeit von PZM
- (setf (fill-pointer PZM) 0)
- (dotimes (i m)
- (if (>= (aref AB i) 0)
- (vector-push i PZM)
- (vector-push i NZM)
- ) )
- ; Streiche die Zusatzspalten, wenn sich PZM echt vergrößert
- ; hat und die Entartung daher vielleicht verschwunden ist.
- (when (> (fill-pointer PZM) old-PZM-count) (setq Extend nil))
- )
- (when (eql (fill-pointer NZM) 0) (return)) ; alle AB[i]≥0 ?
- ; wähle p aus: p:= dasjenige i mit AB[i]<0,
- ; bei dem die Anzahl der AA[i,j]≥0 maximal ist.
- (let ((countmax -1) (p nil))
- (dotimes (ih (fill-pointer NZM))
- (let ((i (aref NZM ih))
- (count 0))
- (dotimes (j n) (when (>= (aref AA i j) 0) (incf count)))
- (when (> count countmax) (setq countmax count p i))
- ) )
- (when (eql countmax n)
- ; alle AA[p,j]≥0, aber AB[p]<0
- ; ==> Zeile fürs LP widerspruchsvoll ==> unlösbar
- (return-from simplex NIL)
- )
- ; Wähle l aus: maximales abs(AA[p,j]) unter allen j mit AA[p,j]<0
- ; (solche gibt es, da countmax<n).
- (let ((hmin 0) (l nil))
- (dotimes (j n)
- (let ((h (aref AA p j)))
- (when (< h hmin) (setq hmin h l j))
- ) )
- ; AWZM aufbauen:
- (let ((AWZM (make-array m :fill-pointer 0)))
- (dotimes (ih (fill-pointer PZM))
- (let ((i (aref PZM ih)))
- (when (> (aref AA i l) 0) (vector-push i AWZM))
- ) )
- (let ((k (SuchePivotZeile AWZM l)))
- (if (null k)
- ; Durch Pivotieren um AA[p,l] wächst PZM um
- ; mindestens das eine Element p, denn:
- ; für i∈PZM gilt AB[i]≥0 und wegen AZWM=ϕ
- ; auch AA[i,l]≤0, also nachher
- ; AB[i]=AB[i]-AB[p]*AA[i,l]/AA[p,l] ≥0,
- ; ≥0 <0 ≤0 <0
- ; also wieder i∈PZM.
- ; Aber nachher auch AB[p]=AB[p]/AA[p,l] (<0/<0) >0,
- ; also p∈PZM.
- (progn
- (setq Extend nil) ; brauche die Zusatzspalten jetzt nicht mehr
- (pivot p l)
- )
- ; Pivotzeile k ausgewählt; fertig zum Pivotieren
- ; Durch Pivotieren um AA[k,l] wird PZM nicht
- ; verkleinert, denn:
- ; für i∈PZM gilt AB[i]≥0.
- ; Falls AA[i,l]≤0, gilt nachher
- ; AB[i]=AB[i]-AB[k]*AA[i,l]/AA[k,l] ≥0.
- ; ≥0 ≥0 ≤0 >0
- ; Falls jedoch AA[i,l]>0, so gilt für i<>k nachher
- ; AB[i]=AA[i,l]*(AB[i]/AA[i,l]-AB[k]/AA[k,l]) ≥0
- ; >0 ≥0 nach Wahl von k wegen i∈AWZM
- ; und für i=k nachher AB[k]=AB[k]/AA[k,l] (≥0/>0) ≥0.
- ; Also nachher stets wieder AB[i]≥0, d.h. i∈PZM.
- (pivot k l)
- ) ) ) ) ) )
- ) )
- ; Jetzt ist Extend=false, weil (fill-pointer PZM) sich gerade
- ; auf m erhöht haben muß.
- ; Ab hier sind alle AB[i]≥0, und diese Eigenschaft geht nicht verloren.
- (loop
- ; Suche ein l mit AC[l]<0 :
- (let (l)
- (when
- (dotimes (j n T)
- (when (< (aref AC j) 0) (setq l j) (return NIL))
- )
- (return) ; alle AC[j]≥0 ==> lösbar
- )
- ; AWZM := Menge der i mit AA[i,l]>0 :
- (let ((AWZM (make-array m :fill-pointer 0)))
- (dotimes (i m)
- (when (> (aref AA i l) 0) (vector-push i AWZM))
- )
- (let ((k (SuchePivotZeile AWZM l)))
- (if (null k)
- ; alle AA[i,l]≤0 und AC[l]<0 ==> Spalte fürs DP widerspruchsvoll
- (return-from simplex NIL)
- (pivot k l)
- ; weiterhin alle AB[i]≥0.
- ; AD:=AD-AB[k]*AC[l]/AA[k,l] ≥ AD wird nicht verkleinert.
- ; ≥0 <0 >0
- ) ) ) )
- )
- ; Lösbar! Lösung bauen:
- (let ((vollständig t))
- (dotimes (i m)
- (let ((s (aref AB i))
- (index (cdr (aref Zeile i))))
- (setf (aref X index) 0 (aref Y index) s)
- (setq vollständig (and vollständig (> s 0)))
- ) )
- (dotimes (j n)
- (let ((s (aref AC j))
- (index (cdr (aref Spalte j))))
- (setf (aref X index) s (aref Y index) 0)
- (setq vollständig (and vollständig (> s 0)))
- ) )
- ; Die nicht eliminierbaren z-Werte berechnen sich aus dem
- ; verstecken Teil von AA und AC und den Werten von X und Y :
- (do ((j n (1+ j)))
- ((>= j (+ n m)))
- (let ((s (aref AC j)))
- (dotimes (i m)
- (setq s (+ s (* (aref AA i j) (aref X (cdr (aref Zeile_save i))))))
- )
- (setf (aref Z (cdr (aref Spalte j))) s)
- ) )
- (values T (list Y (- AD)) (list X Z ZZ AD) vollständig)
- ) ) ) ) ) ) )
-
- (defun test-simplex (aufg)
- (multiple-value-bind (m n) (values-list (array-dimensions (first aufg)))
- (let ((x-list
- (mapcar #'(lambda (i) (format nil "X[~D]" i))
- (make-sequence 'list n :initial-element 1 :update #'1+)
- ) )
- (y-list
- (mapcar #'(lambda (i) (format nil "Y[~D]" i))
- (make-sequence 'list n :initial-element 1 :update #'1+)
- ) )
- (z-list
- (mapcar #'(lambda (i) (format nil "Z[~D]" i))
- (make-sequence 'list m :initial-element 1 :update #'1+)
- )) )
- ; Aufgabe ausgeben:
- (multiple-value-bind (A b c) (values-list aufg)
- (format t "~%~%Lineares Problem:")
- (dotimes (i m)
- (let ((zeile (make-array n)))
- (dotimes (j n) (setf (aref zeile j) (aref A i j)))
- (format t "~%~{~1{~S * ~A~:}~^ + ~} = ~S"
- (remove 0 (mapcar #'list (coerce zeile 'list) y-list)
- :key #'first :test #'=
- )
- (aref b i)
- ) ) )
- (format t "~%mit ~{~A~^, ~} ≥ 0" y-list)
- (format t "~%Minimiere ~{~1{~S * ~A~:}~^ + ~}."
- (remove 0 (mapcar #'list (coerce c 'list) y-list)
- :key #'first :test #'=
- ) )
- (format t "~%Dualproblem:")
- (dotimes (j n)
- (let ((spalte (make-array m)))
- (dotimes (i m) (setf (aref spalte i) (aref A i j)))
- (format t "~%~A = ~:{~S * ~A + ~} ~S ≥ 0"
- (elt x-list j)
- (remove 0 (mapcar #'list (coerce spalte 'list) z-list)
- :key #'first :test #'=
- )
- (aref c j)
- ) ) )
- (format t "~%Minimiere ~{~1{~S * ~A~:}~^ + ~}."
- (remove 0 (mapcar #'list (coerce b 'list) z-list)
- :key #'first :test #'=
- ) )
- )
- (let ((lösung (multiple-value-list (apply #'simplex aufg))))
- ; Lösung ausgeben:
- (if (first lösung)
- (progn
- (format t "~%~%~:[Eine~;Die einzige~] Lösung ist:" (fourth lösung))
- (let ((LP-lösung (second lösung)))
- (format t "~%~{~1{~A = ~S~:}~^, ~}~%Minimum = ~S"
- (mapcar #'list y-list (coerce (first LP-lösung) 'list))
- (second LP-lösung)
- ) )
- (let ((DP-lösung (third lösung)))
- (let ((Z (second DP-lösung))
- (ZZ (third DP-lösung)))
- (dotimes (i m)
- (format t "~%~A = " (elt z-list i))
- (if (aref ZZ i i)
- (format t "beliebig")
- (format t "~S~:{ + ~S * ~A~}"
- (aref Z i)
- (let ((L nil))
- (dotimes (j m)
- (when (aref ZZ j j)
- (unless (zerop (aref ZZ i j))
- (push (list (aref ZZ i j) (elt z-list j))
- L
- ) ) ) )
- (nreverse L)
- ) )
- ) ) )
- (format t "~%~{~1{~A = ~S~:}~^, ~}~%Minimum = ~S"
- (mapcar #'list x-list (coerce (first DP-lösung) 'list))
- (fourth DP-lösung)
- ) ) )
- (format t "~%unlösbar")
- )
- lösung
- ) ) ) )
-
- (defun test ()
- (mapcar #'test-simplex
- '((#2A((1 0 1 -1 -1 3)
- (0 1 2 -1 -1/2 1))
- #(0 0)
- #(0 0 -1 -1 -3 8)
- )
- (#2A((1 -1 -1 3 1 0)
- (2 -1 -1/2 1 0 1))
- #(0 0)
- #(-1 -1 -3 8 0 0)
- )
- (#2A((1 1 0 1)
- (2 0 1 0))
- #(1 1)
- #(-1 1 -2 0)
- )
- (#2A((1 1 2 1 3 -1 0)
- (2 -2 3 1 1 0 -1))
- #(4 3)
- #(2 3 5 2 3 0 0)
- )
- (#2A(( 1 8 0 -1 0 0 0)
- (-3 -7 -20 0 -1 0 0)
- ( 1 0 0 0 0 -1 0)
- ( 0 -1 0 0 0 0 -1)
- ( 1 1 1 0 0 0 0))
- #(3 -6 2/5 -1/2 1)
- #(5 2 1/4 0 0 0 0)
- )
- (#2A((1 2 1 1 -2)
- (1 1 -4 -2 -3)
- (1 2 5 -4 6))
- #(4 2 3)
- #(3 5 4 5 6)
- )
- (#2A((1 2 -1 1)
- (2 -2 3 3)
- (1 -1 2 -1))
- #(0 9 6)
- #(-3 1 3 -1)
- ))
- ) )
-
-