Blender V5.0
ConstrainedConjugateGradient.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
10
11#include <Eigen/Core>
12#include <Eigen/IterativeLinearSolvers>
13#include <Eigen/Sparse>
14
15namespace Eigen {
16
17namespace internal {
18
31template<typename MatrixType,
32 typename Rhs,
33 typename Dest,
34 typename FilterMatrixType,
35 typename Preconditioner>
36EIGEN_DONT_INLINE void constrained_conjugate_gradient(const MatrixType &mat,
37 const Rhs &rhs,
38 Dest &x,
39 const FilterMatrixType &filter,
40 const Preconditioner &precond,
41 int &iters,
42 typename Dest::RealScalar &tol_error)
43{
44 using std::abs;
45 using std::sqrt;
46 using RealScalar = typename Dest::RealScalar;
47 using Scalar = typename Dest::Scalar;
48 using VectorType = Matrix<Scalar, Dynamic, 1>;
49
50 RealScalar tol = tol_error;
51 int maxIters = iters;
52
53 int n = mat.cols();
54
55 VectorType residual = filter * (rhs - mat * x); /* initial residual */
56
57 RealScalar rhsNorm2 = (filter * rhs).squaredNorm();
58 if (rhsNorm2 == 0) {
59 /* XXX TODO: set constrained result here. */
60 x.setZero();
61 iters = 0;
62 tol_error = 0;
63 return;
64 }
65 RealScalar threshold = tol * tol * rhsNorm2;
66 RealScalar residualNorm2 = residual.squaredNorm();
67 if (residualNorm2 < threshold) {
68 iters = 0;
69 tol_error = sqrt(residualNorm2 / rhsNorm2);
70 return;
71 }
72
73 VectorType p(n);
74 p = filter * precond.solve(residual); /* initial search direction */
75
76 VectorType z(n), tmp(n);
77 RealScalar absNew = numext::real(
78 residual.dot(p)); /* The square of the absolute value of `r` scaled by `invM`. */
79 int i = 0;
80 while (i < maxIters) {
81 tmp.noalias() = filter * (mat * p); /* The bottleneck of the algorithm. */
82
83 Scalar alpha = absNew / p.dot(tmp); /* The amount we travel on direction. */
84 x += alpha * p; /* Update solution. */
85 residual -= alpha * tmp; /* Update residue. */
86
87 residualNorm2 = residual.squaredNorm();
88 if (residualNorm2 < threshold) {
89 break;
90 }
91
92 z = precond.solve(residual); /* Approximately solve for `A z = residual`. */
93
94 RealScalar absOld = absNew;
95 absNew = numext::real(residual.dot(z)); /* Update the absolute value of `r`. */
96
97 /* Calculate the Gram-Schmidt value used to create the new search direction. */
98 RealScalar beta = absNew / absOld;
99
100 p = filter * (z + beta * p); /* Update search direction. */
101 i++;
102 }
103 tol_error = sqrt(residualNorm2 / rhsNorm2);
104 iters = i;
105}
106
107} // namespace internal
108
109#if 0 /* unused */
110template<typename MatrixType> struct MatrixFilter {
111 MatrixFilter() : m_cmat(NULL) {}
112
113 MatrixFilter(const MatrixType &cmat) : m_cmat(&cmat) {}
114
115 void setMatrix(const MatrixType &cmat)
116 {
117 m_cmat = &cmat;
118 }
119
120 template<typename VectorType> void apply(VectorType v) const
121 {
122 v = (*m_cmat) * v;
123 }
124
125 protected:
126 const MatrixType *m_cmat;
127};
128#endif
129
130template<typename _MatrixType,
131 int _UpLo = Lower,
132 typename _FilterMatrixType = _MatrixType,
133 typename _Preconditioner = DiagonalPreconditioner<typename _MatrixType::Scalar>>
135
136namespace internal {
137
138template<typename _MatrixType, int _UpLo, typename _FilterMatrixType, typename _Preconditioner>
139struct traits<
140 ConstrainedConjugateGradient<_MatrixType, _UpLo, _FilterMatrixType, _Preconditioner>> {
141 using MatrixType = _MatrixType;
142 using FilterMatrixType = _FilterMatrixType;
143 using Preconditioner = _Preconditioner;
144};
145
146} // namespace internal
147
197template<typename _MatrixType, int _UpLo, typename _FilterMatrixType, typename _Preconditioner>
199 : public IterativeSolverBase<
200 ConstrainedConjugateGradient<_MatrixType, _UpLo, _FilterMatrixType, _Preconditioner>> {
201 using Base = IterativeSolverBase<ConstrainedConjugateGradient>;
202 using Base::m_error;
203 using Base::m_info;
204 using Base::m_isInitialized;
205 using Base::m_iterations;
206 using Base::mp_matrix;
207
208 public:
209 using MatrixType = _MatrixType;
210 using Scalar = typename MatrixType::Scalar;
211 using Index = typename MatrixType::Index;
212 using RealScalar = typename MatrixType::RealScalar;
213 using FilterMatrixType = _FilterMatrixType;
214 using Preconditioner = _Preconditioner;
215
216 enum { UpLo = _UpLo };
217
220
233
235
237 {
238 return m_filter;
239 }
241 {
242 return m_filter;
243 }
244
251 template<typename Rhs, typename Guess>
252 internal::solve_retval_with_guess<ConstrainedConjugateGradient, Rhs, Guess> solveWithGuess(
253 const MatrixBase<Rhs> &b, const Guess &x0) const
254 {
255 eigen_assert(m_isInitialized && "ConjugateGradient is not initialized.");
256 eigen_assert(
257 Base::rows() == b.rows() &&
258 "ConjugateGradient::solve(): invalid number of rows of the right hand side matrix b");
259 return internal::solve_retval_with_guess<ConstrainedConjugateGradient, Rhs, Guess>(
260 *this, b.derived(), x0);
261 }
262
264 template<typename Rhs, typename Dest> void _solveWithGuess(const Rhs &b, Dest &x) const
265 {
266 m_iterations = Base::maxIterations();
267 m_error = Base::m_tolerance;
268
269 for (int j = 0; j < b.cols(); j++) {
270 m_iterations = Base::maxIterations();
271 m_error = Base::m_tolerance;
272
273 typename Dest::ColXpr xj(x, j);
274 internal::constrained_conjugate_gradient(mp_matrix->template selfadjointView<UpLo>(),
275 b.col(j),
276 xj,
277 m_filter,
278 Base::m_preconditioner,
279 m_iterations,
280 m_error);
281 }
282
283 m_isInitialized = true;
284 m_info = m_error <= Base::m_tolerance ? Success : NoConvergence;
285 }
286
288 template<typename Rhs, typename Dest> void _solve(const Rhs &b, Dest &x) const
289 {
290 x.setOnes();
292 }
293
294 protected:
296};
297
298namespace internal {
299
300template<typename _MatrixType, int _UpLo, typename _Filter, typename _Preconditioner, typename Rhs>
301struct solve_retval<ConstrainedConjugateGradient<_MatrixType, _UpLo, _Filter, _Preconditioner>,
302 Rhs>
303 : solve_retval_base<ConstrainedConjugateGradient<_MatrixType, _UpLo, _Filter, _Preconditioner>,
304 Rhs> {
306 EIGEN_MAKE_SOLVE_HELPERS(Dec, Rhs)
307
308 template<typename Dest> void evalTo(Dest &dst) const
309 {
310 dec()._solve(rhs(), dst);
311 }
312};
313
314} // end namespace internal
315
316} // end namespace Eigen
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define A
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
A conjugate gradient solver for sparse self-adjoint problems with additional constraints.
internal::solve_retval_with_guess< ConstrainedConjugateGradient, Rhs, Guess > solveWithGuess(const MatrixBase< Rhs > &b, const Guess &x0) const
void _solveWithGuess(const Rhs &b, Dest &x) const
float Scalar
Definition eigen_utils.h:26
#define filter
#define sqrt
ccl_device_inline float beta(const float x, const float y)
Definition math_base.h:661
EIGEN_DONT_INLINE void constrained_conjugate_gradient(const MatrixType &mat, const Rhs &rhs, Dest &x, const FilterMatrixType &filter, const Preconditioner &precond, int &iters, typename Dest::RealScalar &tol_error)
void apply(bContext &C, GestureData &gesture_data, wmOperator &op)
i
Definition text_draw.cc:230