PageRenderTime 25ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/OpenNL/include/CGAL/OpenNL/linear_solver.h

https://gitlab.com/Namdhari/cgal-AnatoMeCo
C Header | 478 lines | 319 code | 68 blank | 91 comment | 26 complexity | e9ee6871a03a6da104d52b4a62e91747 MD5 | raw file
  1. // Copyright (c) 2005-2008 Inria Loria (France).
  2. /*
  3. * author: Bruno Levy, INRIA, project ALICE
  4. * website: http://www.loria.fr/~levy/software
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation, either version 3
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. * Scientific work that use this software can reference the website and
  21. * the following publication:
  22. *
  23. * @INPROCEEDINGS {levy:NMDGP:05,
  24. * AUTHOR = Bruno Levy,
  25. * TITLE = Numerical Methods for Digital Geometry Processing,
  26. * BOOKTITLE =Israel Korea Bi-National Conference,
  27. * YEAR=November 2005,
  28. * URL=http://www.loria.fr/~levy/php/article.php?pub=../publications/papers/2005/Numerics
  29. * }
  30. *
  31. * Laurent Saboret 2005-2006: Changes for CGAL:
  32. * - Added OpenNL namespace
  33. * - DefaultLinearSolverTraits is now a model of the SparseLinearAlgebraTraits_d concept
  34. * - Added SymmetricLinearSolverTraits
  35. * - copied Jacobi preconditioner from Graphite 1.9 code
  36. */
  37. #ifndef __OPENNL_LINEAR_SOLVER__
  38. #define __OPENNL_LINEAR_SOLVER__
  39. #include <CGAL/OpenNL/conjugate_gradient.h>
  40. #include <CGAL/OpenNL/bicgstab.h>
  41. #include <CGAL/OpenNL/preconditioner.h>
  42. #include <CGAL/OpenNL/sparse_matrix.h>
  43. #include <CGAL/OpenNL/full_vector.h>
  44. #include <vector>
  45. #include <iostream>
  46. #include <cstdlib>
  47. #include <CGAL/use.h>
  48. namespace OpenNL {
  49. // Class DefaultLinearSolverTraits
  50. // is a traits class for solving general sparse linear systems.
  51. // It uses BICGSTAB solver with Jacobi preconditioner.
  52. //
  53. // Concept: Model of the SparseLinearAlgebraTraits_d concept.
  54. template
  55. <
  56. class COEFFTYPE, // type of matrix and vector coefficients
  57. class MATRIX = SparseMatrix<COEFFTYPE>, // model of SparseLinearSolverTraits_d::Matrix
  58. class VECTOR = FullVector<COEFFTYPE> // model of SparseLinearSolverTraits_d::Vector
  59. >
  60. class DefaultLinearSolverTraits
  61. {
  62. // Public types
  63. public:
  64. typedef COEFFTYPE CoeffType ;
  65. typedef COEFFTYPE NT;
  66. typedef MATRIX Matrix ;
  67. typedef VECTOR Vector ;
  68. // Private types
  69. private:
  70. typedef Jacobi_Preconditioner<NT> Preconditioner ;
  71. typedef Solver_preconditioned_BICGSTAB<Matrix, Preconditioner, Vector>
  72. Preconditioned_solver ;
  73. typedef Solver_BICGSTAB<Matrix, Vector> Solver ;
  74. // Public operations
  75. public:
  76. // Default contructor, copy constructor, operator=() and destructor are fine
  77. // Solve the sparse linear system "A*X = B"
  78. // Return true on success. The solution is then (1/D) * X.
  79. //
  80. // Preconditions:
  81. // - A.row_dimension() == B.dimension()
  82. // - A.column_dimension() == X.dimension()
  83. bool linear_solver (const Matrix& A, const Vector& B, Vector& X, NT& D)
  84. {
  85. D = 1; // OpenNL does not support homogeneous coordinates
  86. // Solve using BICGSTAB solver with preconditioner
  87. Preconditioned_solver preconditioned_solver ;
  88. NT omega = 1.5;
  89. Preconditioner C(A, omega);
  90. X = B;
  91. if (preconditioned_solver.solve(A, C, B, X))
  92. return true;
  93. // On error, solve using BICGSTAB solver without preconditioner
  94. #ifdef DEBUG_TRACE
  95. std::cerr << " Failure of BICGSTAB solver with Jacobi preconditioner. "
  96. << "Trying BICGSTAB." << std::endl;
  97. #endif
  98. Solver solver ;
  99. X = B;
  100. return solver.solve(A, B, X) ;
  101. }
  102. } ;
  103. // Class SymmetricLinearSolverTraits
  104. // is a traits class for solving symmetric positive definite sparse linear systems.
  105. // It uses Conjugate Gradient solver with Jacobi preconditioner.
  106. //
  107. // Concept: Model of the SparseLinearAlgebraTraits_d concept.
  108. template
  109. <
  110. class COEFFTYPE, // type of matrix and vector coefficients
  111. class MATRIX = SparseMatrix<COEFFTYPE>, // model of SparseLinearSolverTraits_d::Matrix
  112. class VECTOR = FullVector<COEFFTYPE> // model of SparseLinearSolverTraits_d::Vector
  113. >
  114. class SymmetricLinearSolverTraits
  115. {
  116. // Public types
  117. public:
  118. typedef COEFFTYPE CoeffType ;
  119. typedef COEFFTYPE NT;
  120. typedef MATRIX Matrix ;
  121. typedef VECTOR Vector ;
  122. // Private types
  123. private:
  124. typedef Jacobi_Preconditioner<NT> Preconditioner ;
  125. typedef Solver_preconditioned_CG<Matrix, Preconditioner, Vector>
  126. Preconditioned_solver ;
  127. typedef Solver_CG<Matrix, Vector> Solver ;
  128. // Public operations
  129. public:
  130. // Default contructor, copy constructor, operator=() and destructor are fine
  131. // Solve the sparse linear system "A*X = B"
  132. // Return true on success. The solution is then (1/D) * X.
  133. //
  134. // Preconditions:
  135. // - A.row_dimension() == B.dimension()
  136. // - A.column_dimension() == X.dimension()
  137. bool linear_solver (const Matrix& A, const Vector& B, Vector& X, NT& D)
  138. {
  139. D = 1; // OpenNL does not support homogeneous coordinates
  140. // Solve using Conjugate Gradient solver with preconditioner
  141. Preconditioned_solver preconditioned_solver ;
  142. NT omega = 1.5;
  143. Preconditioner C(A, omega);
  144. X = B;
  145. if (preconditioned_solver.solve(A, C, B, X))
  146. return true;
  147. // On error, solve using Conjugate Gradient solver without preconditioner
  148. #ifdef DEBUG_TRACE
  149. std::cerr << " Failure of Conjugate Gradient solver with Jacobi preconditioner. "
  150. << "Trying Conjugate Gradient." << std::endl;
  151. #endif
  152. Solver solver ;
  153. X = B;
  154. return solver.solve(A, B, X) ;
  155. }
  156. };
  157. /*
  158. * Solves a linear system or minimizes a quadratic form.
  159. *
  160. * Requirements for its traits class: must be a model of SparseLinearSolverTraits_d concept
  161. */
  162. template <class TRAITS>
  163. class LinearSolver
  164. {
  165. protected:
  166. enum State {
  167. INITIAL, IN_SYSTEM, IN_ROW, CONSTRUCTED, SOLVED
  168. } ;
  169. public:
  170. typedef TRAITS Traits ;
  171. typedef typename Traits::Matrix Matrix ;
  172. typedef typename Traits::Vector Vector ;
  173. typedef typename Traits::NT CoeffType ;
  174. class Variable {
  175. public:
  176. Variable() : x_(0), index_(-1), locked_(false) { }
  177. double value() const { return x_; }
  178. void set_value(double x_in) { x_ = x_in ; }
  179. void lock() { locked_ = true ; }
  180. void unlock() { locked_ = false ; }
  181. bool is_locked() const { return locked_ ; }
  182. unsigned int index() const {
  183. CGAL_assertion(index_ != -1) ;
  184. return (unsigned int)(index_) ;
  185. }
  186. void set_index(unsigned int index_in) {
  187. index_ = index_in ;
  188. }
  189. private:
  190. CoeffType x_ ;
  191. int index_ ;
  192. bool locked_ ;
  193. } ;
  194. LinearSolver(unsigned int nb_variables) {
  195. state_ = INITIAL ;
  196. least_squares_ = false ;
  197. nb_variables_ = nb_variables ;
  198. variable_ = new Variable[nb_variables] ;
  199. A_ = NULL ;
  200. x_ = NULL ;
  201. b_ = NULL ;
  202. }
  203. ~LinearSolver() {
  204. delete[] variable_ ;
  205. delete A_ ;
  206. delete x_ ;
  207. delete b_ ;
  208. }
  209. // __________________ Parameters ________________________
  210. void set_least_squares(bool x) { least_squares_ = x ; }
  211. // __________________ Access ____________________________
  212. int nb_variables() const { return nb_variables_ ; }
  213. Variable& variable(unsigned int idx) {
  214. CGAL_assertion(idx < nb_variables_) ;
  215. return variable_[idx] ;
  216. }
  217. const Variable& variable(unsigned int idx) const {
  218. CGAL_assertion(idx < nb_variables_) ;
  219. return variable_[idx] ;
  220. }
  221. // _________________ Construction _______________________
  222. void begin_system() {
  223. current_row_ = 0 ;
  224. transition(INITIAL, IN_SYSTEM) ;
  225. // Enumerate free variables.
  226. unsigned int index = 0 ;
  227. for(int ii=0; ii < nb_variables() ; ii++) {
  228. Variable& v = variable(ii) ;
  229. if(!v.is_locked()) {
  230. v.set_index(index) ;
  231. index++ ;
  232. }
  233. }
  234. unsigned int n = index ;
  235. A_ = new Matrix(static_cast<int>(n)) ;
  236. x_ = new Vector(n) ;
  237. b_ = new Vector(n) ;
  238. for(unsigned int i=0; i<n; i++) {
  239. (*x_)[i] = 0 ;
  240. (*b_)[i] = 0 ;
  241. }
  242. variables_to_vector() ;
  243. }
  244. void begin_row() {
  245. transition(IN_SYSTEM, IN_ROW) ;
  246. af_.clear() ;
  247. if_.clear() ;
  248. al_.clear() ;
  249. xl_.clear() ;
  250. bk_ = 0 ;
  251. }
  252. void set_right_hand_side(double b) {
  253. check_state(IN_ROW) ;
  254. bk_ = b ;
  255. }
  256. void add_coefficient(unsigned int iv, double a) {
  257. check_state(IN_ROW) ;
  258. Variable& v = variable(iv) ;
  259. if(v.is_locked()) {
  260. al_.push_back(a) ;
  261. xl_.push_back(v.value()) ;
  262. } else {
  263. af_.push_back(a) ;
  264. if_.push_back(v.index()) ;
  265. }
  266. }
  267. void normalize_row(CoeffType weight = 1) {
  268. check_state(IN_ROW) ;
  269. CoeffType norm = 0.0 ;
  270. unsigned int nf = af_.size() ;
  271. for(unsigned int i=0; i<nf; i++) {
  272. norm += af_[i] * af_[i] ;
  273. }
  274. unsigned int nl = al_.size() ;
  275. for(unsigned int i=0; i<nl; i++) {
  276. norm += al_[i] * al_[i] ;
  277. }
  278. norm = sqrt(norm) ;
  279. CGAL_assertion( fabs(norm)>1e-40 );
  280. scale_row(weight / norm) ;
  281. }
  282. void scale_row(CoeffType s) {
  283. check_state(IN_ROW) ;
  284. unsigned int nf = af_.size() ;
  285. for(unsigned int i=0; i<nf; i++) {
  286. af_[i] *= s ;
  287. }
  288. unsigned int nl = al_.size() ;
  289. for(unsigned int i=0; i<nl; i++) {
  290. al_[i] *= s ;
  291. }
  292. bk_ *= s ;
  293. }
  294. void end_row() {
  295. if(least_squares_) {
  296. std::size_t nf = af_.size() ;
  297. std::size_t nl = al_.size() ;
  298. for(std::size_t i=0; i<nf; i++) {
  299. for(std::size_t j=0; j<nf; j++) {
  300. A_->add_coef(if_[i], if_[j], af_[i] * af_[j]) ;
  301. }
  302. }
  303. CoeffType S = - bk_ ;
  304. for(std::size_t j=0; j<nl; j++) {
  305. S += al_[j] * xl_[j] ;
  306. }
  307. for(std::size_t i=0; i<nf; i++) {
  308. (*b_)[if_[i]] -= af_[i] * S ;
  309. }
  310. } else {
  311. std::size_t nf = af_.size() ;
  312. std::size_t nl = al_.size() ;
  313. for(std::size_t i=0; i<nf; i++) {
  314. A_->add_coef(current_row_, if_[i], af_[i]) ;
  315. }
  316. (*b_)[current_row_] = bk_ ;
  317. for(std::size_t i=0; i<nl; i++) {
  318. (*b_)[current_row_] -= al_[i] * xl_[i] ;
  319. }
  320. }
  321. current_row_++ ;
  322. transition(IN_ROW, IN_SYSTEM) ;
  323. }
  324. void end_system() {
  325. transition(IN_SYSTEM, CONSTRUCTED) ;
  326. }
  327. // ----------------------------- Solver -------------------------------
  328. // Solves a linear system or minimizes a quadratic form.
  329. // Return true on success.
  330. // (modified for SparseLinearAlgebraTraits_d concept)
  331. bool solve()
  332. {
  333. check_state(CONSTRUCTED) ;
  334. // Solve the sparse linear system "A*X = B". On success, the solution is (1/D) * X.
  335. Traits solver_traits;
  336. CoeffType D;
  337. bool success = solver_traits.linear_solver(*A_, *b_, *x_, D) ;
  338. CGAL_assertion(D == 1.0); // WARNING: this library does not support homogeneous coordinates!
  339. vector_to_variables() ;
  340. transition(CONSTRUCTED, SOLVED) ;
  341. delete A_ ; A_ = NULL ;
  342. delete b_ ; b_ = NULL ;
  343. delete x_ ; x_ = NULL ;
  344. return success;
  345. }
  346. protected:
  347. // ----------- Converting between user representation and the internal representation -----
  348. void vector_to_variables() {
  349. for(int ii=0; ii < nb_variables(); ii++) {
  350. Variable& v = variable(ii) ;
  351. if(!v.is_locked()) {
  352. v.set_value( (*x_)[v.index()] ) ;
  353. }
  354. }
  355. }
  356. void variables_to_vector() {
  357. for(int ii=0; ii < nb_variables(); ii++) {
  358. Variable& v = variable(ii) ;
  359. if(!v.is_locked()) {
  360. (*x_)[v.index()] = v.value() ;
  361. }
  362. }
  363. }
  364. // ----------- Finite state automaton (checks that calling sequence is respected) ---------
  365. std::string state_to_string(State s) {
  366. switch(s) {
  367. case INITIAL:
  368. return "initial" ;
  369. case IN_SYSTEM:
  370. return "in system" ;
  371. case IN_ROW:
  372. return "in row" ;
  373. case CONSTRUCTED:
  374. return "constructed" ;
  375. case SOLVED:
  376. return "solved" ;
  377. }
  378. // Should not go there.
  379. CGAL_error();
  380. return "undefined" ;
  381. }
  382. void check_state(State s) {
  383. CGAL_USE(s);
  384. CGAL_assertion(state_ == s) ;
  385. }
  386. void transition(State from, State to) {
  387. check_state(from) ;
  388. state_ = to ;
  389. }
  390. private:
  391. // --------------- parameters --------------------------
  392. bool least_squares_ ;
  393. // --------------- user representation --------------
  394. unsigned int nb_variables_ ;
  395. Variable* variable_ ;
  396. // --------------- construction -----------------------
  397. State state_ ;
  398. unsigned int current_row_ ;
  399. std::vector<CoeffType> af_ ;
  400. std::vector<unsigned int> if_ ;
  401. std::vector<CoeffType> al_ ;
  402. std::vector<CoeffType> xl_ ;
  403. double bk_ ;
  404. // --------------- internal representation ---------
  405. Matrix* A_ ;
  406. Vector* x_ ;
  407. Vector* b_ ;
  408. } ;
  409. } // namespace OpenNL
  410. #endif