1 /*****************************************************************************
3 * ************************************************************************* *
5 * *** ~*~ SIMPLEX ~*~ *** *
7 * *** A simple implementation of the simplex *** *
8 * *** algorithm for Linear Programming for Maxima. *** *
10 * *** This file provides functions minimize_lp and maximize_lp. This *** *
11 * *** file is part of the simplex package for Maxima. *** *
14 * *** Copyright: Andrej Vodopivec <andrejv@users.sourceforge.net> *** *
15 * *** Version: 1.01 *** *
16 * *** License: GPL *** *
18 * ************************************************************************* *
23 * 1) We want to minimize x with constraints y>=x-1, y>=-x-1, y<=x+1, y<=1-x *
29 * minimize_lp(x, [y>=x-1, y>=-x-1, y<=x+1, y<=1-x, y=x/2]); *
30 * => [-2/3, [x=-2/3, y=-1/3]] *
33 * 2) If any variable is known to be positive, you should add an optional *
34 * argument to minimize_lp/maximize_lp. *
35 * We want to maximize x+y subject to x>=0, y>=0, y<=-x/2+3, y<=-x+4. *
39 * maximize_lp(x+y, [y<=-x/2+3, y<=-x+4], [x, y]) *
40 * => [4, [x = 2, y = 2]] *
42 *****************************************************************************/
44 define_variable(nonnegative_lp, false, boolean,
45 "Assume all variables are non-negative!")$
46 alias(nonegative_lp, nonnegative_lp)$
47 define_variable(return_input_lp, false, boolean,
48 "Return the input to linear program, not solution!")$
50 /*****************************************************************************
52 * The minimize_lp function. *
54 *****************************************************************************/
56 minimize_lp(target, constraints, [pozitive]) := block(
57 [var : [], A, b, c, inequalities:0, count, eq, t:expand(target), sol, s,
58 nonpozitive : 0, j, tmpvar, keepfloat:true],
60 /*******************************************************************
61 * Get the list of variables *
62 *******************************************************************/
64 for e in constraints do (
65 tmpvar : listofvars(e),
67 if not(member(v, var)) then var : cons(v, var),
68 if op(e)#"=" then inequalities : inequalities+1
71 if length(pozitive)>0 then (
72 if listp(pozitive[1]) then pozitive : pozitive[1]
73 else if pozitive[1]='all then pozitive : copylist(var)
75 else if nonnegative_lp=true then
76 pozitive : copylist(var),
79 if not(member(v,pozitive)) then nonpozitive : nonpozitive+1,
81 /*******************************************************************
82 * Setup A and b for linear program *
83 *******************************************************************/
85 b : makelist(0, i, 1, length(constraints)),
86 A : zeromatrix(length(constraints), length(var)+nonpozitive+inequalities),
88 for i:1 thru length(constraints) do (
89 eq : lhs(part(constraints,i))-rhs(part(constraints,i)),
92 A[i,j] : ratcoeff(eq, v),
93 if not(constantp(A[i,j])) then
94 error("Error: constraint not linear (1).",A[i,j]),
97 if not(member(v,pozitive)) then (
102 if op(constraints[i])="<=" or op(constraints[i])="<" then (
104 A[i, length(var)+nonpozitive+count] : 1
106 else if op(constraints[i])=">=" or op(constraints[i])=">" then (
108 A[i, length(var)+nonpozitive+count] : -1
110 else if op(constraints[i])#"=" then
111 error("Error: not a proper constraint:", constraints[i]),
113 if not(constantp(b[i])) then
114 error("Error: constraint not linear (2).",b[i])
117 /*******************************************************************
118 * Setup c for linear program *
119 *******************************************************************/
121 c : makelist(0, i, 1, length(var)+nonpozitive+count),
124 c[j] : ratcoeff(t, v),
125 if not(constantp(c[j])) then
126 error("Error: cost function not linear."),
129 if not(member(v,pozitive)) then (
135 if not(constantp(t)) then
136 error("Error: cost function not linear in constrained variables."),
138 if return_input_lp then return([A, b, c]),
140 /*******************************************************************
141 * Solve the linear program *
142 *******************************************************************/
144 sol : linear_program(A, b, c),
146 if not(listp(sol)) then sol
148 if sol[2]=-inf then [-inf, []]
153 if member(v,pozitive) then (
154 s : append(s, [v=sol[1][j]]),
158 s : append(s, [v=sol[1][j]-sol[1][j+1]]),
167 maximize_lp(target, constraints, [pozitive]) := block(
168 [sol : apply(minimize_lp, append([-target], [constraints], pozitive))],
169 if not(listp(sol)) then sol
170 else [-sol[1], sol[2]]
174 /*****************************************************************************
176 * %functions are for debugging purposes. *
178 *****************************************************************************/
180 %prepare_standard_form_lp(target,constraints,pozitive) := block([listconstvars : false,
181 vars, slack_vars, nonpozitive_vars, nonpozitive_vars0, nonpozitive_subs, slack_vars0, nonpozitive_subs0, vars0],
182 vars : listofvars(append([target],constraints)),
183 slack_vars : map(lambda([e],gensym()), constraints),
184 nonpozitive_vars : sublist(vars,lambda([e], not(member(e,pozitive)))),
185 nonpozitive_subs : block([mgensym : lambda([x], gensym(printf(false,"~a_",x)))],
186 map(lambda([x], x=mgensym(x)-mgensym(x)), nonpozitive_vars)),
187 constraints : block([ltoreq : lambda([l,r], -l >= -r)],
188 subst(["<"=ltoreq, "<="=ltoreq], constraints)),
189 constraints : map(lambda([e,s], if op(e)="=" then e else lhs(e)-s-rhs(e)),constraints,slack_vars),
190 slack_vars0 : block([cv:listofvars(constraints)],
191 sublist(slack_vars, lambda([x],member(x,cv)))),
192 nonpozitive_vars0 : listofvars(map('rhs,nonpozitive_subs)),
193 vars0 : block([vars:vars,nonpozitive_subs1:map('lhs,nonpozitive_subs)],
194 for v in nonpozitive_subs1 do vars:delete(v,vars), vars),
195 [target, constraints] : subst("="="-", subst(nonpozitive_subs, [target,constraints])),
196 [target, constraints, vars0, nonpozitive_subs, nonpozitive_vars0, slack_vars0]
198 %minimize_lp(target, constraints, [pozitive]) := block([A, b, c, vars0, vars, tgt, vals, lp,
199 nonpozitive_subs, nonpozitive_vars0, slack_vars0, mcoefmatrix],
201 mcoefmatrix(l,v) := apply('matrix,outermap(coeff,l,v)),
202 pozitive : if pozitive=[] then [] else if listp(part(pozitive,1)) then part(pozitive,1) else if part(pozitive,1)='all or nonnegative_lp then copylist(block([listconstvars:false], listofvars(constraints))) else error("Unrecognized input."),
203 [target, constraints, vars0, nonpozitive_subs, nonpozitive_vars0, slack_vars0] : %prepare_standard_form_lp(target, constraints, pozitive),
204 vars : append(vars0, nonpozitive_vars0, slack_vars0),
205 lp : linear_program(mcoefmatrix(constraints,vars), -subst(map(lambda([x],x=0),vars), constraints), first(args(mcoefmatrix([target],vars)))),
206 if atom(lp) then lp else ([vals,tgt] : lp,
207 block([maperror:false, mapprint:false],
208 [tgt, append(map("=",vars0,vals),subst(map("=",nonpozitive_vars0,rest(vals,length(vars0))),nonpozitive_subs))])));
209 %maximize_lp(target, constraints, [pozitive]) := block([tgt, vals, lp],
210 lp : %minimize_lp(-target, constraints,first(pozitive)),
211 if atom(lp) then lp else ([tgt,vals] : lp,