iMSTK
Interactive Medical Simulation Toolkit
imstkProjectedGaussSeidelSolver.h
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #pragma once
8 
9 #include "imstkMath.h"
10 
11 namespace imstk
12 {
22 template<typename Scalar>
23 class ProjectedGaussSeidelSolver
24 {
25 public:
26  // Sets the vector to be used for the solve
27  //void setGuess(Matrix<Scalar, -1, 1>& g) { x = g; }
28  void setA(Eigen::SparseMatrix<Scalar>* A) { this->m_A = A; }
29 
33  void setMaxIterations(const unsigned int maxIterations) { this->m_maxIterations = maxIterations; }
34 
38  void setRelaxation(const Scalar relaxation) { this->m_relaxation = relaxation; }
39 
44  void setEpsilon(const Scalar epsilon) { this->m_epsilon = epsilon; }
45 
49  const double getEnergy() const { return m_conv; }
50 
51  Eigen::Matrix<Scalar, -1, 1>& solve(const Eigen::Matrix<Scalar, -1, 1>& b, const Eigen::Matrix<Scalar, -1, 2>& cu)
52  {
53  const Eigen::SparseMatrix<Scalar>& A = *m_A;
54 
55  // Allocate new results
56  m_x = Eigen::Matrix<Scalar, -1, 1>(b.rows());
57  m_x.setZero();
58 
59  m_conv = 0.0;
60 
61  // Naive implementation of PGS
62  // Consider graph coloring and TBB parallizing
63  Eigen::Matrix<Scalar, -1, 1> xOld;
64  for (unsigned int i = 0; i < m_maxIterations; i++)
65  {
66  xOld = m_x;
67  for (Eigen::Index r = 0; r < A.rows(); r++)
68  {
69  Scalar delta = 0.0;
70 
71  // Sum up rows (skip r)
72  for (Eigen::Index c = 0; c < r; c++)
73  {
74  delta += A.coeff(r, c) * m_x[c];
75  }
76  for (Eigen::Index c = r + 1; c < A.cols(); c++)
77  {
78  delta += A.coeff(r, c) * m_x[c];
79  }
80 
81  // PGS can't converge for non-diagonal elements so its assumed
82  // we have these
83  delta = (b[r] - delta) / A.coeff(r, r);
84  // Apply relaxation factor
85  m_x(r) += m_relaxation * (delta - m_x(r));
86  // Do projection *every iteration*
87  m_x(r) = std::min(cu(r, 1), std::max(cu(r, 0), m_x(r)));
88  }
89 
90  // Check convergence
91  m_conv = (m_x - xOld).norm();
92  //printf(" %d: %f\n", i, m_conv);
93  if (m_conv < m_epsilon)
94  {
95  //printf("Eps: %f\n", conv);
96  return m_x;
97  }
98  }
99 
100  //printf("Eps: %f\n", conv);
101  return m_x;
102  }
103 
104 private:
105  unsigned int m_maxIterations = 3;
106  Scalar m_relaxation = static_cast<Scalar>(0.1);
107  Scalar m_epsilon = 1.0e-4;
108  Scalar m_conv = 0.0;
109  Eigen::Matrix<Scalar, -1, 1> m_x;
110  Eigen::SparseMatrix<Scalar>* m_A = nullptr;
111 };
112 } // namespace imstk
Compound Geometry.
void setRelaxation(const Scalar relaxation)
Similar to step size can be used to avoid overshooting the solution.
void setMaxIterations(const unsigned int maxIterations)
Set the maximum number of iterations.
void setEpsilon(const Scalar epsilon)
Stops when energy=(x_i+1-x_i).norm() < epsilon, when the solution isn&#39;t changing anymore.
const double getEnergy() const
Energy is defined as energy=(x_i+1-x_i).norm()