LMSolver.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // This file is part of libhedra, a library for polyhedral mesh processing
  2. //
  3. // Copyright (C) 2016 Amir Vaxman <avaxman@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. #ifndef HEDRA_LEVENBERG_MARQUADT_SOLVER_H
  9. #define HEDRA_LEVENBERG_MARQUADT_SOLVER_H
  10. #include <igl/igl_inline.h>
  11. #include <igl/sortrows.h>
  12. #include <igl/speye.h>
  13. #include <Eigen/Core>
  14. #include <string>
  15. #include <vector>
  16. #include <cstdio>
  17. #include <iostream>
  18. namespace hedra {
  19. namespace optimization
  20. {
  21. template<class LinearSolver, class SolverTraits>
  22. class LMSolver{
  23. public:
  24. Eigen::VectorXd x; //current solution; always updated
  25. Eigen::VectorXd prevx; //the solution of the previous iteration
  26. Eigen::VectorXd x0; //the initial solution to the system
  27. Eigen::VectorXd d; //the direction taken.
  28. Eigen::VectorXd currEnergy; //the current value of the energy
  29. Eigen::VectorXd prevEnergy; //the previous value of the energy
  30. Eigen::VectorXi HRows, HCols; //(row,col) pairs for H=J^T*J matrix
  31. Eigen::VectorXd HVals; //values for H matrix
  32. Eigen::MatrixXi S2D; //single J to J^J indices
  33. LinearSolver* LS;
  34. SolverTraits* ST;
  35. int maxIterations;
  36. double xTolerance;
  37. double fooTolerance;
  38. /*void TestMatrixOperations(){
  39. using namespace Eigen;
  40. using namespace std;
  41. int RowSize=1000;
  42. int ColSize=1000;
  43. int TriSize=4000;
  44. VectorXi Rows;
  45. VectorXi Cols;
  46. VectorXd Vals=VectorXd::Random(TriSize);
  47. VectorXd dRows=VectorXd::Random(TriSize);
  48. VectorXd dCols=VectorXd::Random(TriSize);
  49. cout<<"dRows Range: "<<dRows.minCoeff()<<","<<dRows.maxCoeff()<<endl;
  50. Rows=((dRows+MatrixXd::Constant(dRows.size(),1,1.0))*500.0).cast<int>();
  51. Cols=((dCols+MatrixXd::Constant(dRows.size(),1,1.0))*500.0).cast<int>();
  52. VectorXi SortRows, stub;
  53. VectorXi MRows, MCols;
  54. VectorXd MVals;
  55. igl::sortrows(Rows, true, SortRows, stub);
  56. MatrixXi S2D;
  57. double miu=15.0;
  58. MatrixPattern(SortRows, Cols, MRows, MCols, S2D);
  59. MVals.resize(MRows.size());
  60. MatrixValues(MRows, MCols, Vals, S2D, miu, MVals);
  61. //testing multiplyadjoint
  62. SparseMatrix<double> M(SortRows.maxCoeff()+1,Cols.maxCoeff()+1);
  63. //cout<<"Our I"<<I<<endl;
  64. //cout<<"Our J"<<J<<endl;
  65. //cout<<"Our S"<<S<<endl;
  66. vector<Triplet<double> > Tris;
  67. for (int i=0;i<SortRows.size();i++)
  68. Tris.push_back(Triplet<double>(SortRows(i), Cols(i), Vals(i)));
  69. M.setFromTriplets(Tris.begin(), Tris.end());
  70. Tris.clear();
  71. SparseMatrix<double> I;
  72. igl::speye(M.cols(),M.cols(),I);
  73. SparseMatrix<double> MtM1=M.transpose()*M+miu*I;
  74. SparseMatrix<double> MtM2(MtM1.rows(), MtM1.cols());
  75. for (int i=0;i<MRows.size();i++)
  76. Tris.push_back(Triplet<double>(MRows(i), MCols(i), MVals(i)));
  77. MtM2.setFromTriplets(Tris.begin(), Tris.end());
  78. bool Discrepancy=false;
  79. SparseMatrix<double> DiffMat=MtM1-MtM2;
  80. for (int k=0; k<DiffMat.outerSize(); ++k){
  81. for (SparseMatrix<double>::InnerIterator it(DiffMat,k); it; ++it){
  82. if ((abs(it.value())>10e-6)&&(it.row()<=it.col())){
  83. cout<<"Discrepancy at ("<<it.row()<<","<<it.col()<<"): "<<it.value()<<endl;
  84. cout<<"MtM Our Values:"<<MtM2.coeffRef(it.row(),it.col())<<endl;
  85. cout<<"MtM Evaluated:"<<MtM1.coeffRef(it.row(),it.col())<<endl;
  86. Discrepancy=true;
  87. }
  88. }
  89. }
  90. if (!Discrepancy) cout<<"Matrices are equal!"<<endl;
  91. }*/
  92. //Input: pattern of matrix M by (iI,iJ) representation
  93. //Output: pattern of matrix M^T*M by (oI, oJ) representation
  94. // map between values in the input to values in the output (Single2Double). The map is aggregating values from future iS to oS
  95. //prerequisite: iI are sorted by rows (not necessary columns)
  96. void MatrixPattern(const Eigen::VectorXi& iI,
  97. const Eigen::VectorXi& iJ,
  98. Eigen::VectorXi& oI,
  99. Eigen::VectorXi& oJ,
  100. Eigen::MatrixXi& S2D)
  101. {
  102. int CurrTri=0;
  103. using namespace Eigen;
  104. std::vector<int> oIlist;
  105. std::vector<int> oJlist;
  106. std::vector<std::pair<int, int> > S2Dlist;
  107. do{
  108. int CurrRow=iI(CurrTri);
  109. int NumCurrTris=0;
  110. while ((CurrTri+NumCurrTris<iI.size())&&(iI(CurrTri+NumCurrTris)==CurrRow))
  111. NumCurrTris++;
  112. for (int i=CurrTri;i<CurrTri+NumCurrTris;i++){
  113. for (int j=CurrTri;j<CurrTri+NumCurrTris;j++){
  114. if (iJ(j)>=iJ(i)){
  115. oIlist.push_back(iJ(i));
  116. oJlist.push_back(iJ(j));
  117. S2Dlist.push_back(std::pair<int,int>(i,j));
  118. }
  119. }
  120. }
  121. CurrTri+=NumCurrTris;
  122. }while (CurrTri!=iI.size());
  123. //triplets for miu
  124. for (int i=0;i<iJ.maxCoeff()+1;i++){
  125. oIlist.push_back(i);
  126. oJlist.push_back(i);
  127. }
  128. oI.resize(oIlist.size());
  129. oJ.resize(oJlist.size());
  130. S2D.resize(S2Dlist.size(),2);
  131. for (int i=0;i<oIlist.size();i++){
  132. oI(i)=oIlist[i];
  133. oJ(i)=oJlist[i];
  134. }
  135. for (int i=0;i<S2Dlist.size();i++)
  136. S2D.row(i)<<S2Dlist[i].first, S2Dlist[i].second;
  137. }
  138. //returns the values of M^T*M+miu*I by multiplication and aggregating from Single2double list.
  139. //prerequisite - oS is allocated
  140. void MatrixValues(const Eigen::VectorXi& oI,
  141. const Eigen::VectorXi& oJ,
  142. const Eigen::VectorXd& iS,
  143. const Eigen::MatrixXi& S2D,
  144. const double miu,
  145. Eigen::VectorXd& oS)
  146. {
  147. for (int i=0;i<S2D.rows();i++)
  148. oS(i)=iS(S2D(i,0))*iS(S2D(i,1));
  149. //adding miu*I
  150. for (int i=S2D.rows();i<oI.rows();i++)
  151. oS(i)=miu;
  152. }
  153. //returns M^t*ivec by (I,J,S) representation
  154. void MultiplyAdjointVector(const Eigen::VectorXi& iI,
  155. const Eigen::VectorXi& iJ,
  156. const Eigen::VectorXd& iS,
  157. const Eigen::VectorXd& iVec,
  158. Eigen::VectorXd& oVec)
  159. {
  160. oVec.setZero();
  161. for (int i=0;i<iI.size();i++)
  162. oVec(iJ(i))+=iS(i)*iVec(iI(i));
  163. }
  164. public:
  165. LMSolver(){};
  166. void init(LinearSolver* _LS,
  167. SolverTraits* _ST,
  168. int _maxIterations=100,
  169. double _xTolerance=10e-9,
  170. double _fooTolerance=10e-9){
  171. LS=_LS;
  172. ST=_ST;
  173. maxIterations=_maxIterations;
  174. xTolerance=_xTolerance;
  175. fooTolerance=_fooTolerance;
  176. //analysing pattern
  177. MatrixPattern(ST->JRows, ST->JCols,HRows,HCols,S2D);
  178. HVals.resize(HRows.size());
  179. LS->analyze(HRows,HCols, true);
  180. d.resize(ST->xSize);
  181. x.resize(ST->xSize);
  182. x0.resize(ST->xSize);
  183. prevx.resize(ST->xSize);
  184. currEnergy.resize(ST->EVec.size());
  185. prevEnergy.resize(ST->EVec.size());
  186. //TestMatrixOperations();
  187. }
  188. bool solve(const bool verbose) {
  189. using namespace Eigen;
  190. using namespace std;
  191. ST->initial_solution(x0);
  192. prevx<<x0;
  193. int currIter=0;
  194. bool stop=false;
  195. double currError, prevError;
  196. VectorXd rhs(ST->xSize);
  197. VectorXd direction;
  198. if (verbose)
  199. cout<<"******Beginning Optimization******"<<endl;
  200. double tau=10e-3;
  201. //estimating initial miu
  202. double miu=0.0;
  203. ST->update_jacobian(prevx);
  204. MatrixValues(HRows, HCols, ST->JVals, S2D, miu, HVals);
  205. for (int i=0;i<HRows.size();i++)
  206. if (HRows(i)==HCols(i)) //on the diagonal
  207. miu=(miu < HVals(i) ? HVals(i) : miu);
  208. miu*=tau;
  209. double initmiu=miu;
  210. cout<<"initial miu: "<<miu<<endl;
  211. double beta=2.0;
  212. double nu=beta;
  213. double gamma=3.0;
  214. do{
  215. currIter=0;
  216. stop=false;
  217. do{
  218. ST->pre_iteration(prevx);
  219. ST->update_energy(prevx);
  220. ST->update_jacobian(prevx);
  221. if (verbose)
  222. cout<<"Initial Energy for Iteration "<<currIter<<": "<<ST->EVec.template squaredNorm()<<endl;
  223. MatrixValues(HRows, HCols, ST->JVals, S2D, miu, HVals);
  224. MultiplyAdjointVector(ST->JRows, ST->JCols, ST->JVals, -ST->EVec, rhs);
  225. double firstOrderOptimality=rhs.template lpNorm<Infinity>();
  226. if (verbose)
  227. cout<<"firstOrderOptimality: "<<firstOrderOptimality<<endl;
  228. if (firstOrderOptimality<fooTolerance){
  229. x=prevx;
  230. if (verbose){
  231. cout<<"First-order optimality has been reached"<<endl;
  232. break;
  233. }
  234. }
  235. //solving to get the GN direction
  236. if(!LS->factorize(HVals, true)) {
  237. // decomposition failed
  238. cout<<"Solver Failed to factorize! "<<endl;
  239. return false;
  240. }
  241. MatrixXd mRhs=rhs;
  242. MatrixXd mDirection;
  243. LS->solve(mRhs,mDirection);
  244. direction=mDirection.col(0);
  245. if (verbose)
  246. cout<<"direction magnitude: "<<direction.norm()<<endl;
  247. if (direction.norm() < xTolerance * prevx.norm()){
  248. x=prevx;
  249. if (verbose)
  250. cout<<"Stopping since direction magnitude small."<<endl;
  251. break;
  252. }
  253. VectorXd tryx=prevx+direction;
  254. ST->update_energy(prevx);
  255. double prevE=ST->EVec.squaredNorm();
  256. ST->update_energy(tryx);
  257. double currE=ST->EVec.squaredNorm();
  258. double rho=(prevE-currE)/(direction.dot(miu*direction+rhs));
  259. if (rho>0){
  260. x=tryx;
  261. //if (verbose){
  262. //cout<<"Energy: "<<currE<<endl;
  263. // cout<<"1.0-(beta-1.0)*pow(2.0*rho-1.0,3): "<<1.0-(beta-1.0)*pow(2.0*rho-1.0,3)<<endl;
  264. //}
  265. miu*=(1.0/gamma > 1.0-(beta-1.0)*pow(2.0*rho-1.0,3) ? 1.0/gamma : 1.0-(beta-1.0)*pow(2.0*rho-1.0,3));
  266. nu=beta;
  267. //if (verbose)
  268. // cout<<"rho, miu, nu: "<<rho<<","<<miu<<","<<nu<<endl;
  269. } else {
  270. x=prevx;
  271. miu = miu*nu;
  272. nu=2*nu;
  273. //if (verbose)
  274. // cout<<"rho, miu, nu: "<<rho<<","<<miu<<","<<nu<<endl;
  275. }
  276. //The SolverTraits can order the optimization to stop by giving "true" of to continue by giving "false"
  277. if (ST->post_iteration(x)){
  278. if (verbose)
  279. cout<<"ST->Post_iteration() gave a stop"<<endl;
  280. break;
  281. }
  282. currIter++;
  283. prevx=x;
  284. }while (currIter<=maxIterations);
  285. }while (!ST->post_optimization(x));
  286. return true;
  287. }
  288. };
  289. }
  290. }
  291. #endif