linsolve_with_fixed.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 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. #ifndef IGL_LINSOLVE_WITH_FIXED_H
  9. #define IGL_LINSOLVE_WITH_FIXED_H
  10. #include "igl_inline.h"
  11. #define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
  12. #include <Eigen/Core>
  13. #include <Eigen/Dense>
  14. #include <Eigen/Sparse>
  15. #include <Eigen/SparseExtra>
  16. // Bug in unsupported/Eigen/SparseExtra needs iostream first
  17. #include <iostream>
  18. #include <unsupported/Eigen/SparseExtra>
  19. namespace igl
  20. {
  21. // LINSOLVE_WITH_FIXED Solves a sparse linear system Ax=b with
  22. // fixed known values in x
  23. // Templates:
  24. // T should be a eigen matrix primitive type like float or double
  25. // Inputs:
  26. // A m by n sparse matrix
  27. // b n by k dense matrix, k is bigger than 1 for multiple right handsides
  28. // known list of indices to known rows in x (must be sorted in ascending order)
  29. // Y list of fixed values corresponding to known rows in Z
  30. // Outputs:
  31. // x n by k dense matrix containing the solution
  32. template<typename T, typename Derived>
  33. inline void SolveLinearSystemWithBoundaryConditions(const SparseMatrix<T>& A, const MatrixBase<Derived>& b, const vector<int>& known, MatrixBase<Derived>& x)
  34. {
  35. const int rows = x.rows();
  36. const int cols = x.cols();
  37. SparseMatrix<T> AP(rows,rows);
  38. const int knownCount = known.size();
  39. const int unknownCount = rows - knownCount;
  40. int knownIndex = 0;
  41. int unknownIndex = 0;
  42. if(knownCount >= rows)
  43. {
  44. std::cerr << "No unknowns to solve for!\n";
  45. return;
  46. }
  47. // Permutate to sort by known boundary conditions -> [A1,A2] * [x1;x2]
  48. VectorXi transpositions;
  49. transpositions.resize(rows);
  50. for(int n=0;n<rows;n++)
  51. {
  52. if(knownIndex < known.size() && n == known[knownIndex])
  53. {
  54. transpositions[unknownCount + knownIndex] = n;
  55. knownIndex++;
  56. }
  57. else
  58. {
  59. transpositions[unknownIndex] = n;
  60. unknownIndex++;
  61. }
  62. }
  63. PermutationMatrix<Dynamic,Dynamic,int> P(transpositions);
  64. PermutationMatrix<Dynamic,Dynamic,int> PInv = P.inverse();
  65. A.twistedBy(PInv).evalTo(AP);
  66. // Split in kown and unknown parts A1,A2,x2,b1
  67. SparseMatrix<T> A1, A2;
  68. internal::plain_matrix_type<Derived>::type x1, x2, b1;
  69. x2 = (PInv*x).block(unknownCount,0,knownCount,cols);
  70. b1 = (PInv*b).block(0,0,unknownCount,cols);
  71. SparseMatrix<T> A1Temp(rows,unknownCount);
  72. SparseMatrix<T> A2Temp(rows,knownCount);
  73. A1Temp = AP.innerVectors(0,unknownCount).transpose();
  74. A2Temp = AP.innerVectors(unknownCount,knownCount).transpose();
  75. A1 = A1Temp.innerVectors(0,unknownCount).transpose();
  76. A2 = A2Temp.innerVectors(0,unknownCount).transpose();
  77. // Solve A1*x1 = b - A2*x2
  78. SparseLU<SparseMatrix<T>> solver;
  79. solver.compute(A1);
  80. if (solver.info() != Eigen::Success)
  81. {
  82. std::cerr << "Matrix can not be decomposed.\n";
  83. return;
  84. }
  85. internal::plain_matrix_type<Derived>::type t = b1-A2*x2;
  86. x1 = solver.solve(t);
  87. if (solver.info() != Eigen::Success)
  88. {
  89. std::cerr << "Solving failed.\n";
  90. return;
  91. }
  92. // Compose resulting x
  93. x.block(0,0,unknownCount,cols) = x1;
  94. x.block(unknownCount,0,knownCount,cols) = x2;
  95. x = P * x;
  96. };
  97. }