linprog.cpp 8.0 KB

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