linprog.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "linprog.h"
  9. #include "slice.h"
  10. #include "slice_into.h"
  11. #include "find.h"
  12. #include "matlab_format.h"
  13. #include "colon.h"
  14. #include <iostream>
  15. //#define IGL_LINPROG_VERBOSE
  16. IGL_INLINE bool igl::linprog(
  17. const Eigen::VectorXd & c,
  18. const Eigen::MatrixXd & _A,
  19. const Eigen::VectorXd & b,
  20. const int k,
  21. Eigen::VectorXd & x)
  22. {
  23. // This is a very literal translation of
  24. // http://www.mathworks.com/matlabcentral/fileexchange/2166-introduction-to-linear-algebra/content/strang/linprog.m
  25. using namespace Eigen;
  26. using namespace std;
  27. using namespace igl;
  28. bool success = true;
  29. // number of constraints
  30. const int m = _A.rows();
  31. // number of original variables
  32. const int n = _A.cols();
  33. // number of iterations
  34. int it = 0;
  35. // maximum number of iterations
  36. //const int MAXIT = 10*m;
  37. const int MAXIT = 100*m;
  38. // residual tolerance
  39. const double tol = 1e-10;
  40. const auto & sign = [](const Eigen::VectorXd & B) -> Eigen::VectorXd
  41. {
  42. Eigen::VectorXd Bsign(B.size());
  43. for(int i = 0;i<B.size();i++)
  44. {
  45. Bsign(i) = B(i)>0?1:(B(i)<0?-1:0);
  46. }
  47. return Bsign;
  48. };
  49. // initial (inverse) basis matrix
  50. VectorXd Dv = sign(sign(b).array()+0.5);
  51. Dv.head(k).setConstant(1.);
  52. MatrixXd D = Dv.asDiagonal();
  53. // Incorporate slack variables
  54. MatrixXd A(_A.rows(),_A.cols()+D.cols());
  55. A<<_A,D;
  56. // Initial basis
  57. VectorXi B = igl::colon<int>(n,n+m-1);
  58. // non-basis, may turn out that vector<> would be better here
  59. VectorXi N = igl::colon<int>(0,n-1);
  60. int j;
  61. double bmin = b.minCoeff(&j);
  62. int phase;
  63. VectorXd xb;
  64. VectorXd s;
  65. VectorXi J;
  66. if(k>0 && bmin<0)
  67. {
  68. phase = 1;
  69. xb = VectorXd::Ones(m);
  70. // super cost
  71. s.resize(n+m+1);
  72. s<<VectorXd::Zero(n+k),VectorXd::Ones(m-k+1);
  73. N.resize(n+1);
  74. N<<igl::colon<int>(0,n-1),B(j);
  75. J.resize(B.size()-1);
  76. // [0 1 2 3 4]
  77. // ^
  78. // [0 1]
  79. // [3 4]
  80. J.head(j) = B.head(j);
  81. J.tail(B.size()-j-1) = B.tail(B.size()-j-1);
  82. B(j) = n+m;
  83. MatrixXd AJ;
  84. igl::slice(A,J,2,AJ);
  85. const VectorXd a = b - AJ.rowwise().sum();
  86. {
  87. MatrixXd old_A = A;
  88. A.resize(A.rows(),A.cols()+a.cols());
  89. A<<old_A,a;
  90. }
  91. D.col(j) = -a/a(j);
  92. D(j,j) = 1./a(j);
  93. }else if(k==m)
  94. {
  95. phase = 2;
  96. xb = b;
  97. s.resize(c.size()+m);
  98. // cost function
  99. s<<c,VectorXd::Zero(m);
  100. }else //k = 0 or bmin >=0
  101. {
  102. phase = 1;
  103. xb = b.array().abs();
  104. s.resize(n+m);
  105. // super cost
  106. s<<VectorXd::Zero(n+k),VectorXd::Ones(m-k);
  107. }
  108. while(phase<3)
  109. {
  110. double df = -1;
  111. int t = std::numeric_limits<int>::max();
  112. // Lagrange mutipliers fro Ax=b
  113. VectorXd yb = D.transpose() * igl::slice(s,B);
  114. while(true)
  115. {
  116. if(MAXIT>0 && it>=MAXIT)
  117. {
  118. #ifdef IGL_LINPROG_VERBOSE
  119. cerr<<"linprog: warning! maximum iterations without convergence."<<endl;
  120. #endif
  121. success = false;
  122. break;
  123. }
  124. // no freedom for minimization
  125. if(N.size() == 0)
  126. {
  127. break;
  128. }
  129. // reduced costs
  130. VectorXd sN = igl::slice(s,N);
  131. MatrixXd AN = igl::slice(A,N,2);
  132. VectorXd r = sN - AN.transpose() * yb;
  133. int q;
  134. // determine new basic variable
  135. double rmin = r.minCoeff(&q);
  136. // optimal! infinity norm
  137. if(rmin>=-tol*(sN.array().abs().maxCoeff()+1))
  138. {
  139. break;
  140. }
  141. // increment iteration count
  142. it++;
  143. // apply Bland's rule to avoid cycling
  144. if(df>=0)
  145. {
  146. if(MAXIT == -1)
  147. {
  148. #ifdef IGL_LINPROG_VERBOSE
  149. cerr<<"linprog: warning! degenerate vertex"<<endl;
  150. #endif
  151. success = false;
  152. }
  153. igl::find((r.array()<0).eval(),J);
  154. double Nq = igl::slice(N,J).minCoeff();
  155. // again seems like q is assumed to be a scalar though matlab code
  156. // could produce a vector for multiple matches
  157. (N.array()==Nq).cast<int>().maxCoeff(&q);
  158. }
  159. VectorXd d = D*A.col(N(q));
  160. VectorXi I;
  161. igl::find((d.array()>tol).eval(),I);
  162. if(I.size() == 0)
  163. {
  164. #ifdef IGL_LINPROG_VERBOSE
  165. cerr<<"linprog: warning! solution is unbounded"<<endl;
  166. #endif
  167. // This seems dubious:
  168. it=-it;
  169. success = false;
  170. break;
  171. }
  172. VectorXd xbd = igl::slice(xb,I).array()/igl::slice(d,I).array();
  173. // new use of r
  174. int p;
  175. {
  176. double r;
  177. r = xbd.minCoeff(&p);
  178. p = I(p);
  179. // apply Bland's rule to avoid cycling
  180. if(df>=0)
  181. {
  182. igl::find((xbd.array()==r).eval(),J);
  183. double Bp = igl::slice(B,igl::slice(I,J)).minCoeff();
  184. // idiotic way of finding index in B of Bp
  185. // code down the line seems to assume p is a scalar though the matlab
  186. // code could find a vector of matches)
  187. (B.array()==Bp).cast<int>().maxCoeff(&p);
  188. }
  189. // update x
  190. xb -= r*d;
  191. xb(p) = r;
  192. // change in f
  193. df = r*rmin;
  194. }
  195. // row vector
  196. RowVectorXd v = D.row(p)/d(p);
  197. yb += v.transpose() * (s(N(q)) - d.transpose()*igl::slice(s,B));
  198. d(p)-=1;
  199. // update inverse basis matrix
  200. D = D - d*v;
  201. t = B(p);
  202. B(p) = N(q);
  203. if(t>(n+k-1))
  204. {
  205. // remove qth entry from N
  206. VectorXi old_N = N;
  207. N.resize(N.size()-1);
  208. N.head(q) = old_N.head(q);
  209. N.head(q) = old_N.head(q);
  210. N.tail(old_N.size()-q-1) = old_N.tail(old_N.size()-q-1);
  211. }else
  212. {
  213. N(q) = t;
  214. }
  215. }
  216. // iterative refinement
  217. xb = (xb+D*(b-igl::slice(A,B,2)*xb)).eval();
  218. // must be due to rounding
  219. VectorXi I;
  220. igl::find((xb.array()<0).eval(),I);
  221. if(I.size()>0)
  222. {
  223. // so correct
  224. VectorXd Z = VectorXd::Zero(I.size(),1);
  225. igl::slice_into(Z,I,xb);
  226. }
  227. // B, xb,n,m,res=A(:,B)*xb-b
  228. if(phase == 2 || it<0)
  229. {
  230. break;
  231. }
  232. if(xb.transpose()*igl::slice(s,B) > tol)
  233. {
  234. it = -it;
  235. #ifdef IGL_LINPROG_VERBOSE
  236. cerr<<"linprog: warning, no feasible solution"<<endl;
  237. #endif
  238. success = false;
  239. break;
  240. }
  241. // re-initialize for Phase 2
  242. phase = phase+1;
  243. s*=1e6*c.array().abs().maxCoeff();
  244. s.head(n) = c;
  245. }
  246. x.resize(std::max(B.maxCoeff()+1,n));
  247. igl::slice_into(xb,B,x);
  248. x = x.head(n).eval();
  249. return success;
  250. }
  251. IGL_INLINE bool igl::linprog(
  252. const Eigen::VectorXd & f,
  253. const Eigen::MatrixXd & A,
  254. const Eigen::VectorXd & b,
  255. const Eigen::MatrixXd & B,
  256. const Eigen::VectorXd & c,
  257. Eigen::VectorXd & x)
  258. {
  259. using namespace Eigen;
  260. using namespace igl;
  261. using namespace std;
  262. const int m = A.rows();
  263. const int n = A.cols();
  264. const int p = B.rows();
  265. MatrixXd Im = MatrixXd::Identity(m,m);
  266. MatrixXd AS(m,n+m);
  267. AS<<A,Im;
  268. MatrixXd bS = b.array().abs();
  269. for(int i = 0;i<m;i++)
  270. {
  271. const auto & sign = [](double x)->double
  272. {
  273. return (x<0?-1:(x>0?1:0));
  274. };
  275. AS.row(i) *= sign(b(i));
  276. }
  277. MatrixXd In = MatrixXd::Identity(n,n);
  278. MatrixXd P(n+m,2*n+m);
  279. P<< In, -In, MatrixXd::Zero(n,m),
  280. MatrixXd::Zero(m,2*n), Im;
  281. MatrixXd ASP = AS*P;
  282. MatrixXd BSP(0,2*n+m);
  283. if(p>0)
  284. {
  285. MatrixXd BS(p,2*n);
  286. BS<<B,MatrixXd::Zero(p,n);
  287. BSP = BS*P;
  288. }
  289. VectorXd fSP = VectorXd::Ones(2*n+m);
  290. fSP.head(2*n) = P.block(0,0,n,2*n).transpose()*f;
  291. const VectorXd & cc = fSP;
  292. MatrixXd AA(m+p,2*n+m);
  293. AA<<ASP,BSP;
  294. VectorXd bb(m+p);
  295. bb<<bS,c;
  296. VectorXd xxs;
  297. bool ret = linprog(cc,AA,bb,0,xxs);
  298. x = P.block(0,0,n,2*n+m)*xxs;
  299. return ret;
  300. }