simplex.red 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. module simplex;
  2. %**********************************************************************%
  3. % %
  4. % Computation of the optimal value of an objective function given a %
  5. % number of linear inequalities using the SIMPLEX algorithm. %
  6. % %
  7. % Author: Matt Rebbeck, June 1994. %
  8. % %
  9. % Many of the ideas were taken from "Linear Programming" by %
  10. % M.J.Best & K. Ritter %
  11. % %
  12. % Minor changes: Herbert Melenk, Jan 1995 %
  13. % %
  14. % replacing first, second etc. by car, cadr %
  15. % converted big smacros to ordinary procedures %
  16. % %
  17. %**********************************************************************%
  18. if not get('leq,'simpfn) then
  19. <<
  20. algebraic operator <=;
  21. algebraic operator >=;
  22. >>;
  23. symbolic smacro procedure smplx_prepsq u;
  24. %
  25. % If u in (!*sq) standard quotient form then get !:rd!: part.
  26. %
  27. if atom u then u
  28. else if car u = 'minus and atom cadr u then u
  29. else if car u = 'minus and caadr u = '!*sq then {'minus,car cadadr u}
  30. else if car u = 'minus and caadr u = '!:rd!: then u
  31. else if car u = '!:rd!: then u
  32. else if car u = '!*sq then prepsq cadr u;
  33. symbolic smacro procedure fast_row_dim(in_mat);
  34. %
  35. % Finds row dimension of a matrix with no error checking.
  36. %
  37. length in_mat #- 1;
  38. symbolic smacro procedure fast_column_dim(in_mat);
  39. %
  40. % Finds column dimension of a matrix with no error checking.
  41. %
  42. length cadr in_mat;
  43. symbolic smacro procedure fast_stack_rows(in_mat,row_list);
  44. %
  45. % row_list is always an integer in simplex.
  46. %
  47. 'mat.{nth(cdr in_mat,row_list)};
  48. symbolic smacro procedure fast_getmat(matri,i,j);
  49. %
  50. % Get matrix element (i,j).
  51. %
  52. fast_unchecked_getmatelem list(matri,i,j);
  53. symbolic smacro procedure fast_my_letmtr(u,v,y);
  54. rplaca(pnth(nth(cdr y,car my_revlis cdr u),cadr my_revlis cdr u),v);
  55. put('simplex,'psopfn,'simplex1);
  56. symbolic procedure simplex1(input);
  57. %
  58. % The simplex problem is:
  59. %
  60. % min {c'x | Ax = b, x>=0},
  61. %
  62. % where Ax = b describes the linear equations and c is the function
  63. % that is to be optimised.
  64. %
  65. % This code implements the basic phaseI-phaseII revised simplex
  66. % algorithm. (phaseI checks for feasibility and phaseII finds the
  67. % optimal solution).
  68. %
  69. % A general idea of tha algorithm is as follows:
  70. %
  71. % 1: create phase 1 data.
  72. %
  73. % Add slack and artificial variables to equations to create matrix
  74. % A1. The initial basis (ib) consists of the numbers of the columns
  75. % relating to the artificial variables. The basic feasible solution
  76. % (xb) (if one exists) is B^(-1)*b where b is the r.h.s. of the
  77. % equations. Throughout, cb denotes the columns of the objective
  78. % matrix corresponding to ib.
  79. % This data goes to the revised simplex algorithm(2).
  80. %
  81. % 2: revised simplex:
  82. %
  83. % step 1: Computation of search direction sb.
  84. %
  85. % Compute u = -(B^(-1))'*cb, the smallest index k, and vk s.t.
  86. %
  87. % vk = min{c(i) + A(i)'u | i not elt of ib}.
  88. %
  89. % If vk>=0, stop with optimal solution xb = B^(-1)*b.
  90. % If vk<0, set sb = B^(-1)*A(k) and go to step 2.
  91. %
  92. % step 2: Computation of maximum feasible step size Ob.
  93. %
  94. % If sb<=0 then rederr "Problem unbounded from below".
  95. % If (sb)(i) >0 for at least one i, compute Ob and the smallest
  96. % index l s.t.
  97. %
  98. % (xb)(l) { (xb)(i) | }
  99. % Ob = ------- = min { ------ | all i with (sb)(i)>0 },
  100. % (sb)(l) { (sb)(i) | }
  101. %
  102. % and go to step 3.
  103. %
  104. % step3: Update.
  105. %
  106. % Replace B^(-1) with [phiprm((B^(-1)',A(k),l)]', xb with B^(-1)*b
  107. % and the l'th elt in ib with k. Compute cb'xb and go to step 1.
  108. %
  109. % 3: If we get this far (ie: we are feasible) then apply revised
  110. % simplex to A (equations with slacks added), and the new xb,
  111. % Binv, and ib.
  112. %
  113. %
  114. % Further details and far more advanced algorithms can be found
  115. % in almost any linear programming book. The above was adapted from
  116. % "Linear Programming" M.J.Best and K. Ritter. To date, the code
  117. % contains no anti_cycling algorithm.
  118. %
  119. begin
  120. scalar max_or_min,objective,equation_list,tmp,A,b,obj_mat,X,A1,
  121. phase1_obj,ib,xb,Binv,simp_calc,phase1_obj_value,big,sum,
  122. stop,work,I_turned_rounded_on,ans_list,optimal_value;
  123. integer m,n,k,i,ell,no_coeffs,no_variables,equation_variables;
  124. max_or_min := reval car input;
  125. objective := reval cadr input;
  126. equation_list := reval caddr input;
  127. if not !*rounded then << I_turned_rounded_on := t; on rounded; >>;
  128. if (max_or_min neq 'max) and (max_or_min neq 'min) then rederr
  129. "Error in simplex(first argument): must be either max or min.";
  130. if pairp equation_list and car equation_list = 'list then
  131. equation_list := cdr equation_list
  132. else rederr "Error in simplex(third argument}: must be a list.";
  133. % get rid of any two (or more) equal equations! Probably makes
  134. % things faster in general.
  135. tmp := unique_equation_list(equation_list);
  136. equation_list := car tmp;
  137. equation_variables := cadr tmp;
  138. % If r.h.s. and l.h.s. of inequalities are both <0 then multiply
  139. % by -1.
  140. equation_list := make_equations_positive(equation_list);
  141. % If there are variables in the objective function that are not in
  142. % the equation_list then add these variables to the equation list.
  143. % (They are added as variable>=0).
  144. equation_list :=
  145. add_not_defined_variables(objective,equation_list,
  146. equation_variables);
  147. tmp := initialise(max_or_min,objective,equation_list);
  148. A := car tmp;
  149. b := cadr tmp;
  150. obj_mat := caddr tmp;
  151. X := cadddr tmp;
  152. % no_variables is the number of variables in the input equation
  153. % list. this is used in make_answer_list.
  154. no_variables := car cddddr tmp;
  155. % r.h.s. (i.e. b matrix) must be positive.
  156. tmp := check_minus_b(A,b);
  157. A := car tmp;
  158. b := cadr tmp;
  159. m := fast_row_dim(A);
  160. n := no_coeffs := fast_column_dim(A);
  161. tmp := create_phase1_A1_and_obj_and_ib(A);
  162. A1 := car tmp;
  163. phase1_obj := cadr tmp;
  164. ib := caddr tmp;
  165. xb := copy_mat(b);
  166. Binv := fast_make_identity(fast_row_dim(A));
  167. % Phase 1 data is now ready to go...
  168. simp_calc := simplex_calculation(phase1_obj,A1,b,ib,Binv,xb);
  169. phase1_obj_value := car simp_calc;
  170. xb := cadr simp_calc;
  171. Binv := cadddr(simp_calc);
  172. if get_num_part(phase1_obj_value) neq 0
  173. then rederr "Error in simplex: Problem has no feasible solution.";
  174. % Are any artificials still basic?
  175. for ell:=1:m do if nth(ib,ell) <= n then <<>>
  176. else
  177. <<
  178. % so here, an artificial is basic in row ell.
  179. big := -1;
  180. k := 0;
  181. stop := nil;
  182. i := 1;
  183. while i<=n and not stop do
  184. <<
  185. sum := get_num_part(smplx_prepsq(fast_getmat(reval
  186. {'times,fast_stack_rows(Binv,ell),
  187. fast_augment_columns(A,i)},1,1)));
  188. if abs(sum) leq big then stop := t
  189. else
  190. <<
  191. big := abs(sum);
  192. k := i;
  193. >>;
  194. i := i+1;
  195. >>;
  196. if big geq 0 then <<>>
  197. else rederr {"Error in simplex: constraint",k," is redundant."};
  198. work := fast_augment_columns(A,k);
  199. Binv := phiprm(Binv,work,ell);
  200. nth(ib,ell) := k;
  201. >>;
  202. % Into Phase 2.
  203. simp_calc := simplex_calculation(obj_mat,A,b,ib,Binv,xb);
  204. optimal_value := car simp_calc;
  205. xb := cadr simp_calc;
  206. ib := caddr simp_calc;
  207. ans_list := make_answer_list(xb,ib,no_coeffs,X,no_variables);
  208. if I_turned_rounded_on then off rounded;
  209. if max_or_min = 'max then
  210. optimal_value := my_reval{'minus,optimal_value};
  211. return {'list,optimal_value,'list.ans_list};
  212. end;
  213. flag('(simplex1),'opfn);
  214. symbolic procedure unique_equation_list(equation_list);
  215. %
  216. % Removes repititions in input. Also returns coeffecients in equation
  217. % list.
  218. %
  219. begin
  220. scalar unique_equation_list,coeff_list;
  221. for each equation in equation_list do
  222. <<
  223. if not intersection({equation},unique_equation_list) then
  224. <<
  225. unique_equation_list := append(unique_equation_list,{equation});
  226. coeff_list := union(coeff_list,get_coeffs(cadr equation));
  227. >>;
  228. >>;
  229. return {unique_equation_list,coeff_list};
  230. end;
  231. symbolic procedure make_equations_positive(equation_list);
  232. %
  233. % If r.h.s. and l.h.s. of inequality are <0 then mult. both sides by
  234. % -1.
  235. %
  236. for each equation in equation_list collect
  237. if pairp cadr equation and caadr equation = 'minus and
  238. pairp caddr equation and caaddr equation = 'minus
  239. then {car equation,my_minus(cadr equation),my_minus(caddr equation)}
  240. else equation;
  241. symbolic procedure add_not_defined_variables
  242. (objective,equation_list,equation_variables);
  243. %
  244. % If variables in the objective have not been defined in the
  245. % inequalities(equation_list) then add them. They are added as
  246. % variable >= 0.
  247. %
  248. begin
  249. scalar obj_variables;
  250. obj_variables := get_coeffs(objective);
  251. if length obj_variables = length equation_variables then
  252. return equation_list;
  253. for each variable in obj_variables do
  254. <<
  255. if not intersection({variable},equation_variables) then
  256. <<
  257. prin2
  258. "*** Warning: variable ";
  259. prin2 variable;
  260. prin2t " not defined in input. Has been defined as >=0.";
  261. equation_list := append(equation_list,{{'geq,variable,0}});
  262. >>;
  263. >>;
  264. return equation_list;
  265. end;
  266. symbolic procedure initialise(max_or_min,objective,equation_list);
  267. %
  268. % Creates A (with slack variables included), b (r.h.s. of equations),
  269. % the objective matrix (obj_mat) and X s.t. AX=b and
  270. % obj_mat * X = objective function.
  271. % Also returns the number of equations in the equation_list so we know
  272. % where to stop making answers in make_answer_list.
  273. %
  274. begin
  275. scalar more_init,A,b,obj_mat,X;
  276. integer no_variables;
  277. if max_or_min = 'max then
  278. objective := reval{'times,objective,-1};
  279. more_init := more_initialise(objective,equation_list);
  280. A := car more_init;
  281. b := cadr more_init;
  282. obj_mat := caddr more_init;
  283. X := cadddr more_init;
  284. no_variables := car cddddr more_init;
  285. return {A,b,obj_mat,X,no_variables};
  286. end;
  287. symbolic procedure more_initialise(objective,equation_list);
  288. begin
  289. scalar objective,equation_list,non_slack_variable_list,obj_mat,
  290. no_of_non_slacks,tmp,variable_list,slack_equations,A,b,X;
  291. non_slack_variable_list :=
  292. get_preliminary_variable_list(equation_list);
  293. no_of_non_slacks := length non_slack_variable_list;
  294. tmp := add_slacks_to_equations(equation_list);
  295. slack_equations := car tmp;
  296. b := cadr tmp;
  297. variable_list := union(non_slack_variable_list,caddr tmp);
  298. tmp := get_X_and_obj_mat(objective,variable_list);
  299. X := car tmp;
  300. obj_mat := cadr tmp;
  301. A := simp_get_A(slack_equations,variable_list);
  302. return {A,b,obj_mat,X,no_of_non_slacks};
  303. end;
  304. symbolic procedure check_minus_b(A,b);
  305. %
  306. % The algorithm requires the r.h.s. (i.e. the b matrix) to contain
  307. % only positive entries.
  308. %
  309. begin
  310. for i:=1:row_dim(b) do
  311. <<
  312. if get_num_part( reval getmat(b,i,1) ) < 0 then
  313. <<
  314. b := mult_rows(b,i,-1);
  315. A := mult_rows(A,i,-1);
  316. >>;
  317. >>;
  318. return {A,b};
  319. end;
  320. symbolic procedure create_phase1_A1_and_obj_and_ib(A);
  321. begin
  322. scalar phase1_obj,A1,ib;
  323. integer column_dim_A1,column_dim_A,row_dim_A1,i;
  324. column_dim_A := fast_column_dim(A);
  325. % Add artificials to A.
  326. A1 := fast_matrix_augment({A,fast_make_identity(fast_row_dim(A))});
  327. column_dim_A1 := fast_column_dim(A1);
  328. row_dim_A1 := fast_row_dim(A1);
  329. phase1_obj := mkmatrix(1,fast_column_dim(A1));
  330. for i:=column_dim_A+1:fast_column_dim(A1) do
  331. fast_setmat(phase1_obj,1,i,1);
  332. ib := for i:=column_dim_A+1:fast_column_dim(A1) collect i;
  333. return {A1,phase1_obj,ib};
  334. end;
  335. symbolic procedure simplex_calculation(obj_mat,A,b,ib,Binv,xb);
  336. %
  337. % Applies the revised simplex algorithm. See above for details.
  338. %
  339. begin
  340. scalar rs1,sb,rs2,rs3,u,continue,obj_value;
  341. integer k,iter,ell;
  342. obj_value := compute_objective(get_cb(obj_mat,ib),xb);
  343. while continue neq 'optimal do
  344. <<
  345. rs1 := rstep1(A,obj_mat,Binv,ib);
  346. sb := car rs1;
  347. k := cadr rs1;
  348. u := caddr rs1;
  349. continue := cadddr rs1;
  350. if continue neq 'optimal then
  351. <<
  352. rs2 := rstep2(xb,sb);
  353. ell := cadr rs2;
  354. rs3 := rstep3(xb,obj_mat,b,Binv,A,ib,k,ell);
  355. iter := iter + 1;
  356. Binv := car rs3;
  357. obj_value := cadr rs3;
  358. xb := caddr rs3;
  359. >>;
  360. >>;
  361. return {obj_value,xb,ib,Binv};
  362. end;
  363. symbolic procedure get_preliminary_variable_list(equation_list);
  364. %
  365. % Gets all variables before slack variables are added.
  366. %
  367. begin
  368. scalar variable_list;
  369. for each equation in equation_list do
  370. variable_list := union(variable_list,get_coeffs(cadr equation));
  371. return variable_list;
  372. end;
  373. symbolic procedure add_slacks_to_equations(equation_list);
  374. %
  375. % Takes list of equations (=, <=, >=) and adds required slack
  376. % variables. Also returns all the rhs integers in a column matrix,
  377. % and a list of the added slack variables.
  378. %
  379. begin
  380. scalar slack_list,rhs_mat,slack_variable,slack_variable_list;
  381. integer i,row;
  382. rhs_mat := mkmatrix(length equation_list,1);
  383. row := 1;
  384. for each equation in equation_list do
  385. <<
  386. if not numberp reval caddr equation then
  387. <<
  388. prin2 "***** Error in simplex(third argument): ";
  389. rederr "right hand side of each inequality must be a number";
  390. >>
  391. else fast_setmat(rhs_mat,row,1,caddr equation);
  392. row := row+1;
  393. %
  394. % Put in slack/surplus variables where required.
  395. %
  396. if car equation = 'geq then
  397. <<
  398. i := i+1;
  399. slack_variable := mkid('sl_var,i);
  400. equation := {'plus,{'minus,mkid('sl_var,i)},cadr equation};
  401. slack_variable_list := append(slack_variable_list,
  402. {slack_variable});
  403. >>
  404. else if car equation = 'leq then
  405. <<
  406. i := i+1;
  407. slack_variable := mkid('sl_var,i);
  408. equation := {'plus,mkid('sl_var,i),cadr equation};
  409. slack_variable_list := append(slack_variable_list,
  410. {slack_variable});
  411. >>
  412. else if car equation = 'equal then equation := cadr equation
  413. else
  414. <<
  415. prin2 "***** Error in simplex(third argument):";
  416. rederr "inequalities must contain either >=, <=, or =.";
  417. >>;
  418. slack_list := append(slack_list,{equation});
  419. >>;
  420. return {slack_list,rhs_mat,slack_variable_list};
  421. end;
  422. flag('(add_slacks_to_list),'opfn);
  423. symbolic procedure simp_get_A(slack_equations,variable_list);
  424. %
  425. % Extracts the A matrix from the slack equations.
  426. %
  427. begin
  428. scalar A,slack_elt,var_elt;
  429. integer row,col,length_slack_equations,length_variable_list;
  430. length_slack_equations := length slack_equations;
  431. length_variable_list := length variable_list;
  432. A := mkmatrix(length slack_equations,length variable_list);
  433. for row := 1:length_slack_equations do
  434. <<
  435. for col := 1:length_variable_list do
  436. <<
  437. slack_elt := nth(slack_equations,row);
  438. var_elt := nth(variable_list,col);
  439. fast_setmat(A,row,col,smplx_prepsq(
  440. algebraic coeffn(slack_elt,var_elt,1)));
  441. >>;
  442. >>;
  443. return A;
  444. end;
  445. symbolic procedure get_X_and_obj_mat(objective,variable_list);
  446. %
  447. % Converts the variable list into a matrix and creates the objective
  448. % matrix. This is the matrix s.t. obj_mat * X = objective function.
  449. %
  450. begin
  451. scalar X,obj_mat;
  452. integer i,length_variable_list,tmp;
  453. length_variable_list := length variable_list;
  454. X := mkmatrix(length_variable_list,1);
  455. obj_mat := mkmatrix(1,length_variable_list);
  456. for i := 1:length variable_list do
  457. <<
  458. fast_setmat(X,i,1,nth(variable_list,i));
  459. tmp := nth(variable_list,i);
  460. fast_setmat(obj_mat,1,i,algebraic coeffn(objective,tmp,1));
  461. >>;
  462. return {X,obj_mat};
  463. end;
  464. symbolic procedure get_cb(obj_mat,ib);
  465. %
  466. % Gets hold of the columns of the objective matrix that are pointed
  467. % at in ib.
  468. %
  469. fast_augment_columns(obj_mat,ib);
  470. symbolic procedure compute_objective(cb,xb);
  471. %
  472. % Objective value := cb * xb (both are matrices)
  473. %
  474. fast_getmat(reval {'times,cb,xb},1,1);
  475. symbolic procedure rstep1(A,obj_mat,Binv,ib);
  476. %
  477. % Implements step 1 of the revised simplex algorithm.
  478. % ie: Computation of search direction sb.
  479. %
  480. % See above for details. (comments in simplex).
  481. %
  482. begin
  483. scalar u,sb,sum,i_in_ib;
  484. integer i,j,m,n,k,vkmin;
  485. m := fast_row_dim(A);
  486. n := fast_column_dim(A);
  487. u := mkmatrix(m,1);
  488. sb := mkmatrix(m,1);
  489. % Compute u.
  490. u := reval {'times,{'minus,algebraic (tp(Binv))},
  491. algebraic tp(symbolic get_cb(obj_mat,ib))};
  492. k := 0;
  493. vkmin := 10^10;
  494. i := 1;
  495. for i:=1:n do
  496. <<
  497. i_in_ib := nil;
  498. % Check if i is in ib.
  499. for j:=1:m do
  500. <<
  501. if i = nth(ib,j) then i_in_ib := t;
  502. >>;
  503. if not i_in_ib then
  504. <<
  505. sum := specrd!:plus(smplx_prepsq(fast_getmat(obj_mat,1,i)),
  506. two_column_scalar_product(fast_augment_columns(A,i),u));
  507. % if i is not in ib.
  508. %sum := fast_getmat(obj_mat,1,i);
  509. %for p:=1:m do
  510. %<<
  511. %sum := reval
  512. % {'plus,sum,{'times,fast_getmat(A,p,i),fast_getmat(u,p,1)}};
  513. %>>;
  514. if get_num_part(sum) geq get_num_part(vkmin) then <<>>
  515. else
  516. <<
  517. vkmin := sum;
  518. k := i;
  519. >>;
  520. >>;
  521. >>;
  522. % Do we need a tolerance here?
  523. if get_num_part(vkmin) < 0 then
  524. <<
  525. % Form sb.
  526. for i:=1:m do
  527. <<
  528. sum := 0;
  529. for j:=1:m do sum := specrd!:plus(sum,
  530. specrd!:times(fast_getmat(Binv,i,j),fast_getmat(A,j,k)));
  531. fast_setmat(sb,i,1,sum);
  532. >>;
  533. return {sb,k,u,nil};
  534. >>
  535. else return {sb,k,u,'optimal};
  536. end;
  537. symbolic procedure rstep2(xb,sb);
  538. %
  539. % step 2: Computation of maximum feasible step size Ob.
  540. %
  541. % see above for details. (comments in simplex).
  542. %
  543. begin
  544. scalar ratio;
  545. integer ell,sigb;
  546. sigb := 1*10^30;
  547. for i:=1:fast_row_dim(sb) do
  548. <<
  549. if get_num_part(my_reval fast_getmat(sb,i,1)) leq 0 then <<>>
  550. else
  551. <<
  552. ratio := specrd!:quotient(smplx_prepsq(fast_getmat(xb,i,1)),
  553. smplx_prepsq(fast_getmat(sb,i,1)));
  554. if get_num_part(ratio) geq get_num_part(sigb) then <<>>
  555. else
  556. <<
  557. sigb := ratio;
  558. ell := i;
  559. >>;
  560. >>;
  561. >>;
  562. if ell= 0 then
  563. rederr "Error in simplex: The problem is unbounded.";
  564. return {sigb,ell};
  565. end;
  566. symbolic procedure rstep3(xb,obj_mat,b,Binv,A,ib,k,ell);
  567. %
  568. % step3: Update.
  569. %
  570. % see above for details. (comments in simplex).
  571. %
  572. begin
  573. scalar work,Binv;
  574. work := fast_augment_columns(A,k);
  575. Binv := phiprm(Binv,work,ell);
  576. xb := reval{'times,Binv,b};
  577. nth(ib,ell) := k;
  578. obj_mat := compute_objective(get_cb(obj_mat,ib),xb);
  579. return {Binv,obj_mat,xb};
  580. end;
  581. symbolic procedure phiprm(Binv,D,ell);
  582. %
  583. % Replaces B^(-1) with [phi((B^(-1)',A(k),l)]'.
  584. %
  585. begin
  586. scalar sum,temp;
  587. integer m,j;
  588. m := fast_column_dim(Binv);
  589. sum := scalar_product(fast_stack_rows(Binv,ell),D);
  590. % if get_num_part(sum) = 0 then
  591. % rederr
  592. %{"Error in simplex: new matrix would be singular. Inner product = 0."};
  593. if not zerop get_num_part(sum) then
  594. sum := specrd!:quotient(1,sum);
  595. Binv := fast_mult_rows(Binv,ell,sum);
  596. for j:=1:m do
  597. <<
  598. if j = ell then <<>>
  599. else
  600. <<
  601. temp := fast_getmat(reval{'times,fast_stack_rows(Binv,j),D},
  602. 1,1);
  603. Binv := fast_add_rows(Binv,ell,j,{'minus,temp});
  604. >>;
  605. >>;
  606. return Binv;
  607. end;
  608. symbolic procedure make_answer_list(xb,ib,no_coeffs,X,no_variables);
  609. %
  610. % Creates a list of the values of the variables at the optimal
  611. % solution.
  612. %
  613. begin
  614. scalar x_mat,ans_list;
  615. integer i;
  616. x_mat := mkmatrix(1,no_coeffs);
  617. i := 1;
  618. for each elt in ib do
  619. <<
  620. if fast_getmat(xb,i,1) neq 0 then
  621. fast_setmat(x_mat,1,elt,fast_getmat(xb,i,1)); i := i+1;
  622. >>;
  623. ans_list := for i:=1:no_variables collect
  624. {'equal,my_reval fast_getmat(X,i,1),
  625. get_num_part(my_reval fast_getmat(x_mat,1,i))};
  626. return ans_list;
  627. end;
  628. % Speed functions
  629. symbolic procedure fast_add_rows(in_mat,r1,r2,mult1);
  630. %
  631. % Replaces row2 (r2) by mult1*r1 + r2 without messing around.
  632. %
  633. begin
  634. scalar new_mat,fast_getmatel;
  635. integer i,coldim;
  636. coldim := fast_column_dim(in_mat);
  637. new_mat := copy_mat(in_mat);
  638. if (my_reval mult1) = 0 then return new_mat;
  639. for i:=1:coldim do
  640. <<
  641. if not((fast_getmatel :=my_reval fast_getmat(new_mat,r1,i)) = 0)
  642. then fast_setmat(new_mat,r2,i,specrd!:plus(specrd!:times(
  643. smplx_prepsq(mult1),smplx_prepsq(fast_getmatel)),smplx_prepsq(
  644. fast_getmat(in_mat,r2,i))));
  645. >>;
  646. return new_mat;
  647. end;
  648. symbolic procedure fast_augment_columns(in_mat,col_list);
  649. %
  650. % Quickly augments columns of in_mat specified in col_list.
  651. %
  652. if atom col_list then 'mat.for i:=1:fast_row_dim(in_mat)
  653. collect {fast_getmat(in_mat,i,col_list)}
  654. else 'mat.for each row in cdr in_mat
  655. collect for each elt in col_list collect nth(row,elt);
  656. symbolic procedure fast_matrix_augment(mat_list);
  657. %
  658. % As in linear_algebra package but doesn't produce !*sq output.
  659. %
  660. begin
  661. scalar ll,new_list;
  662. if length mat_list = 1 then return mat_list
  663. else
  664. <<
  665. new_list := {};
  666. for i:=1:fast_row_dim(car mat_list) do
  667. <<
  668. ll := {};
  669. for each mat1 in mat_list do ll := append(ll,nth(cdr mat1,i));
  670. new_list := append(new_list,{ll});
  671. >>;
  672. return 'mat.new_list;
  673. >>;
  674. end;
  675. symbolic procedure fast_setmat(matri,i,j,val);
  676. %
  677. % Set matrix element (i,j) to val.
  678. %
  679. fast_my_letmtr(list(matri,i,j),val,matri);
  680. symbolic procedure fast_unchecked_getmatelem u;
  681. nth(nth(cdr car u,cadr u),caddr u);
  682. symbolic procedure fast_mult_rows(in_mat,row_list,mult1);
  683. %
  684. % In simplex row_list is always an integer.
  685. %
  686. begin
  687. scalar new_list,new_row;
  688. integer row_no;
  689. row_no := 1;
  690. for each row in cdr in_mat do
  691. <<
  692. if row_no neq row_list then new_list := append(new_list,{row})
  693. else
  694. <<
  695. new_row := for each elt in row collect
  696. my_reval{'times,mult1,elt};
  697. new_list := append(new_list,{new_row});
  698. >>;
  699. row_no := row_no+1;
  700. >>;
  701. return 'mat.new_list;
  702. end;
  703. symbolic procedure fast_make_identity(sq_size);
  704. %
  705. % Creates identity matrix.
  706. %
  707. 'mat. (for i:=1:sq_size collect
  708. for j:=1:sq_size collect if i=j then 1 else 0);
  709. symbolic procedure two_column_scalar_product(col1,col2);
  710. %
  711. % Calculates tp(col1)*col2.
  712. %
  713. % Uses sparsity efficiently.
  714. %
  715. begin
  716. scalar sum;
  717. sum := 0;
  718. for i:=1:length cdr col1 do
  719. <<
  720. if car nth(cdr col1,i)=0 or car nth(cdr col2,i)=0 then <<>>
  721. else
  722. sum := specrd!:plus(sum,specrd!:times(smplx_prepsq(
  723. car nth(cdr col1,i)),smplx_prepsq(
  724. car nth(cdr col2,i))));
  725. >>;
  726. return sum;
  727. end;
  728. symbolic procedure scalar_product(row,col);
  729. %
  730. % Calculates row*col.
  731. %
  732. % Uses sparsity efficiently.
  733. %
  734. begin
  735. scalar sum;
  736. sum := 0;
  737. for i:=1:length cadr row do
  738. <<
  739. if nth(cadr row,i)=0 or car nth(cdr col,i)=0 then <<>>
  740. else
  741. sum := specrd!:plus(sum,
  742. specrd!:times(smplx_prepsq(nth(cadr row,i)),
  743. smplx_prepsq(car nth(cdr col,i))));
  744. >>;
  745. return sum;
  746. end;
  747. endmodule; % simplex.
  748. end;