SLSolver.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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_SINGLE_LINEAR_SOLVER_H
  9. #define HEDRA_SINGLE_LINEAR_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 SLSolver{
  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. //Input: pattern of matrix M by (iI,iJ) representation
  36. //Output: pattern of matrix M^T*M by (oI, oJ) representation
  37. // map between values in the input to values in the output (Single2Double). The map is aggregating values from future iS to oS
  38. //prerequisite: iI are sorted by rows (not necessary columns)
  39. void MatrixPattern(const Eigen::VectorXi& iI,
  40. const Eigen::VectorXi& iJ,
  41. Eigen::VectorXi& oI,
  42. Eigen::VectorXi& oJ,
  43. Eigen::MatrixXi& S2D)
  44. {
  45. int CurrTri=0;
  46. using namespace Eigen;
  47. std::vector<int> oIlist;
  48. std::vector<int> oJlist;
  49. std::vector<std::pair<int, int> > S2Dlist;
  50. do{
  51. int CurrRow=iI(CurrTri);
  52. int NumCurrTris=0;
  53. while ((CurrTri+NumCurrTris<iI.size())&&(iI(CurrTri+NumCurrTris)==CurrRow))
  54. NumCurrTris++;
  55. for (int i=CurrTri;i<CurrTri+NumCurrTris;i++){
  56. for (int j=CurrTri;j<CurrTri+NumCurrTris;j++){
  57. if (iJ(j)>=iJ(i)){
  58. oIlist.push_back(iJ(i));
  59. oJlist.push_back(iJ(j));
  60. S2Dlist.push_back(std::pair<int,int>(i,j));
  61. }
  62. }
  63. }
  64. CurrTri+=NumCurrTris;
  65. }while (CurrTri!=iI.size());
  66. oI.resize(oIlist.size());
  67. oJ.resize(oJlist.size());
  68. S2D.resize(S2Dlist.size(),2);
  69. for (int i=0;i<oIlist.size();i++){
  70. oI(i)=oIlist[i];
  71. oJ(i)=oJlist[i];
  72. }
  73. for (int i=0;i<S2Dlist.size();i++)
  74. S2D.row(i)<<S2Dlist[i].first, S2Dlist[i].second;
  75. }
  76. //returns the values of M^T*M+miu*I by multiplication and aggregating from Single2double list.
  77. //prerequisite - oS is allocated
  78. void MatrixValues(const Eigen::VectorXi& oI,
  79. const Eigen::VectorXi& oJ,
  80. const Eigen::VectorXd& iS,
  81. const Eigen::MatrixXi& S2D,
  82. Eigen::VectorXd& oS)
  83. {
  84. for (int i=0;i<S2D.rows();i++)
  85. oS(i)=iS(S2D(i,0))*iS(S2D(i,1));
  86. }
  87. //returns M^t*ivec by (I,J,S) representation
  88. void MultiplyAdjointVector(const Eigen::VectorXi& iI,
  89. const Eigen::VectorXi& iJ,
  90. const Eigen::VectorXd& iS,
  91. const Eigen::VectorXd& iVec,
  92. Eigen::VectorXd& oVec)
  93. {
  94. oVec.setZero();
  95. for (int i=0;i<iI.size();i++)
  96. oVec(iJ(i))+=iS(i)*iVec(iI(i));
  97. }
  98. public:
  99. SLSolver(){};
  100. void init(LinearSolver* _LS,
  101. SolverTraits* _ST){
  102. LS=_LS;
  103. ST=_ST;
  104. //analysing pattern
  105. MatrixPattern(ST->JRows, ST->JCols,HRows,HCols,S2D);
  106. HVals.resize(HRows.size());
  107. LS->analyze(HRows,HCols);
  108. d.resize(ST->xSize);
  109. x.resize(ST->xSize);
  110. x0.resize(ST->xSize);
  111. prevx.resize(ST->xSize);
  112. currEnergy.resize(ST->EVec.size());
  113. prevEnergy.resize(ST->EVec.size());
  114. //TestMatrixOperations();
  115. }
  116. bool solve(const bool verbose) {
  117. using namespace Eigen;
  118. using namespace std;
  119. ST->initial_solution(x0);
  120. prevx<<x0;
  121. int currIter=0;
  122. bool stop=false;
  123. double currError, prevError;
  124. VectorXd rhs(ST->xSize);
  125. VectorXd direction;
  126. if (verbose)
  127. cout<<"******Beginning Optimization******"<<endl;
  128. ST->update_jacobian(prevx);
  129. do{
  130. ST->update_energy(prevx);
  131. ST->update_jacobian(prevx);
  132. ST->pre_iteration(prevx);
  133. MatrixValues(HRows, HCols, ST->JVals, S2D, HVals);
  134. MultiplyAdjointVector(ST->JRows, ST->JCols, ST->JVals, -ST->EVec, rhs);
  135. //solving to get the GN direction
  136. if(!LS->factorize(HVals)) {
  137. // decomposition failed
  138. cout<<"Solver Failed to factorize! "<<endl;
  139. return false;
  140. }
  141. LS->solve(rhs,direction);
  142. x=prevx+direction;
  143. ST->update_energy(x);
  144. ST->update_jacobian(x);
  145. ST->post_iteration(x);
  146. prevx=x;
  147. }while (!ST->post_optimization(x));
  148. return true;
  149. }
  150. };
  151. }
  152. }
  153. #endif