1
;;; -*- Mode: Lisp -*- ;;;;
2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;
6
;; ;;; ~*~ SIMPLEX ~*~ ;;; ;;
8
;; ;;; A simple implementation of the simplex ;;; ;;
9
;; ;;; algorithm for Linear Programming for Maxima. ;;; ;;
12
;; ;;; Copyright: Andrej Vodopivec <andrejv@users.sourceforge.net> ;;; ;;
13
;; ;;; Version: 1.02 ;;; ;;
14
;; ;;; License: GPL ;;; ;;
16
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;
22
;; To get optimal speed this file should be compiled. ;;
24
;; linear_program(A, b, c): ;;
26
;; - problem: - find x which minimizes c'.x with constraints A.x=b and x>=0 ;;
28
;; - input: - matrix A of size mxn, ;;
29
;; - vector (list) b of length m, ;;
30
;; - vector (list) c of length n ;;
32
;; - output: - [x, val] if the problem is solvable; ;;
33
;; x is the optimal vector, val=c'.x ;;
34
;; - "Problem not bounded" if the problem is not bounded ;;
35
;; - "Problem not feasible" if the problem is not feasible ;;
37
;; - algorithm: a simple implementation of the two-phase simplex algorithm ;;
43
;; We would like to minimize x-2*y subject to: ;;
50
;; We have to introduce two slack variables for inequalities to get a ;;
51
;; linear program in the standard form: ;;
54
;; 2*x - 3*y - s2 = 1 ;;
56
;; x, y, s1, s2 >= 0 ;;
58
;; Construct parameters: ;;
60
;; A : matrix([1,1,-1,0],[2,-3,0,-1], [4,-5,0,0]); ;;
66
;; linear_program(A, b, c); ;;
67
;; => [[13/2, 4, 19/2, 0], -3/2] ;;
69
;; The solution is: x=13/2 and y=4 (s1=19/2, s2=0), and the value of the ;;
70
;; minimum is x-2*y=-3/2. ;;
76
;; - pivot_count_sx: the number of pivots in last computation ;;
77
;; - pivot_max_sx: the maximum number of pivots in computation ;;
78
;; - epsilon_sx: epsilon for numeric computation (default: 1e-8) ;;
79
;; - scale_sx: should maxima scale the problem: can be used in ;;
80
;; Klee-Minty problem to speed-up computation or in some ;;
81
;; cases to improve numerical stability (default: false); ;;
82
;; uses equilibratium scaling ;;
84
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
87
(macsyma-module simplex)
89
(proclaim '(optimize (speed 3) (safety 0) (space 0) (compilation-speed 0)))
91
($put '$simplex 1.02 '$version)
93
(defmvar $pivot_count_sx 0 "Number of pivots in last problem." fixnum)
94
(defmvar $pivot_max_sx 15000 "Maximum number of pivots allowed." fixnum)
95
(defmvar $epsilon_sx 1e-8 "Epsilon for numerical computation." flonum)
96
(defmvar $scale_sx nil "Should we scale the input." boolean)
98
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
100
;; Two-phase standard simplex method for solving linear program in standard ;;
103
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
105
(defun $linear_program (A b c)
106
(if (not ($matrixp A))
107
(merror "linear_program: first argument not matrix."))
109
(merror "linear_program: second argument not list."))
111
(merror "linear_program: third argument not list."))
112
(if (not (meqp ($length b) ($length A)))
113
(merror "linear_program: second argument not of correct length."))
114
(if (not (meqp ($length c) ($length ($first A))))
115
(merror "linear_program: third argument not of correct length."))
117
(let* ((m ($length A))
118
(n ($length ($first A)))
119
(Tab (make-array `(,(+ 2 m) ,(1+ n)))) ; Tableau
120
(basis ()) ; which columns are in current basis
121
(sc-fac ())) ; scaling factors
123
(setq $pivot_count_sx 0)
125
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
126
;; Construct the tableau for phase 1: ;;
129
;; [ sm(A) sm(b) ] ;;
131
;; If b[i]<0 multiply b[i] and A[i] by -1 (required for phase 1). ;;
132
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
134
(if (mlsp (maref b (1+ i)) 0)
137
(setf (aref Tab i j) (neg (maref A (1+ i) (1+ j)))))
138
(setf (aref Tab i n) (neg (maref b (1+ i)))))
141
(setf (aref Tab i j) (maref A (1+ i) (1+ j))))
142
(setf (aref Tab i n) (maref b (1+ i))))))
144
(setf (aref Tab m i) (neg (maref c (1+ i)))))
146
(setf (aref Tab (1+ m) i) 0)
148
(setf (aref Tab (1+ m) i) (add (aref Tab (1+ m) i)
150
(setf (aref Tab (1+ m) n) 0)
152
(setf (aref Tab (1+ m) n) (add (aref Tab (1+ m) n)
154
(setf (aref Tab m n) 0)
156
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
157
;; At the beginning the artificial variables are in the basis. ;;
158
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
160
(setq basis (append basis (list (add n i)))))
162
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
164
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
166
(setq sc-fac (append sc-fac (list 1))))
168
(scale-sx Tab (+ 2 m) (1+ n) sc-fac))
170
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
174
(simplex-sx Tab basis m (+ 2 m) (1+ n))
176
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
178
(if (mlsp $epsilon_sx (aref Tab (1+ m) n))
179
"Problem not feasible!"
182
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
183
;; Check for artificial variables in basis. ;;
184
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
187
(if (>= (nth i basis) n)
188
(if (not (run-out-of-basis-sx Tab m n basis i))
189
($print "Matrix A is not of full rank:"
190
"Row" (1+ i) "is redundant!"))))
192
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
194
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
196
(setq is-bounded (simplex-sx Tab basis m (1+ m) (1+ n)))
198
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
204
(setq opt-tmp (append opt-tmp (list 0))))
206
(setf (nth (nth i basis) opt-tmp)
207
(div (aref Tab i n) ;; undo the
208
(nth (nth i basis) sc-fac)))) ;; scaling
210
(setq opt (append opt (list 0))))
212
(setf (nth i opt) (nth i opt-tmp)))
213
(setq opt (cons '(mlist simp) opt)) ;; build the
214
(setq opt `((mlist simp) ,opt ;; the solution
216
"Problem not bounded!")))))
219
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
221
;; Simplex algorithm. ;;
223
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
225
(defun simplex-sx (Tab basis Am m n)
226
(let ((ip) (jp) (tmp) (is-bounded))
227
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
228
;; Repeat while we don't have a solution or know that the ;;
229
;; problem is unbounded. ;;
230
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
231
(do ((have-solution nil))
232
((not (null have-solution)))
233
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
234
;; Choose jp so that jp-th column has the biggest reduced cost. ;;
235
;; If all reduced costs are negative, we have the solution. ;;
236
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
237
(setq tmp (aref Tab (1- m) 0))
240
(if (mlsp tmp (aref Tab (1- m) j))
242
(setq tmp (aref Tab (1- m) j))
244
(if (or (mlsp tmp $epsilon_sx)
245
(meqp tmp $epsilon_sx))
248
(setq have-solution t))
250
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
251
;; Choose ip so that Tab[ip,n]/Tab[ip,jp] is the smallest ;;
252
;; possible among those for which Tab[i,n] is positive. If all ;;
253
;; Tab[i,n] are negative, the problem is unbounded. ;;
254
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
258
(if (mlsp $epsilon_sx (aref Tab i jp))
259
(if (or (null tmp) (mlsp (div (aref Tab i (1- n))
263
(setq tmp (div (aref Tab i (1- n))
268
(setq is-bounded nil)
269
(setq have-solution t))
271
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
272
;; Pivot the simplex tableau. ;;
273
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
274
(setf (nth ip basis) jp)
275
(pivot-sx Tab ip jp m n))))))
278
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
280
;; Pivoting for the Simplex algorithm. ;;
282
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
284
(defun pivot-sx (Tab ip jp m n)
285
(let ((piv (aref Tab ip jp)))
286
(setq $pivot_count_sx (1+ $pivot_count_sx))
287
(if (meqp $pivot_count_sx $pivot_max_sx)
289
($print "Maximum number of pivots reached.")
290
($print "Try setting a bigger value for pivot_max_sx.")
291
($print "Try setting scale_sx to true.")
293
($error "linear_program: maximum number of pivots reached.")))
298
(setf (aref Tab ip i) (div (aref Tab ip i) piv)))
301
(let ((tm (aref Tab i jp)))
302
(if (not (meqp tm 0))
306
(mul tm (aref Tab ip j)))))))))))))
308
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310
;; Run artificial variable out of basis. ;;
312
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
314
(defun run-out-of-basis-sx (Tab m n basis i)
317
((or (= j n) (not (null jp))))
318
(if (not (meqp 0 (aref Tab i j))) ; if Tab[i,j]#0 then column j is not
319
(setq jp j))) ; in the basis
323
(setf (nth i basis) jp)
324
(pivot-sx Tab i jp (+ 2 m) (+ 1 n))
328
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
330
;; Scaling for the simplex algorithm. (Equilibratium scaling) ;;
332
;; After scaling, the maximum absolute value in each row/column is 1. ;;
334
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
336
(defun scale-sx (Tab m n sc-fac)
338
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
339
;; Scale the rows of A and b. ;;
340
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
344
(let* ((tij (aref Tab i j))
345
(ta (if (mlsp tij 0) (neg tij) tij)))
348
(if (mlsp $epsilon_sx r)
350
(setf (aref Tab i j) (div (aref Tab i j) r)))))
351
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
352
;; Scale the columns of A and c. ;;
353
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
357
(let* ((tij (aref Tab i j))
358
(ta (if (mlsp tij 0) (neg tij) tij)))
361
(if (mlsp $epsilon_sx r)
364
(setf (aref Tab i j) (div (aref Tab i j) r)))
365
(setf (nth j sc-fac) r))))))