26#ifndef EIGEN_STRUCTURED_VANDERMONDE_H
27#define EIGEN_STRUCTURED_VANDERMONDE_H
30#include "./InternalHeaderCheck.h"
34template <
typename Scalar_,
int Rows_ = Dynamic,
int Cols_ = Dynamic>
37template <
typename Scalar_>
42template <
typename Scalar_,
int Rows_,
int Cols_>
43struct traits<Vandermonde<Scalar_, Rows_, Cols_>> {
44 using Scalar = Scalar_;
45 using StorageKind = Dense;
46 using XprKind = MatrixXpr;
47 using StorageIndex = int;
48 static constexpr int RowsAtCompileTime = Rows_;
49 static constexpr int ColsAtCompileTime = Cols_;
50 static constexpr int MaxRowsAtCompileTime = Rows_;
51 static constexpr int MaxColsAtCompileTime = Cols_;
57 static constexpr int Flags = Rows_ == 1 && Cols_ != 1 ?
RowMajorBit : 0;
60template <
typename Scalar_,
int Rows_,
int Cols_>
61struct evaluator_traits<Vandermonde<Scalar_, Rows_, Cols_>> {
62 using Kind = IndexBased;
63 using Shape = StructuredShape;
69template <
typename Scalar_,
int Rows_,
int Cols_>
70struct evaluator<Vandermonde<Scalar_, Rows_, Cols_>> : evaluator_base<Vandermonde<Scalar_, Rows_, Cols_>> {
71 using XprType = Vandermonde<Scalar_, Rows_, Cols_>;
72 using Scalar = Scalar_;
73 static constexpr int CoeffReadCost = HugeCost;
74 static constexpr int Flags = traits<XprType>::Flags;
75 static constexpr int Alignment = 0;
77 EIGEN_DEVICE_FUNC
constexpr EIGEN_STRONG_INLINE
explicit evaluator(
const XprType& xpr) : m_xpr(xpr) {}
79 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col)
const {
return m_xpr.coeff(row, col); }
85template <
typename Scalar_,
int Rows_,
int Cols_>
86struct blas_traits<Vandermonde<Scalar_, Rows_, Cols_>> {
87 using XprType = Vandermonde<Scalar_, Rows_, Cols_>;
88 using Scalar = Scalar_;
89 using ExtractType =
const XprType&;
90 using ExtractType_ = XprType;
91 using DirectLinearAccessType = XprType;
92 static constexpr bool IsComplex = NumTraits<Scalar>::IsComplex;
93 static constexpr bool IsTransposed =
false;
94 static constexpr bool NeedToConjugate =
false;
95 static constexpr bool HasUsableDirectAccess =
false;
96 static constexpr bool HasScalarFactor =
false;
97 static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE ExtractType extract(
const XprType& x) {
return x; }
98 static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar extractScalarFactor(
const XprType&) {
return Scalar(1); }
101template <
typename Scalar_>
102struct traits<BjorckPereyra<Scalar_>> : traits<Matrix<Scalar_, Dynamic, Dynamic>> {
103 using XprKind = MatrixXpr;
104 using StorageKind = SolverStorage;
105 using StorageIndex = int;
106 using BaseTraits = traits<Matrix<Scalar_, Dynamic, Dynamic>>;
107 static constexpr int Flags = BaseTraits::Flags &
RowMajorBit;
108 static constexpr int CoeffReadCost = Dynamic;
157template <
typename Scalar_,
int Rows_,
int Cols_>
162 using Scalar = Scalar_;
164 using StorageIndex = int;
169 static constexpr int RowsAtCompileTime = Rows_;
170 static constexpr int ColsAtCompileTime = Cols_;
171 static constexpr int MaxRowsAtCompileTime = Rows_;
172 static constexpr int MaxColsAtCompileTime = Cols_;
173 static constexpr int SizeAtCompileTime = internal::size_at_compile_time(Rows_, Cols_);
174 static constexpr int MaxSizeAtCompileTime = SizeAtCompileTime;
175 static constexpr int Flags = internal::traits<Vandermonde>::Flags;
176 static constexpr bool IsRowMajor = (Flags &
RowMajorBit) != 0;
181 EIGEN_STATIC_ASSERT_NON_INTEGER(RealScalar)
182 EIGEN_MAKE_SCALAR_BINARY_OP_ONTHELEFT(
operator*, internal::scalar_product_op)
185 template <
typename Derived>
187 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
188 eigen_assert(m_x.size() > 0 && m_cols > 0 &&
"Vandermonde must be non-empty");
189 eigen_assert((Cols_ == Dynamic || Cols_ == cols) &&
"cols does not match the compile-time column count");
193 template <
typename Derived>
195 EIGEN_STATIC_ASSERT(Rows_ == Dynamic || Cols_ == Dynamic || Rows_ == Cols_, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)
197 Cols_ == Dynamic || Derived::SizeAtCompileTime == Dynamic || Cols_ == Derived::SizeAtCompileTime,
198 YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)
201 EIGEN_DEVICE_FUNC Index rows()
const {
return m_x.size(); }
202 EIGEN_DEVICE_FUNC Index cols()
const {
return m_cols; }
205 const NodeVector&
nodes()
const {
return m_x; }
210 const Scalar xi = m_x.coeff(row);
211 for (
Index t = 0; t < col; ++t) p *= xi;
227 eigen_assert(rows() == cols() &&
"Vandermonde::determinant requires a square matrix");
228 const Index n = rows();
230 internal::structured_exponent_type exponent = 0;
231 for (
Index j = 1; j < n; ++j)
232 for (
Index i = 0; i < j; ++i)
233 det = internal::structured_balance(
234 det * internal::structured_balance(Scalar(m_x.coeff(j) - m_x.coeff(i)), exponent), exponent);
237 return internal::structured_ldexp_clamped(det, exponent);
243 template <
typename Dest>
244 void evalTo(Dest& dst)
const {
245 dst.col(0).setOnes();
246 for (Index j = 1; j < m_cols; ++j) dst.col(j) = dst.col(j - 1).cwiseProduct(m_x);
250 template <
typename Dest>
251 void addTo(Dest& dst)
const {
252 NodeVector p = NodeVector::Ones(rows());
254 for (Index j = 1; j < m_cols; ++j) {
255 p = p.cwiseProduct(m_x);
261 template <
typename Dest>
262 void subTo(Dest& dst)
const {
263 NodeVector p = NodeVector::Ones(rows());
265 for (
Index j = 1; j < m_cols; ++j) {
266 p = p.cwiseProduct(m_x);
277 template <
typename Rhs>
279 EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic ||
280 int(ColsAtCompileTime) ==
int(Rhs::RowsAtCompileTime),
281 INVALID_MATRIX_PRODUCT)
282 eigen_assert(a.rows() == cols() &&
"invalid product: dimensions do not match");
293 template <
typename Dest,
typename Rhs,
typename ProductScalar>
294 void addProduct(Dest& dst,
const Rhs& rhs,
const ProductScalar& alpha)
const {
295 eigen_assert(rhs.rows() == m_cols &&
"invalid product: dimensions do not match");
298 const bool unitAlpha = alpha == ProductScalar(1);
299 using SplitComponents =
303 for (Index k = 0; k < rhs.cols(); ++k) {
304 horner(acc, rhs, k, SplitComponents());
306 dst.col(k) += acc.matrix();
308 dst.col(k) += alpha * acc.matrix();
313 template <
typename ProductScalar,
typename Rhs>
314 void horner(Array<ProductScalar, Rows_, 1>& acc,
const Rhs& rhs,
Index k, std::false_type)
const {
315 const Index n = m_cols;
316 acc.setConstant(ProductScalar(rhs.coeff(n - 1, k)));
317 for (
Index j = n - 2; j >= 0; --j)
318 acc = acc * m_x.array().template cast<ProductScalar>() + ProductScalar(rhs.coeff(j, k));
324 template <
typename ProductScalar,
typename Rhs>
325 void horner(Array<ProductScalar, Rows_, 1>& acc,
const Rhs& rhs,
Index k, std::true_type)
const {
326 using NodeArray = Array<Scalar, Rows_, 1>;
327 const Index n = m_cols;
328 const ProductScalar top(rhs.coeff(n - 1, k));
329 NodeArray re = NodeArray::Constant(rows(), numext::real(top));
330 NodeArray im = NodeArray::Constant(rows(), numext::imag(top));
331 for (
Index j = n - 2; j >= 0; --j) {
332 const ProductScalar c(rhs.coeff(j, k));
333 re = re * m_x.array() + numext::real(c);
334 im = im * m_x.array() + numext::imag(c);
336 acc = re.binaryExpr(im, [](
const Scalar& a,
const Scalar& b) {
return ProductScalar(a, b); });
346template <
typename Derived>
354template <
typename Derived>
396template <
typename Scalar_>
402 EIGEN_STATIC_ASSERT_NON_INTEGER(RealScalar)
409 template <
int Rows_,
int Cols_>
417 template <
int Rows_,
int Cols_>
419 EIGEN_STATIC_ASSERT(Rows_ == Dynamic || Cols_ == Dynamic || Rows_ == Cols_, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)
420 eigen_assert(V.rows() == V.cols() &&
"BjorckPereyra requires a square Vandermonde matrix");
424 const Index n = m_x.size();
427 for (
Index i = 0; i < j; ++i) {
428 if (m_x[i] == m_x[j]) {
434 m_isInitialized =
true;
438 Index rows() const noexcept {
return m_x.size(); }
439 Index cols() const noexcept {
return m_x.size(); }
445 eigen_assert(m_isInitialized &&
"BjorckPereyra is not initialized.");
449#ifdef EIGEN_PARSED_BY_DOXYGEN
454 template <
typename Rhs>
458#ifndef EIGEN_PARSED_BY_DOXYGEN
461 template <
typename RhsType,
typename DstType>
462 void _solve_impl(
const RhsType& rhs, DstType& dst)
const {
463 using RhsScalar =
typename RhsType::Scalar;
464 using WorkScalar =
typename DstType::Scalar;
465 using ProductOp = internal::scalar_product_op<Scalar, RhsScalar>;
466 EIGEN_CHECK_BINARY_COMPATIBILITY(ProductOp, Scalar, RhsScalar)
468 const Index n = m_x.size();
471 if (!m_order.empty()) permuted.
resize(n);
472 for (
Index k = 0; k < rhs.cols(); ++k) {
474 if (!m_order.empty()) {
475 for (
Index i = 0; i < n; ++i) permuted[i] = a[m_order[static_cast<std::size_t>(i)]];
478 for (Index j = 0; j < n - 1; ++j)
479 for (Index i = n - 1; i > j; --i) a[i] = (a[i] - a[i - 1]) / (m_x[i] - m_x[i - j - 1]);
480 for (Index j = n - 2; j >= 0; --j)
481 for (Index i = j; i < n - 1; ++i) a[i] -= m_x[j] * a[i + 1];
488 template <
bool Conjugate,
typename RhsType,
typename DstType>
489 void _solve_impl_transposed(
const RhsType& rhs, DstType& dst)
const {
490 using RhsScalar =
typename RhsType::Scalar;
491 using WorkScalar =
typename DstType::Scalar;
492 using ProductOp = internal::scalar_product_op<Scalar, RhsScalar>;
493 EIGEN_CHECK_BINARY_COMPATIBILITY(ProductOp, Scalar, RhsScalar)
495 const Index n = m_x.size();
496 dst = rhs.template conjugateIf<Conjugate>();
497 Matrix<WorkScalar, Dynamic, 1> permuted;
498 if (!m_order.empty()) permuted.
resize(n);
499 for (
Index k = 0; k < rhs.cols(); ++k) {
501 for (
Index j = 0; j < n - 1; ++j)
502 for (
Index i = n - 1; i > j; --i) w[i] -= m_x[j] * w[i - 1];
503 for (
Index j = n - 2; j >= 0; --j) {
504 w.tail(n - j - 1).array() /= (m_x.tail(n - j - 1) - m_x.head(n - j - 1)).array();
505 for (
Index i = j; i < n - 1; ++i) w[i] -= w[i + 1];
508 if (!m_order.empty()) {
510 for (
Index i = 0; i < n; ++i) w[m_order[static_cast<std::size_t>(i)]] = permuted[i];
513 if (Conjugate) dst = dst.conjugate().eval();
518 static RealScalar lejaLogAbs(
const Scalar& z) {
return numext::log(numext::abs(z)); }
520 void initializeNodeOrder(
const NodeVector&, std::false_type) {}
522 void initializeNodeOrder(
const NodeVector& nodes, std::true_type) {
523 using Real =
typename NumTraits<Scalar>::Real;
524 const Index n = nodes.size();
525 bool genuinelyComplex =
false;
526 for (
Index i = 0; i < n; ++i) genuinelyComplex = genuinelyComplex || numext::imag(nodes[i]) != Real(0);
527 if (!genuinelyComplex || n < 2)
return;
529 const NodeVector original = nodes;
531 m_order.resize(
static_cast<std::size_t
>(n));
532 std::vector<char> selected(
static_cast<std::size_t
>(n), 0);
533 std::vector<RealScalar> scores(
static_cast<std::size_t
>(n), RealScalar(0));
535 original.unaryExpr(&lejaLogAbs).maxCoeff(&next);
537 for (
Index position = 0; position < n; ++position) {
538 m_order[
static_cast<std::size_t
>(position)] = next;
539 selected[
static_cast<std::size_t
>(next)] = 1;
540 if (position + 1 == n)
break;
542 Index candidate = -1;
543 RealScalar candidateScore = -NumTraits<RealScalar>::infinity();
544 for (
Index i = 0; i < n; ++i) {
545 if (selected[
static_cast<std::size_t
>(i)])
continue;
546 scores[
static_cast<std::size_t
>(i)] += lejaLogAbs(original[i] - original[next]);
547 if (candidate < 0 || scores[
static_cast<std::size_t
>(i)] > candidateScore) {
549 candidateScore = scores[
static_cast<std::size_t
>(i)];
555 for (
Index i = 0; i < n; ++i) m_x[i] = original[m_order[static_cast<std::size_t>(i)]];
559 std::vector<Index> m_order;
560 bool m_isInitialized;
569template <
typename SolverScalar,
typename RhsScalar,
570 bool Compatible = has_ReturnType<ScalarBinaryOpTraits<SolverScalar, RhsScalar>>::value>
571struct bjorck_pereyra_result_scalar {
572 using type = SolverScalar;
575template <
typename SolverScalar,
typename RhsScalar>
576struct bjorck_pereyra_result_scalar<SolverScalar, RhsScalar, true> {
577 using type =
typename ScalarBinaryOpTraits<SolverScalar, RhsScalar>::ReturnType;
580template <
typename SolverScalar,
typename RhsType>
581struct bjorck_pereyra_solve_traits {
582 using ResultScalar =
typename bjorck_pereyra_result_scalar<SolverScalar, typename RhsType::Scalar>::type;
584 typename make_proper_matrix_type<ResultScalar, Dynamic, RhsType::ColsAtCompileTime, RhsType::PlainObject::Options,
585 Dynamic, RhsType::MaxColsAtCompileTime>::type;
588template <
typename Scalar_,
typename RhsType>
589struct solve_traits<BjorckPereyra<Scalar_>, RhsType, Dense> : bjorck_pereyra_solve_traits<Scalar_, RhsType> {};
591template <
typename Scalar_,
typename RhsType>
592struct solve_traits<Transpose<const BjorckPereyra<Scalar_>>, RhsType, Dense>
593 : bjorck_pereyra_solve_traits<Scalar_, RhsType> {};
595template <
typename Scalar_,
typename RhsType>
596struct solve_traits<CwiseUnaryOp<scalar_conjugate_op<Scalar_>, const Transpose<const BjorckPereyra<Scalar_>>>, RhsType,
597 Dense> : bjorck_pereyra_solve_traits<Scalar_, RhsType> {};
599template <
typename Factor,
typename Scalar_,
int Rows_,
int Cols_,
typename Plain,
typename Rhs>
600struct scaled_vandermonde_product_impl
601 : generic_product_impl_base<
602 CwiseBinaryOp<scalar_product_op<Factor, Scalar_>, const CwiseNullaryOp<scalar_constant_op<Factor>, Plain>,
603 const Vandermonde<Scalar_, Rows_, Cols_>>,
604 Rhs, scaled_vandermonde_product_impl<Factor, Scalar_, Rows_, Cols_, Plain, Rhs>> {
605 using Op = Vandermonde<Scalar_, Rows_, Cols_>;
606 using ScaledOp = CwiseBinaryOp<scalar_product_op<Factor, Scalar_>,
607 const CwiseNullaryOp<scalar_constant_op<Factor>, Plain>,
const Op>;
608 using Scalar =
typename Product<ScaledOp, Rhs>::Scalar;
610 template <
typename Dest>
611 static void scaleAndAddTo(Dest& dst,
const ScaledOp& lhs,
const Rhs& rhs,
const Scalar& alpha) {
612 using RhsNested =
typename nested_eval<Rhs, Rows_>::type;
613 RhsNested actualRhs(rhs);
614 lhs.rhs().addProduct(dst, actualRhs, Scalar(alpha * lhs.lhs().functor().m_other));
620#define EIGEN_SCALED_VANDERMONDE_PRODUCT_IMPL(ProductTag) \
621 template <typename Factor, typename Scalar_, int Rows_, int Cols_, typename Plain, typename Rhs> \
622 struct generic_product_impl< \
623 CwiseBinaryOp<scalar_product_op<Factor, Scalar_>, const CwiseNullaryOp<scalar_constant_op<Factor>, Plain>, \
624 const Vandermonde<Scalar_, Rows_, Cols_>>, \
625 Rhs, DenseShape, DenseShape, ProductTag> \
626 : scaled_vandermonde_product_impl<Factor, Scalar_, Rows_, Cols_, Plain, Rhs> {};
628EIGEN_SCALED_VANDERMONDE_PRODUCT_IMPL(CoeffBasedProductMode)
629EIGEN_SCALED_VANDERMONDE_PRODUCT_IMPL(LazyCoeffBasedProductMode)
630EIGEN_SCALED_VANDERMONDE_PRODUCT_IMPL(OuterProduct)
631EIGEN_SCALED_VANDERMONDE_PRODUCT_IMPL(InnerProduct)
632EIGEN_SCALED_VANDERMONDE_PRODUCT_IMPL(GemvProduct)
633EIGEN_SCALED_VANDERMONDE_PRODUCT_IMPL(GemmProduct)
635#undef EIGEN_SCALED_VANDERMONDE_PRODUCT_IMPL
637template <
typename Scalar_,
int Rows_,
int Cols_,
typename Rhs,
int ProductTag>
638struct generic_product_impl<Vandermonde<Scalar_, Rows_, Cols_>, Rhs, StructuredShape, DenseShape, ProductTag>
639 : structured_product_impl<Vandermonde<Scalar_, Rows_, Cols_>, Rhs> {};
Björck-Pereyra O(n^2) solver for square Vandermonde systems.
Definition Vandermonde.h:397
ComputationInfo info() const
Definition Vandermonde.h:444
BjorckPereyra(const Vandermonde< Scalar, Rows_, Cols_ > &V)
Definition Vandermonde.h:410
BjorckPereyra()
Definition Vandermonde.h:406
BjorckPereyra & compute(const Vandermonde< Scalar, Rows_, Cols_ > &V)
Definition Vandermonde.h:418
const Solve< BjorckPereyra, Rhs > solve(const MatrixBase< Rhs > &f) const
constexpr void resize(Index rows, Index cols)
An m x n Vandermonde matrix represented by its node vector.
Definition Vandermonde.h:158
Vandermonde(const MatrixBase< Derived > &nodes, Index cols)
Definition Vandermonde.h:186
Scalar determinant() const
Definition Vandermonde.h:226
const NodeVector & nodes() const
Definition Vandermonde.h:205
Vandermonde(const MatrixBase< Derived > &nodes)
Definition Vandermonde.h:194
Scalar coeff(Index row, Index col) const
Definition Vandermonde.h:208
Product< Vandermonde, Rhs > operator*(const MatrixBase< Rhs > &a) const
Definition Vandermonde.h:278
Vandermonde< typename Derived::Scalar, Derived::SizeAtCompileTime, Dynamic > makeVandermonde(const MatrixBase< Derived > &nodes, Index cols)
Definition Vandermonde.h:347
constexpr unsigned int RowMajorBit
Namespace containing all symbols from the Eigen library.
constexpr Index size() const noexcept