100 using Scalar = Scalar_;
102 using StorageIndex = int;
103 using Complex = std::complex<RealScalar>;
109 static constexpr int RowsAtCompileTime = Size_;
110 static constexpr int ColsAtCompileTime = Size_;
111 static constexpr int MaxRowsAtCompileTime = Size_;
112 static constexpr int MaxColsAtCompileTime = Size_;
113 static constexpr int SizeAtCompileTime = internal::size_at_compile_time(Size_, Size_);
114 static constexpr int MaxSizeAtCompileTime = SizeAtCompileTime;
115 static constexpr bool IsRowMajor =
false;
125 template <
typename Derived>
127 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
128 eigen_assert(m_col.size() > 0 &&
"Circulant generator must be non-empty");
129 if (m_col.size() > internal::structured_direct_threshold()) {
130 m_symbol = computeSymbol();
131 m_prodSymbol = computeProdSymbol(m_col);
135 EIGEN_DEVICE_FUNC Index rows()
const {
return m_col.size(); }
136 EIGEN_DEVICE_FUNC Index cols()
const {
return m_col.size(); }
139 const GeneratorType&
column()
const {
return m_col; }
145 ComplexVector
symbol()
const {
return m_symbol.size() > 0 ? m_symbol : computeSymbol(); }
150 if (k < 0) k += rows();
151 return m_col.coeff(k);
159 const Index n = rows();
160 GeneratorType col(n);
162 if (n > 1) col.tail(n - 1) = m_col.tail(n - 1).reverse();
163 return Circulant(col, internal::structured_reverse_symbol(m_symbol),
164 internal::structured_reverse_symbol(m_prodSymbol));
171 return Circulant(m_col.conjugate(), internal::structured_reverse_symbol(m_symbol).conjugate(),
172 internal::structured_reverse_symbol(m_prodSymbol).conjugate());
180 const Index n = rows();
181 GeneratorType col(n);
182 col[0] = numext::conj(m_col[0]);
183 if (n > 1) col.tail(n - 1) = m_col.tail(n - 1).reverse().conjugate();
184 return Circulant(col, m_symbol.conjugate(), m_prodSymbol.conjugate());
190 template <
typename Dest>
191 void evalTo(Dest& dst)
const {
192 const Index n = rows();
193 EIGEN_IF_CONSTEXPR (Dest::IsRowMajor) {
194 for (Index i = 0; i < n; ++i) {
195 dst.row(i).head(i + 1) = m_col.head(i + 1).reverse().transpose();
196 dst.row(i).tail(n - i - 1) = m_col.tail(n - i - 1).reverse().transpose();
200 for (
Index j = 0; j < n; ++j) {
201 dst.col(j).head(j) = m_col.tail(j);
202 dst.col(j).tail(n - j) = m_col.head(n - j);
207 template <
typename Dest>
208 void addTo(Dest& dst)
const {
209 const Index n = rows();
210 EIGEN_IF_CONSTEXPR (Dest::IsRowMajor) {
211 for (
Index i = 0; i < n; ++i) {
212 dst.row(i).head(i + 1) += m_col.head(i + 1).reverse().transpose();
213 dst.row(i).tail(n - i - 1) += m_col.tail(n - i - 1).reverse().transpose();
217 for (
Index j = 0; j < n; ++j) {
218 dst.col(j).head(j) += m_col.tail(j);
219 dst.col(j).tail(n - j) += m_col.head(n - j);
224 template <
typename Dest>
225 void subTo(Dest& dst)
const {
226 const Index n = rows();
227 EIGEN_IF_CONSTEXPR (Dest::IsRowMajor) {
228 for (
Index i = 0; i < n; ++i) {
229 dst.row(i).head(i + 1) -= m_col.head(i + 1).reverse().transpose();
230 dst.row(i).tail(n - i - 1) -= m_col.tail(n - i - 1).reverse().transpose();
234 for (
Index j = 0; j < n; ++j) {
235 dst.col(j).head(j) -= m_col.tail(j);
236 dst.col(j).tail(n - j) -= m_col.head(n - j);
244 template <
typename Rhs>
246 EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic ||
247 int(ColsAtCompileTime) ==
int(Rhs::RowsAtCompileTime),
248 INVALID_MATRIX_PRODUCT)
249 eigen_assert(x.rows() == cols() &&
"invalid product: dimensions do not match");
259 template <
typename Rhs>
261 EIGEN_STATIC_ASSERT(RowsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic ||
262 int(RowsAtCompileTime) ==
int(Rhs::RowsAtCompileTime),
263 YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)
264 const Index n = rows();
265 eigen_assert(b.rows() == n &&
"right-hand side has the wrong number of rows");
266 const ComplexVector s =
symbol();
267 const RealVector mods = s.cwiseAbs();
268 const ComplexVector sinv = internal::structured_pinv_symbol(s, mods, internal::structured_rank_threshold(s, mods));
271 internal::structured_fft_apply(x, sinv, n, b.derived(), Scalar(1));
282 const ComplexVector s =
symbol();
283 const RealVector mods = s.cwiseAbs();
284 return (!(mods.array() < internal::structured_rank_threshold(s, mods))).count();
292 const Index n = rows();
293 const ComplexVector sinv =
symbol().cwiseInverse();
294 GeneratorType col(n);
296 col = internal::structured_scalar_part_impl<Scalar>::run(sinv);
298 auto&& fft = internal::structured_fft_engine<RealScalar>();
300 fft.inv(ct, sinv, n);
301 col = internal::structured_scalar_part_impl<Scalar>::run(ct);
303 return Circulant(col, n > internal::structured_direct_threshold() ? sinv : ComplexVector(),
304 n > internal::structured_direct_threshold() ? computeProdSymbol(col) : ComplexVector());
316 const ComplexVector s =
symbol();
319 for (
Index k = 0; k < s.size(); ++k)
320 det = internal::structured_balance(Complex(det * internal::structured_balance(s[k], exponent)), exponent);
321 return internal::structured_scalar_part_impl<Scalar>::run_scalar(internal::structured_ldexp_clamped(det, exponent));
335 const Index n = rows();
336 const ComplexVector roots = fourierRoots();
337 ComplexMatrix F(n, n);
338 for (
Index k = 0; k < n; ++k) fourierColumn(F, roots, k, k);
350 const std::vector<Index> perm = svdOrdering(s, mods);
351 RealVector sv(s.size());
352 for (
Index t = 0; t < s.size(); ++t) sv[t] = mods[perm[t]];
360 const Index n = rows();
363 const std::vector<Index> perm = svdOrdering(s, mods);
364 const ComplexVector roots = fourierRoots();
365 ComplexMatrix U(n, n);
366 for (
Index t = 0; t < n; ++t) {
367 fourierColumn(U, roots, perm[t], t);
368 const RealScalar a = mods[perm[t]];
369 if (a > RealScalar(0)) U.col(t) *= s[perm[t]] / a;
378 const Index n = rows();
381 const std::vector<Index> perm = svdOrdering(s, mods);
382 const ComplexVector roots = fourierRoots();
383 ComplexMatrix V(n, n);
384 for (
Index t = 0; t < n; ++t) fourierColumn(V, roots, perm[t], t);
391 template <
typename Dest,
typename Rhs,
typename ProductScalar>
392 void addProduct(Dest& dst,
const Rhs& rhs,
const ProductScalar& alpha)
const {
393 const Index n = rows();
394 eigen_assert(rhs.rows() == n &&
"invalid product: dimensions do not match");
395 if (n <= internal::structured_direct_threshold()) {
396 directProduct(dst, rhs, alpha);
402 const ComplexVector& s = m_prodSymbol.size() > 0 ? m_prodSymbol : m_symbol;
403 internal::structured_fft_apply(dst, s, n, rhs, alpha);
412 Circulant(
const GeneratorType& col,
const ComplexVector&
symbol,
const ComplexVector& prodSymbol)
413 : m_col(col), m_symbol(
symbol), m_prodSymbol(prodSymbol) {}
425 static ComplexVector computeProdSymbol(
const GeneratorType& col) {
426 const Index n = col.size();
427 if (internal::fft_next_good_size(n) == n)
return ComplexVector();
428 const Index p = internal::fft_next_good_size(2 * n - 1);
429 ComplexVector embedding = ComplexVector::Zero(p);
430 embedding.head(n) = col.template cast<Complex>();
431 embedding.tail(n - 1) = col.tail(n - 1).template cast<Complex>();
433 auto&& fft = internal::structured_fft_engine<RealScalar>();
434 fft.fwd(
symbol, embedding, p);
441 template <
typename Dest,
typename Rhs,
typename ProductScalar>
442 void directProductColumn(Dest& dst,
const Rhs& rhs,
Index k,
const ProductScalar& alpha)
const {
443 const Index n = rows();
446 const bool unitAlpha = alpha == ProductScalar(1);
447 if (n <= internal::structured_scalar_threshold()) {
450 for (
Index i = 0; i < n; ++i) {
451 ProductScalar acc(0);
452 for (
Index j = 0; j < n; ++j) acc +=
coeff(i, j) * rhs.coeff(j, k);
453 dst.coeffRef(i, k) += unitAlpha ? acc : ProductScalar(alpha * acc);
459 auto dstCol = dst.col(k);
460 for (
Index j = 0; j < n; ++j) {
461 const ProductScalar xj = unitAlpha ? ProductScalar(rhs.coeff(j, k)) : ProductScalar(alpha * rhs.
coeff(j, k));
462 dstCol.head(j) += xj * m_col.tail(j);
463 dstCol.tail(n - j) += xj * m_col.head(n - j);
469 template <
typename Dest,
typename Rhs,
typename ProductScalar>
470 void directProduct(Dest& dst,
const Rhs& rhs,
const ProductScalar& alpha)
const {
471 for (
Index k = 0; k < rhs.cols(); ++k) directProductColumn(dst, rhs, k, alpha);
490 std::vector<Index> svdOrdering(ComplexVector& s, RealVector& mods)
const {
491 const Index n = rows();
493 EIGEN_IF_CONSTEXPR (!NumTraits<Scalar>::IsComplex) {
494 const Index pairs = (n - 1) / 2;
496 mods.head(n - pairs) = s.head(n - pairs).cwiseAbs();
497 mods.tail(pairs) = mods.segment(1, pairs).reverse();
501 return internal::structured_svd_permutation(mods);
506 ComplexVector fourierRoots()
const {
507 const Index n = rows();
508 const RealScalar scale = RealScalar(1) / numext::sqrt(RealScalar(n));
509 ComplexVector roots(n);
510 for (
Index j = 0; j < n; ++j)
511 roots[j] = std::polar(scale, RealScalar(2 * EIGEN_PI) * RealScalar(j) / RealScalar(n));
516 void fourierColumn(ComplexMatrix& F,
const ComplexVector& roots,
Index k,
Index dstCol)
const {
517 const Index n = rows();
519 for (
Index j = 0; j < n; ++j) {
520 F(j, dstCol) = roots[jk];
522 if (jk >= n) jk -= n;
527 ComplexVector computeSymbol()
const {
528 const Index n = m_col.size();
529 const ComplexVector cc = m_col.template cast<Complex>();
530 if (n == 1)
return cc;
532 auto&& fft = internal::structured_fft_engine<RealScalar>();
538 ComplexVector m_symbol;
541 ComplexVector m_prodSymbol;