Fix #4414: Add url for bug reporting page in bug_report
[maxima.git] / share / simplex / simplex_algorithm.lisp
blob832c31f7ce56174316d6615e8fa2b6db52776a80
1 ;;; -*- Mode: Lisp -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; ;;
4 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;
5 ;; ;;; ;;; ;;
6 ;; ;;; ~*~ SIMPLEX ~*~ ;;; ;;
7 ;; ;;; ;;; ;;
8 ;; ;;; A simple implementation of the simplex ;;; ;;
9 ;; ;;; algorithm for Linear Programming for Maxima. ;;; ;;
10 ;; ;;; ;;; ;;
11 ;; ;;; ;;; ;;
12 ;; ;;; Copyright: Andrej Vodopivec <andrejv@users.sourceforge.net> ;;; ;;
13 ;; ;;; Version: 1.02 ;;; ;;
14 ;; ;;; License: GPL ;;; ;;
15 ;; ;;; ;;; ;;
16 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;
17 ;; ;;
18 ;; ;;
19 ;; USAGE: ;;
20 ;; ======= ;;
21 ;; ;;
22 ;; To get optimal speed this file should be compiled. ;;
23 ;; ;;
24 ;; linear_program(A, b, c): ;;
25 ;; ;;
26 ;; - problem: - find x which minimizes c'.x with constraints A.x=b and x>=0 ;;
27 ;; ;;
28 ;; - input: - matrix A of size mxn, ;;
29 ;; - vector (list) b of length m, ;;
30 ;; - vector (list) c of length n ;;
31 ;; ;;
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 ;;
36 ;; ;;
37 ;; - algorithm: a simple implementation of the two-phase simplex algorithm ;;
38 ;; ;;
39 ;; ;;
40 ;; DEMO: ;;
41 ;; ====== ;;
42 ;; ;;
43 ;; We would like to minimize x-2*y subject to: ;;
44 ;; ;;
45 ;; x + y >= 1 ;;
46 ;; 2*x - 3*y >= 1 ;;
47 ;; 4*x - 5*y = 6 ;;
48 ;; x, y >= 0 ;;
49 ;; ;;
50 ;; We have to introduce two slack variables for inequalities to get a ;;
51 ;; linear program in the standard form: ;;
52 ;; ;;
53 ;; x + y - s1 = 1 ;;
54 ;; 2*x - 3*y - s2 = 1 ;;
55 ;; 4*x - 5*y = 6 ;;
56 ;; x, y, s1, s2 >= 0 ;;
57 ;; ;;
58 ;; Construct parameters: ;;
59 ;; ;;
60 ;; A : matrix([1,1,-1,0],[2,-3,0,-1], [4,-5,0,0]); ;;
61 ;; b : [1,1,6]; ;;
62 ;; c : [1,-2,0,0]; ;;
63 ;; ;;
64 ;; Solution: ;;
65 ;; ;;
66 ;; linear_program(A, b, c); ;;
67 ;; => [[13/2, 4, 19/2, 0], -3/2] ;;
68 ;; ;;
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. ;;
71 ;; ;;
72 ;; ;;
73 ;; VARIABLES: ;;
74 ;; =========== ;;
75 ;; ;;
76 ;; - pivot_count_sx: the number of pivots in last computation ;;
77 ;; - pivot_max_sx: the maximum number of pivots in computation ;;
78 ;; - epsilon_lp: epsilon for numeric computation (default: 1e-8) ;;
79 ;; - scale_lp: 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 ;;
83 ;; ;;
84 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86 (in-package :maxima)
87 (macsyma-module simplex)
89 ($put '$simplex 1.02 '$version)
91 (defmvar $pivot_count_sx 0 "Number of pivots in last problem." fixnum)
92 (defmvar $pivot_max_sx 15000 "Maximum number of pivots allowed." fixnum)
93 (defmvar $epsilon_lp 1e-8 "Epsilon for numerical computation." flonum)
94 (defmvar $scale_lp nil "Should we scale the input." boolean)
95 (defmvar $warn_rank_sx nil "Print warnings about rank." boolean)
97 ;; type checkers
98 (defun lp-rat-mlist-p (x) (and (listp x) (every #'$ratnump (cdr x))))
99 (defun lp-rat-matrix-p (x) (and ($matrixp x) (every #'lp-rat-mlist-p (cdr x))))
100 ;; comparison
101 (defun lp-mlsp (a b)
102 (let ((x (mlsp a b)))
103 (cond ((or (eq x t) (eq x nil)) x)
105 (let ((s ($asksign (cadr x))))
106 (cond ((eq s '$pos) t)
107 (t nil)))))))
108 (defun lp-mgqp (a b) (or (meqp a b) (lp-mlsp b a)))
110 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
111 ;; ;;
112 ;; Two-phase standard simplex method for solving linear program in standard ;;
113 ;; form. ;;
114 ;; ;;
115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118 (defun $linear_program (A b c)
119 (if (not ($matrixp A))
120 (merror "linear_program: first argument not matrix."))
121 (if (not ($listp b))
122 (merror "linear_program: second argument not list."))
123 (if (not ($listp c))
124 (merror "linear_program: third argument not list."))
125 (if (not (meqp ($length b) ($length A)))
126 (merror "linear_program: second argument not of correct length."))
127 (if (not (meqp ($length c) ($length ($first A))))
128 (merror "linear_program: third argument not of correct length."))
130 (let* ((m ($length A))
131 (n ($length ($first A)))
132 (Tab (make-array `(,(+ 2 m) ,(1+ n)))) ; Tableau
133 (basis ()) ; which columns are in current basis
134 (sc-fac ()) ; scaling factors
135 ($epsilon_lp (if (and (lp-rat-mlist-p b) (lp-rat-mlist-p c) (lp-rat-matrix-p A))
136 0 $epsilon_lp))
137 ($ratprint nil))
138 (cond ((lp-mlsp 0 $epsilon_lp)
139 (mwarning (format nil "linear_program(A,b,c): non-rat inputs found, epsilon_lp=~e." $epsilon_lp))
140 (mwarning "Solution may be incorrect.")))
142 (setq $pivot_count_sx 0)
144 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
145 ;; Construct the tableau for phase 1: ;;
146 ;; [ A b ] ;;
147 ;; Tab = [ c' 0 ] ;;
148 ;; [ sm(A) sm(b) ] ;;
149 ;; ;;
150 ;; If b[i]<0 multiply b[i] and A[i] by -1 (required for phase 1). ;;
151 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
152 (dotimes (i m)
153 (if (lp-mlsp (maref b (1+ i)) 0)
154 (progn
155 (dotimes (j n)
156 (setf (aref Tab i j) (neg (maref A (1+ i) (1+ j)))))
157 (setf (aref Tab i n) (neg (maref b (1+ i)))))
158 (progn
159 (dotimes (j n)
160 (setf (aref Tab i j) (maref A (1+ i) (1+ j))))
161 (setf (aref Tab i n) (maref b (1+ i))))))
162 (dotimes (i n)
163 (setf (aref Tab m i) (neg (maref c (1+ i)))))
164 (dotimes (i n)
165 (setf (aref Tab (1+ m) i) 0)
166 (dotimes (j m)
167 (setf (aref Tab (1+ m) i) (add (aref Tab (1+ m) i)
168 (aref Tab j i)))))
169 (setf (aref Tab (1+ m) n) 0)
170 (dotimes (i m)
171 (setf (aref Tab (1+ m) n) (add (aref Tab (1+ m) n)
172 (aref Tab i n))))
173 (setf (aref Tab m n) 0)
175 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
176 ;; At the beginning the artificial variables are in the basis. ;;
177 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
178 (dotimes (i m)
179 (setq basis (append basis (list (add n i)))))
181 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
182 ;; Scaling. ;;
183 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
184 (dotimes (i n)
185 (setq sc-fac (append sc-fac (list 1))))
186 (if $scale_lp
187 (scale-sx Tab (+ 2 m) (1+ n) sc-fac))
189 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
190 ;; Phase 1 ;;
191 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
193 (simplex-sx Tab basis m (+ 2 m) (1+ n))
195 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
197 (if (lp-mlsp $epsilon_lp (aref Tab (1+ m) n))
198 "Problem not feasible!"
199 (let ((is-bounded))
201 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
202 ;; Check for artificial variables in basis. ;;
203 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
205 (dotimes (i m)
206 (if (>= (nth i basis) n)
207 (if (and (not (run-out-of-basis-sx Tab m n basis i))
208 $warn_rank_sx)
209 ($print "Matrix A is not of full rank:"
210 "Row" (1+ i) "is redundant!"))))
212 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
213 ;; Phase 2 ;;
214 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216 (setq is-bounded (simplex-sx Tab basis m (1+ m) (1+ n)))
218 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
220 (if is-bounded
221 (let ((opt-tmp ())
222 (opt ()))
223 (dotimes (i (+ m n))
224 (setq opt-tmp (append opt-tmp (list 0))))
225 (dotimes (i m)
226 (setf (nth (nth i basis) opt-tmp)
227 (div (aref Tab i n) ;; undo the
228 (nth (nth i basis) sc-fac)))) ;; scaling
229 (dotimes (i n)
230 (setq opt (append opt (list 0))))
231 (dotimes (i n)
232 (setf (nth i opt) (nth i opt-tmp)))
233 (setq opt (cons '(mlist simp) opt)) ;; build the
234 (setq opt `((mlist simp) ,opt ;; the solution
235 ,(aref Tab m n))))
236 "Problem not bounded!")))))
239 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
240 ;; ;;
241 ;; Simplex algorithm. ;;
242 ;; ;;
243 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
245 (defun simplex-sx (Tab basis Am m n)
246 (let ((ip) (jp) (tmp) (is-bounded))
247 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
248 ;; Repeat while we don't have a solution or know that the ;;
249 ;; problem is unbounded. ;;
250 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
251 (do ((have-solution nil))
252 ((not (null have-solution)))
253 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
254 ;; Choose jp so that jp-th column has the biggest reduced cost. ;;
255 ;; If all reduced costs are negative, we have the solution. ;;
256 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
257 (setq tmp (aref Tab (1- m) 0))
258 (setq jp 0)
259 (dotimes (j (- n 1))
260 (if (lp-mlsp tmp (aref Tab (1- m) j))
261 (progn
262 (setq tmp (aref Tab (1- m) j))
263 (setq jp j))))
264 (if (lp-mgqp $epsilon_lp tmp)
265 (progn
266 (setq is-bounded t)
267 (setq have-solution t))
268 (progn
269 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
270 ;; Choose ip so that Tab[ip,n]/Tab[ip,jp] is the smallest ;;
271 ;; possible among those for which Tab[i,n] is positive. If all ;;
272 ;; Tab[i,n] are negative, the problem is unbounded. ;;
273 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
274 (setq tmp nil)
275 (setq ip 0)
276 (dotimes (i Am)
277 (if (lp-mlsp $epsilon_lp (aref Tab i jp))
278 (if (or (null tmp) (lp-mlsp (div (aref Tab i (1- n))
279 (aref Tab i jp))
280 tmp))
281 (progn
282 (setq tmp (div (aref Tab i (1- n))
283 (aref Tab i jp)))
284 (setq ip i)))))
285 (if (null tmp)
286 (progn
287 (setq is-bounded nil)
288 (setq have-solution t))
289 (progn
290 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
291 ;; Pivot the simplex tableau. ;;
292 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
293 (setf (nth ip basis) jp)
294 (pivot-sx Tab ip jp m n))))))
295 is-bounded))
297 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
298 ;; ;;
299 ;; Pivoting for the Simplex algorithm. ;;
300 ;; ;;
301 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
303 (defun pivot-sx (Tab ip jp m n)
304 (let ((piv (aref Tab ip jp)))
305 (setq $pivot_count_sx (1+ $pivot_count_sx))
306 (if (meqp $pivot_count_sx $pivot_max_sx)
307 (progn
308 ($print "Maximum number of pivots reached.")
309 ($print "Try setting a bigger value for pivot_max_sx.")
310 ($print "Try setting scale_lp to true.")
311 ($print "")
312 ($error "linear_program: maximum number of pivots reached.")))
313 (if (meqp piv 0)
314 ($print "Singular!")
315 (progn
316 (dotimes (i n)
317 (setf (aref Tab ip i) (div (aref Tab ip i) piv)))
318 (dotimes (i m)
319 (if (not (eq i ip))
320 (let ((tm (aref Tab i jp)))
321 (if (not (meqp tm 0))
322 (dotimes (j n)
323 (setf (aref Tab i j)
324 (sub (aref Tab i j)
325 (mul tm (aref Tab ip j)))))))))))))
327 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
328 ;; ;;
329 ;; Run artificial variable out of basis. ;;
330 ;; ;;
331 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
333 (defun run-out-of-basis-sx (Tab m n basis i)
334 (let ((jp nil))
335 (do ((j 0 (1+ j)))
336 ((or (= j n) (not (null jp))))
337 (if (not (meqp 0 (aref Tab i j))) ; if Tab[i,j]#0 then column j is not
338 (setq jp j))) ; in the basis
339 (if (null jp)
341 (progn
342 (setf (nth i basis) jp)
343 (pivot-sx Tab i jp (+ 2 m) (+ 1 n))
344 1))))
347 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
348 ;; ;;
349 ;; Scaling for the simplex algorithm. (Equilibratium scaling) ;;
350 ;; ;;
351 ;; After scaling, the maximum absolute value in each row/column is 1. ;;
352 ;; ;;
353 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
355 (defun scale-sx (Tab m n sc-fac)
356 (let ((r 0))
357 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
358 ;; Scale the rows of A and b. ;;
359 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
360 (dotimes (i (- m 2))
361 (setq r 0)
362 (dotimes (j n)
363 (let* ((tij (aref Tab i j))
364 (ta (if (lp-mlsp tij 0) (neg tij) tij)))
365 (if (lp-mlsp r ta)
366 (setq r ta))))
367 (if (lp-mlsp $epsilon_lp r)
368 (dotimes (j n)
369 (setf (aref Tab i j) (div (aref Tab i j) r)))))
370 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
371 ;; Scale the columns of A and c. ;;
372 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
373 (dotimes (j (1- n))
374 (setq r 0)
375 (dotimes (i (- m 2))
376 (let* ((tij (aref Tab i j))
377 (ta (if (lp-mlsp tij 0) (neg tij) tij)))
378 (if (lp-mlsp r ta)
379 (setq r ta))))
380 (if (lp-mlsp $epsilon_lp r)
381 (progn
382 (dotimes (i m)
383 (setf (aref Tab i j) (div (aref Tab i j) r)))
384 (setf (nth j sc-fac) r))))))