Bertini 2 d882924 (2026-10-06 19:56 UTC)
Numerical algebraic geometry library (C++ core)
Loading...
Searching...
No Matches
lu_solver.hpp
Go to the documentation of this file.
1//This file is part of Bertini 2.
2//
3//bertini2/linalg/lu_solver.hpp is free software: you can redistribute it and/or modify
4//it under the terms of the GNU General Public License as published by
5//the Free Software Foundation, either version 3 of the License, or
6//(at your option) any later version.
7//
8//bertini2/linalg/lu_solver.hpp is distributed in the hope that it will be useful,
9//but WITHOUT ANY WARRANTY; without even the implied warranty of
10//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11//GNU General Public License for more details.
12//
13//You should have received a copy of the GNU General Public License
14//along with bertini2/linalg/lu_solver.hpp. If not, see <http://www.gnu.org/licenses/>.
15//
16// silviana amethyst, university of wisconsin-eau claire
17
35
36#ifndef BERTINI_LINALG_LU_SOLVER_HPP
37#define BERTINI_LINALG_LU_SOLVER_HPP
38
40
41namespace bertini {
42namespace linalg {
43
56template<typename NumT>
58{
59 using RealT = typename Eigen::NumTraits<NumT>::Real;
60 static constexpr bool is_mp = !std::is_same<NumT, complex_dbl>::value;
61
62public:
65 void ChangeSize(unsigned n)
66 {
67 n_ = n;
68 lu_.resize(n, n); // new mp elements come up at the thread default precision
69 piv_.resize(n);
70 y_.resize(n);
71 if (is_mp && precision_ != 0) // re-establish a previously-set precision on the new storage
72 ApplyPrecision();
73 }
74
77 void ChangePrecision(unsigned prec)
78 {
79 precision_ = prec;
80 if (is_mp)
81 ApplyPrecision();
82 }
83
85 unsigned precision() const { return precision_; }
86
91 {
92 lu_ = A; // one copy into reusable workspace (A must survive)
93 return FactorInPlace();
94 }
95
100 {
101 lu_.swap(A); // steal A's storage; A is left holding our old workspace
102 auto code = FactorInPlace();
103 return code;
104 }
105
110 template<typename OutDerived>
111 void Solve(Vec<NumT> const& b, Eigen::MatrixBase<OutDerived> const& x_out) const
112 {
113 // Eigen idiom for a write-to output that may be a temporary Block (e.g. K.col(stage)).
114 Eigen::MatrixBase<OutDerived>& x = const_cast<Eigen::MatrixBase<OutDerived>&>(x_out);
115
116 // y_ = P b : copy then replay the row swaps recorded during factorization.
117 y_ = b;
118 for (unsigned k = 0; k < n_; ++k)
119 if (piv_[k] != k)
120 std::swap(y_[k], y_[piv_[k]]);
121
122 // forward substitution: L y = P b, L unit lower-triangular (implicit unit diagonal).
123 for (unsigned i = 1; i < n_; ++i)
124 for (unsigned j = 0; j < i; ++j)
125 {
126 t_ = lu_(i, j);
127 t_ *= y_[j];
128 y_[i] -= t_; // y_[i] -= lu_(i,j) * y_[j]
129 }
130
131 // back substitution: U x = y, U upper-triangular.
132 for (unsigned ii = n_; ii-- > 0; )
133 {
134 for (unsigned j = ii + 1; j < n_; ++j)
135 {
136 t_ = lu_(ii, j);
137 t_ *= x(j);
138 y_[ii] -= t_; // y_[ii] -= lu_(ii,j) * x(j)
139 }
140 x(ii) = y_[ii];
141 x(ii) /= lu_(ii, ii);
142 }
143 }
144
147 Mat<NumT> const& Factors() const { return lu_; }
148
149private:
151 MatrixSuccessCode FactorInPlace()
152 {
153 for (unsigned k = 0; k < n_; ++k)
154 {
155 // partial pivot: pick the row p >= k with the largest |lu_(p,k)|.
156 unsigned p = k;
157 amax_ = abs(lu_(k, k));
158 for (unsigned i = k + 1; i < n_; ++i)
159 {
160 acur_ = abs(lu_(i, k));
161 if (acur_ > amax_) { amax_ = acur_; p = i; }
162 }
163 piv_[k] = p;
164 if (p != k)
165 lu_.row(k).swap(lu_.row(p));
166
167 // scale the sub-column below the pivot by the reciprocal of the pivot -- one (costly)
168 // mpc division per column instead of one per sub-row, then cheap multiplies. Pin recip_
169 // to the pivot's own precision first: during AMP the working precision changes, and a
170 // reciprocal left at a stale precision would contaminate the factorization (and, through
171 // the solution, trip the endgame's uniform-precision checks).
172 if constexpr (is_mp)
173 Precision(recip_, Precision(lu_(k, k)));
174 recip_ = 1;
175 recip_ /= lu_(k, k); // recip_ = 1 / a_kk, at the pivot's precision
176 for (unsigned i = k + 1; i < n_; ++i)
177 lu_(i, k) *= recip_; // l_ik = a_ik * (1 / a_kk)
178
179 // rank-1 trailing-submatrix update, reusing t_ for every multiply-subtract so the
180 // whole O(N^3) sweep allocates nothing beyond the scratch scalar.
181 for (unsigned j = k + 1; j < n_; ++j)
182 for (unsigned i = k + 1; i < n_; ++i)
183 {
184 t_ = lu_(i, k);
185 t_ *= lu_(k, j);
186 lu_(i, j) -= t_; // lu_(i,j) -= lu_(i,k) * lu_(k,j)
187 }
188 }
190 }
191
193 void ApplyPrecision()
194 {
195 if constexpr (is_mp)
196 {
197 Precision(lu_, precision_);
198 Precision(y_, precision_);
199 Precision(t_, precision_);
200 Precision(recip_, precision_); // re-pinned per pivot in FactorInPlace, but keep it valid
201 Precision(amax_, precision_);
202 Precision(acur_, precision_);
203 }
204 }
205
206 unsigned n_ = 0;
207 unsigned precision_ = 0;
208 Mat<NumT> lu_;
209 std::vector<unsigned> piv_;
210 mutable Vec<NumT> y_;
211 mutable NumT t_;
212 NumT recip_;
213 RealT amax_;
214 RealT acur_;
215};
216
217} // namespace linalg
218} // namespace bertini
219
220#endif
Stateful partial-pivot LU factor/solve with preallocated, precision-adjustable banks.
Definition lu_solver.hpp:58
void ChangeSize(unsigned n)
(Re)size the workspace to hold n x n systems.
Definition lu_solver.hpp:65
MatrixSuccessCode FactorDestructive(Mat< NumT > &A)
Factor A destructively (no copy): on return A holds the L\U factors.
Definition lu_solver.hpp:99
MatrixSuccessCode Factor(Mat< NumT > const &A)
Factor a copy of A with partial pivoting; A is preserved.
Definition lu_solver.hpp:90
void ChangePrecision(unsigned prec)
Re-set the precision of every mp temporary bank (a no-op for complex_dbl).
Definition lu_solver.hpp:77
Mat< NumT > const & Factors() const
The factored matrix (L below the diagonal, U on and above), for the caller's LUPartialPivotDecomposit...
Definition lu_solver.hpp:147
unsigned precision() const
Get the current working precision (digits).
Definition lu_solver.hpp:85
void Solve(Vec< NumT > const &b, Eigen::MatrixBase< OutDerived > const &x_out) const
Solve A x = b using the stored factors.
Definition lu_solver.hpp:111
Bertini extensions of the Eigen linear algebra library.
Definition lu_solver.hpp:42
Definition algorithm_builder.hpp:36
MatrixSuccessCode
Outcome of a matrix-decomposition sanity check (e.g. LU pivot magnitude).
Definition eigen_extensions.hpp:464
Eigen::Matrix< NumT, Eigen::Dynamic, 1 > Vec
A dynamically-sized column vector of NumT.
Definition eigen_extensions.hpp:296
MatrixSuccessCode LUPartialPivotDecompositionSuccessful(Eigen::MatrixBase< Derived > const &LU)
Check the diagonal elements of an LU decomposition for small values and large ratios.
Definition eigen_extensions.hpp:480
Eigen::Matrix< NumT, Eigen::Dynamic, Eigen::Dynamic > Mat
A dynamically-sized matrix of NumT.
Definition eigen_extensions.hpp:298
unsigned Precision(Eigen::MatrixBase< Derived > const &v)
Get the precision of an Eigen object.
Definition eigen_extensions.hpp:339