112 using Scalar = Scalar_;
114 using StorageIndex = int;
118 EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(
bool(RowNodeVector::NeedsToAlign || ColNodeVector::NeedsToAlign))
120 static constexpr int RowsAtCompileTime = Rows_;
121 static constexpr int ColsAtCompileTime = Cols_;
122 static constexpr int MaxRowsAtCompileTime = Rows_;
123 static constexpr int MaxColsAtCompileTime = Cols_;
124 static constexpr int SizeAtCompileTime = internal::size_at_compile_time(Rows_, Cols_);
125 static constexpr int MaxSizeAtCompileTime = SizeAtCompileTime;
126 static constexpr bool IsRowMajor =
false;
133 template <
typename XDerived,
typename YDerived>
135 EIGEN_STATIC_ASSERT_VECTOR_ONLY(XDerived)
136 EIGEN_STATIC_ASSERT_VECTOR_ONLY(YDerived)
137 eigen_assert(m_x.size() > 0 && m_y.size() > 0 &&
"Cauchy node vectors must be non-empty");
140 EIGEN_DEVICE_FUNC Index rows()
const {
return m_x.size(); }
141 EIGEN_DEVICE_FUNC Index cols()
const {
return m_y.size(); }
144 const RowNodeVector&
rowNodes()
const {
return m_x; }
146 const ColNodeVector&
colNodes()
const {
return m_y; }
149 Scalar
coeff(
Index row,
Index col)
const {
return Scalar(1) / (m_x.coeff(row) - m_y.coeff(col)); }
178 eigen_assert(rows() == cols() &&
"Cauchy::determinant requires a square matrix");
179 const Index n = rows();
182 for (
Index j = 1; j < n; ++j)
183 for (
Index i = 0; i < j; ++i) {
184 const Scalar xDiff = internal::structured_balance(Scalar(m_x.coeff(j) - m_x.coeff(i)), exponent);
185 det = internal::structured_balance(Scalar(det * xDiff), exponent);
186 const Scalar yDiff = internal::structured_balance(Scalar(m_y.coeff(i) - m_y.coeff(j)), exponent);
187 det = internal::structured_balance(Scalar(det * yDiff), exponent);
189 for (
Index j = 0; j < n; ++j)
190 for (
Index i = 0; i < n; ++i) {
191 Index denomExponent = 0;
192 const Scalar d = internal::structured_balance(Scalar(m_x.coeff(i) - m_y.coeff(j)), denomExponent);
193 exponent -= denomExponent;
194 det = internal::structured_balance(Scalar(det / d), exponent);
196 return internal::structured_ldexp_clamped(det, exponent);
201 template <
typename Dest>
202 void evalTo(Dest& dst)
const {
203 applyAssignment(dst, internal::assign_op<typename Dest::Scalar, Scalar>());
207 template <
typename Dest>
208 void addTo(Dest& dst)
const {
209 applyAssignment(dst, internal::add_assign_op<typename Dest::Scalar, Scalar>());
213 template <
typename Dest>
214 void subTo(Dest& dst)
const {
215 applyAssignment(dst, internal::sub_assign_op<typename Dest::Scalar, Scalar>());
223 template <
typename Rhs>
225 EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic ||
226 int(ColsAtCompileTime) ==
int(Rhs::RowsAtCompileTime),
227 INVALID_MATRIX_PRODUCT)
228 eigen_assert(v.rows() == cols() &&
"invalid product: dimensions do not match");
238 template <
typename Dest,
typename Rhs,
typename ProductScalar>
239 void addProduct(Dest& dst,
const Rhs& rhs,
const ProductScalar& alpha)
const {
240 const Index n = cols();
241 eigen_assert(rhs.rows() == n &&
"invalid product: dimensions do not match");
244 const bool unitAlpha = alpha == ProductScalar(1);
245 const auto weight = [&](Index j, Index k) {
246 return unitAlpha ? ProductScalar(rhs.coeff(j, k)) : ProductScalar(alpha * rhs.
coeff(j, k));
250 if (rhs.cols() > 1 && std::is_same<ProductScalar, Scalar>::value) {
253 constexpr Index kBlockBytes =
Index(1) << 19;
254 constexpr Index kMinBlockRows = 1024;
255 const Index m = rows(), r = rhs.cols();
256 const Index blockRows = numext::mini(m, numext::maxi(kMinBlockRows, kBlockBytes / (r *
Index(
sizeof(Scalar)))));
257 Matrix<Scalar, Dynamic, 1, ColMajor, Rows_> reciprocals(blockRows);
258 for (Index i = 0; i < m; i += blockRows) {
259 const Index b = numext::mini(blockRows, m - i);
260 for (Index j = 0; j < n; ++j) {
261 reciprocals.head(b) = (m_x.segment(i, b).array() - m_y.
coeff(j)).inverse();
262 for (Index k = 0; k < r; ++k) dst.col(k).segment(i, b) += weight(j, k) * reciprocals.head(b);
267 for (
Index k = 0; k < rhs.cols(); ++k)
268 for (
Index j = 0; j < n; ++j) dst.col(k) += weight(j, k) * (m_x.array() - m_y.coeff(j)).inverse().matrix();
272 template <
typename Dest,
typename Assignment>
273 void applyAssignment(Dest& dst,
const Assignment& assignment)
const {
274 for (
Index j = 0; j < cols(); ++j) {
275 auto dstColumn = dst.col(j);
276 internal::call_assignment_no_alias(dstColumn, (m_x.array() - m_y.coeff(j)).inverse().matrix(), assignment);
332 EIGEN_GENERIC_PUBLIC_INTERFACE(
CauchyLU)
340 template <
int Rows_,
int Cols_>
352 template <
int Rows_,
int Cols_>
354 eigen_assert(C.rows() == C.cols() &&
"CauchyLU requires a square Cauchy matrix");
355 const Index n = C.rows();
358 DenseVector a = DenseVector::Ones(n);
359 DenseVector b = DenseVector::Ones(n);
361 m_perm.resize(
static_cast<std::size_t
>(n));
364 for (
Index k = 0; k < n; ++k) {
367 for (
Index i = k; i < n; ++i) {
368 m_lu(i, k) = a[i] * b[k] / (x[i] - y[k]);
369 const RealScalar mag = numext::abs(m_lu(i, k));
370 if ((numext::isnan)(mag) || mag > best) {
376 m_lu.row(piv).head(k + 1).swap(m_lu.row(k).head(k + 1));
377 std::swap(x[piv], x[k]);
378 std::swap(a[piv], a[k]);
380 m_perm[
static_cast<std::size_t
>(k)] = piv;
381 const Scalar pivot = m_lu(k, k);
382 if (pivot == Scalar(0) || !(numext::isfinite)(pivot)) {
384 m_lu.row(k).tail(n - k - 1).setZero();
385 m_lu.col(k).tail(n - k - 1).setZero();
388 m_lu.col(k).tail(n - k - 1) /= pivot;
389 for (
Index j = k + 1; j < n; ++j) {
390 m_lu(k, j) = a[k] * b[j] / (x[k] - y[j]);
393 for (
Index i = k + 1; i < n; ++i) a[i] *= (x[i] - x[k]) / (x[i] - y[k]);
394 for (
Index j = k + 1; j < n; ++j) b[j] *= (y[j] - y[k]) / (y[j] - x[k]);
396 m_isInitialized =
true;
400 Index rows() const noexcept {
return m_lu.rows(); }
401 Index cols() const noexcept {
return m_lu.cols(); }
406 eigen_assert(m_isInitialized &&
"CauchyLU is not initialized.");
410#ifdef EIGEN_PARSED_BY_DOXYGEN
415 template <
typename Rhs>
419#ifndef EIGEN_PARSED_BY_DOXYGEN
421 template <
typename RhsType,
typename DstType>
422 void _solve_impl(
const RhsType& rhs, DstType& dst)
const {
424 for (
Index k = 0; k < rows(); ++k) {
425 const Index piv = m_perm[
static_cast<std::size_t
>(k)];
426 if (piv != k) dst.row(k).swap(dst.row(piv));
428 m_lu.template triangularView<UnitLower>().solveInPlace(dst);
429 m_lu.template triangularView<Upper>().solveInPlace(dst);
435 template <
bool Conjugate,
typename RhsType,
typename DstType>
436 void _solve_impl_transposed(
const RhsType& rhs, DstType& dst)
const {
437 dst = rhs.template conjugateIf<Conjugate>();
438 m_lu.template triangularView<Upper>().transpose().solveInPlace(dst);
439 m_lu.template triangularView<UnitLower>().transpose().solveInPlace(dst);
440 for (Index k = rows() - 1; k >= 0; --k) {
441 const Index piv = m_perm[
static_cast<std::size_t
>(k)];
442 if (piv != k) dst.row(k).swap(dst.row(piv));
444 if (Conjugate) dst = dst.conjugate().eval();
450 std::vector<Index> m_perm;
451 bool m_isInitialized;