11#ifndef PBAT_MATH_MOMENTFITTING_H
12#define PBAT_MATH_MOMENTFITTING_H
25#include <tbb/parallel_for.h>
27#include <unsupported/Eigen/NNLS>
39template <
int Dims,
int Order>
42 static auto constexpr kOrder = Order;
43 static auto constexpr kDims = Dims;
60template <polynomial::CBasis TBasis, CFixedPo
intPolynomialQuadratureRule TQuad>
64 TBasis::kDims == TQuad::kDims,
65 "Dimensions of the quadrature rule and the polynomial basis must match, i.e. a k-D "
66 "polynomial must be fit in a k-D integration domain.");
68 auto Xg =
common::ToEigen(Q.points).reshaped(TQuad::kDims + 1, TQuad::kPoints);
70 for (
auto g = 0u; g < TQuad::kPoints; ++g)
71 P.col(g) = Pb.eval(Xg.col(g).template segment<TQuad::kDims>(1));
84template <polynomial::CBasis TBasis, CPolynomialQuadratureRule TQuad>
88 TBasis::kDims == TQuad::kDims,
89 "Dimensions of the quadrature rule and the polynomial basis must match, i.e. a k-D "
90 "polynomial must be fit in a k-D integration domain.");
92 auto Xg =
common::ToEigen(Q.points).reshaped(TQuad::kDims + 1, Q.weights.size());
93 for (
auto g = 0u; g < Xg.cols(); ++g)
94 P.col(g) = Pb.eval(Xg.col(g).template segment<TQuad::kDims>(1));
107template <polynomial::CBasis TBasis,
class TDerivedXg>
113 TBasis::kDims == QuadratureType::kDims,
114 "Dimensions of the quadrature rule and the polynomial basis must match, i.e. a k-D "
115 "polynomial must be fit in a k-D integration domain.");
117 for (
auto g = 0u; g < Xg.cols(); ++g)
118 P.col(g) = Pb.eval(Xg.col(g));
133template <
class TDerivedP,
class TDerivedB>
135 Eigen::MatrixBase<TDerivedP>
const& P,
136 Eigen::DenseBase<TDerivedB>
const& b,
137 Index maxIterations = 10,
138 Scalar precision = std::numeric_limits<Scalar>::epsilon())
140 using MatrixType = TDerivedP;
141 Eigen::NNLS<MatrixType> nnls{};
142 nnls.setMaxIterations(maxIterations);
143 nnls.setTolerance(precision);
144 nnls.compute(P.derived());
145 auto w = nnls.solve(b);
146 if (nnls.info() != Eigen::ComputationInfo::Success)
148 std::string what =
"Moment fitting's non-negative least-squares failed with error: ";
149 if (nnls.info() == Eigen::ComputationInfo::InvalidInput)
150 what +=
"InvalidInput";
151 if (nnls.info() == Eigen::ComputationInfo::NoConvergence)
152 what +=
"NoConvergence";
153 if (nnls.info() == Eigen::ComputationInfo::NumericalIssue)
154 what +=
"NumericalIssue";
155 throw std::invalid_argument(what);
171template <polynomial::CBasis Polynomial,
class TDerivedXg,
class TDerivedWg>
174 Eigen::MatrixBase<TDerivedXg>
const& Xg,
175 Eigen::DenseBase<TDerivedWg>
const& wg)
179 for (
auto g = 0; g < wg.size(); ++g)
180 b += wg(g) * P.eval(Xg.col(g));
203template <polynomial::CBasis Polynomial,
class TDerivedXg1,
class TDerivedXg2,
class TDerivedWg2>
206 Eigen::MatrixBase<TDerivedXg1>
const& Xg1,
207 Eigen::MatrixBase<TDerivedXg2>
const& Xg2,
208 Eigen::DenseBase<TDerivedWg2>
const& wg2,
209 Index maxIterations = 10,
210 Scalar precision = std::numeric_limits<Scalar>::epsilon())
254 Eigen::DenseBase<TDerivedS1>
const& S1,
255 Eigen::MatrixBase<TDerivedXi1>
const& Xi1,
256 Eigen::DenseBase<TDerivedS2>
const& S2,
257 Eigen::MatrixBase<TDerivedXi2>
const& Xi2,
258 Eigen::DenseBase<TDerivedWg2>
const& wi2,
259 Index nSimplices = -1,
260 bool bEvaluateError =
false,
261 Index maxIterations = 10,
262 Scalar precision = std::numeric_limits<Scalar>::epsilon())
270 nSimplices = std::max(
271 *std::max_element(S1.begin(), S1.end()),
272 *std::max_element(S2.begin(), S2.end())) +
274 IndexVectorX S1P = CumSum(Counts(S1.begin(), S1.end(), nSimplices));
275 IndexVectorX S2P = CumSum(Counts(S2.begin(), S2.end(), nSimplices));
276 IndexVectorX S1N = ArgSort<Index>(S1.size(), [&](
auto si,
auto sj) { return S1(si) < S1(sj); });
277 IndexVectorX S2N = ArgSort<Index>(S2.size(), [&](
auto si,
auto sj) { return S2(si) < S2(sj); });
279 auto fSolveWeights = [maxIterations,
281 bEvaluateError](
auto const& Xg1,
auto const& Xg2,
auto const& wg2) {
291 error = (b1 - b2).squaredNorm();
293 return std::make_pair(w, error);
304 error = (b1 - b2).squaredNorm();
306 return std::make_pair(w, error);
317 error = (b1 - b2).squaredNorm();
319 return std::make_pair(w, error);
321 throw std::invalid_argument(
322 "Expected quadrature points in reference simplex space of dimensions (i.e. rows) 1,2 "
326 VectorX error = VectorX::Zero(nSimplices);
327 VectorX wi1 = VectorX::Zero(Xi1.cols());
328 tbb::parallel_for(
Index(0), nSimplices, [&](
Index s) {
329 auto S1begin = S1P(s);
330 auto S1end = S1P(s + 1);
333 auto s1inds = S1N(Eigen::seq(S1begin, S1end - 1));
334 MatrixX Xg1 = Xi1(Eigen::placeholders::all, s1inds);
335 auto S2begin = S2P(s);
336 auto S2end = S2P(s + 1);
337 auto s2inds = S2N(Eigen::seq(S2begin, S2end - 1));
338 MatrixX Xg2 = Xi2(Eigen::placeholders::all, s2inds);
340 auto [wg1, err] = fSolveWeights(Xg1, Xg2, wg2);
384 Eigen::DenseBase<TDerivedS1>
const& S1,
385 Eigen::MatrixBase<TDerivedX1>
const& X1,
386 Eigen::DenseBase<TDerivedS2>
const& S2,
387 Eigen::MatrixBase<TDerivedX2>
const& X2,
388 Eigen::DenseBase<TDerivedW2>
const& w2,
397 nSimplices = std::max(
398 *std::max_element(S1.begin(), S1.end()),
399 *std::max_element(S2.begin(), S2.end())) +
401 IndexVectorX S1P = CumSum(Counts<Index>(S1.begin(), S1.end(), nSimplices));
402 IndexVectorX S2P = CumSum(Counts<Index>(S2.begin(), S2.end(), nSimplices));
403 IndexVectorX S1N = ArgSort<Index>(S1.size(), [&](
auto si,
auto sj) { return S1(si) < S1(sj); });
404 IndexVectorX S2N = ArgSort<Index>(S2.size(), [&](
auto si,
auto sj) { return S2(si) < S2(sj); });
406 auto fPolyRows = [](
MatrixX const& Xg) {
413 throw std::invalid_argument(
414 "Expected quadrature points in reference simplex space of dimensions (i.e. rows) 1,2 "
417 auto fAssembleSystem =
418 [](
auto const& Xg1,
auto const& Xg2,
auto const& wg2) -> std::pair<MatrixX, VectorX> {
440 throw std::invalid_argument(
441 "Expected quadrature points in reference simplex space of dimensions (i.e. rows) 1,2 "
444 auto nrows = fPolyRows(X1);
448 for (
Index s = 0; s < nSimplices; ++s)
449 if (S1P(s + 1) > S1P(s))
453 for (
Index s = 0, sy = 0; s < nSimplices; ++s)
455 if (S1P(s + 1) > S1P(s))
457 nQuads(sy++) = S1P(s + 1) - S1P(s);
462 MatrixX P(nrows, prefix(Eigen::placeholders::last));
465 for (
Index s = 0, sy = 0; s < nSimplices; ++s)
467 auto S1begin = S1P(s);
468 auto S1end = S1P(s + 1);
471 auto s1inds = S1N(Eigen::seq(S1begin, S1end - 1));
472 MatrixX Xg1 = X1(Eigen::placeholders::all, s1inds);
473 auto S2begin = S2P(s);
474 auto S2end = S2P(s + 1);
475 auto s2inds = S2N(Eigen::seq(S2begin, S2end - 1));
476 MatrixX Xg2 = X2(Eigen::placeholders::all, s2inds);
478 auto [Ps, bs] = fAssembleSystem(Xg1, Xg2, wg2);
479 P.block(0, prefix(sy), nrows, nQuads(sy)) = Ps;
484 return std::make_tuple(P, B, prefix);
500template <
class TDerivedM,
class TDerivedP>
502 Eigen::MatrixBase<TDerivedM>
const& M,
503 Eigen::DenseBase<TDerivedP>
const& P)
505 auto const nblocks = P.size() - 1;
506 auto const nblockrows = M.rows();
507 auto const nrows = nblockrows * nblocks;
508 auto const ncols = P(Eigen::placeholders::last);
511 for (
auto b = 0; b < nblocks; ++b)
515 auto const nblockcols = end - begin;
516 auto const offset = b * nblockrows;
517 for (
auto i = 0; i < nblockrows; ++i)
518 reserves(offset + i) = nblockcols;
520 GM.reserve(reserves);
521 for (
auto b = 0; b < nblocks; ++b)
525 auto const nblockcols = end - begin;
526 auto Mb = M.block(0, begin, nblockrows, nblockcols);
527 auto const roffset = b * nblockrows;
528 auto const coffset = begin;
529 for (
auto i = 0; i < nblockrows; ++i)
531 for (
auto j = 0; j < nblockcols; ++j)
533 GM.insert(roffset + i, coffset + j) = Mb(i, j);
Basis polynomials in dimensions and orders .
Eigen adaptors for ranges.
This file contains the concepts used in the math module.
Concepts for polynomial basis.
auto Counts(auto begin, auto end, TIndex ncounts) -> Eigen::Vector< TIndex, Eigen::Dynamic >
Counts the number of occurrences of each integer in a contiguous range.
Definition Indexing.h:57
auto CumSum(R &&sizes) -> Eigen::Vector< TIndex, Eigen::Dynamic >
Cumulative sum of a range of integers.
Definition Indexing.h:34
auto ArgSort(TIndex n, FLess less) -> Eigen::Vector< TIndex, Eigen::Dynamic >
Computes the indices that would sort an array.
Definition ArgSort.h:32
auto ToEigen(R &&r) -> Eigen::Map< Eigen::Vector< std::ranges::range_value_t< R >, Eigen::Dynamic > const >
Map a range of scalars to an eigen vector of such scalars.
Definition Eigen.h:28
Math related functionality.
Definition Concepts.h:19
Vector< Polynomial::kSize > Integrate(Polynomial const &P, Eigen::MatrixBase< TDerivedXg > const &Xg, Eigen::DenseBase< TDerivedWg > const &wg)
Computes given an existing quadrature rule .
Definition MomentFitting.h:172
CSRMatrix BlockDiagonalReferenceMomentFittingSystem(Eigen::MatrixBase< TDerivedM > const &M, Eigen::DenseBase< TDerivedP > const &P)
Block diagonalizes the given reference moment fitting systems (see ReferenceMomentFittingSystems()) i...
Definition MomentFitting.h:501
VectorX MomentFittedWeights(Eigen::MatrixBase< TDerivedP > const &P, Eigen::DenseBase< TDerivedB > const &b, Index maxIterations=10, Scalar precision=std::numeric_limits< Scalar >::epsilon())
Computes non-negative quadrature weights by moment fitting.
Definition MomentFitting.h:134
Vector< TDerivedXg1::ColsAtCompileTime > TransferQuadrature(Polynomial const &P, Eigen::MatrixBase< TDerivedXg1 > const &Xg1, Eigen::MatrixBase< TDerivedXg2 > const &Xg2, Eigen::DenseBase< TDerivedWg2 > const &wg2, Index maxIterations=10, Scalar precision=std::numeric_limits< Scalar >::epsilon())
Obtain weights by transferring an existing quadrature rule defined on a simplex onto a new quadrat...
Definition MomentFitting.h:204
std::tuple< MatrixX, MatrixX, IndexVectorX > ReferenceMomentFittingSystems(Eigen::DenseBase< TDerivedS1 > const &S1, Eigen::MatrixBase< TDerivedX1 > const &X1, Eigen::DenseBase< TDerivedS2 > const &S2, Eigen::MatrixBase< TDerivedX2 > const &X2, Eigen::DenseBase< TDerivedW2 > const &w2, Index nSimplices=Index(-1))
Computes reference moment fitting systems for all simplices , given an existing quadrature rule defi...
Definition MomentFitting.h:383
Matrix< TBasis::kSize, TQuad::kPoints > ReferenceMomentFittingMatrix(TBasis const &Pb, TQuad const &Q)
Compute the moment fitting matrix in the reference simplex space.
Definition MomentFitting.h:61
The main namespace of the library.
Definition Aliases.h:15
Eigen::Vector< Index, Eigen::Dynamic > IndexVectorX
Dynamic-size index vector type.
Definition Aliases.h:49
Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic-size matrix type.
Definition Aliases.h:34
Eigen::Vector< Scalar, N > Vector
Fixed-size vector type.
Definition Aliases.h:24
Eigen::Vector< Scalar, Eigen::Dynamic > VectorX
Dynamic-size vector type.
Definition Aliases.h:33
std::ptrdiff_t Index
Index type.
Definition Aliases.h:17
double Scalar
Scalar type.
Definition Aliases.h:18
Eigen::SparseMatrix< Scalar, Eigen::RowMajor > CSRMatrix
Row-major sparse matrix type.
Definition Aliases.h:53
Eigen::Matrix< Scalar, Rows, Cols > Matrix
Fixed-size matrix type.
Definition Aliases.h:31
Quadrature rule with variable points and weights.
Definition MomentFitting.h:41
MatrixX points
Definition MomentFitting.h:45
static auto constexpr kDims
Spatial dimensions.
Definition MomentFitting.h:43
VectorX weights
Definition MomentFitting.h:47
static auto constexpr kOrder
Polynomial order.
Definition MomentFitting.h:42
Orthonormal polynomial basis in dimensions and order .
Definition Basis.h:126
static constexpr int kSize
Number of basis functions.
Definition Basis.h:131