98class Hankel :
public EigenBase<Hankel<Scalar_, Rows_, Cols_>> {
100 using Scalar = Scalar_;
102 using StorageIndex = int;
103 using Complex = std::complex<RealScalar>;
108 static constexpr int RowsAtCompileTime = Rows_;
109 static constexpr int ColsAtCompileTime = Cols_;
110 static constexpr int MaxRowsAtCompileTime = Rows_;
111 static constexpr int MaxColsAtCompileTime = Cols_;
112 static constexpr int SizeAtCompileTime = internal::size_at_compile_time(Rows_, Cols_);
113 static constexpr int MaxSizeAtCompileTime = SizeAtCompileTime;
114 static constexpr bool IsRowMajor =
false;
120 static constexpr int GenSizeAtCompileTime = (Rows_ == Dynamic || Cols_ == Dynamic) ? Dynamic : (Rows_ + Cols_ - 1);
131 template <
typename ColDerived,
typename RowDerived>
133 : m_rows(col.
size()), m_cols(row.
size()) {
134 EIGEN_STATIC_ASSERT_VECTOR_ONLY(ColDerived)
135 EIGEN_STATIC_ASSERT_VECTOR_ONLY(RowDerived)
136 const Index m = col.size(), n = row.size();
137 eigen_assert(m > 0 && n > 0 &&
"Hankel generators must be non-empty");
138 m_h.resize(m + n - 1);
140 if (n > 1) m_h.
tail(n - 1) = row.
tail(n - 1);
141 if (m > 1 && n > 1 && (m > internal::structured_direct_threshold() || n > internal::structured_direct_threshold()))
142 m_symbol = computeSymbol();
145 EIGEN_DEVICE_FUNC Index rows()
const {
return m_rows.value(); }
146 EIGEN_DEVICE_FUNC Index cols()
const {
return m_cols.value(); }
153 ColGeneratorType
column()
const {
return m_h.head(rows()); }
156 RowGeneratorType
lastRow()
const {
return m_h.segment(rows() - 1, cols()); }
163 ComplexVector
symbol()
const {
return m_symbol.size() > 0 ? m_symbol : computeSymbol(); }
174 return Hankel<Scalar, Cols_, Rows_>(m_h, cols(), rows(), transposedSymbol());
181 return Hankel(m_h.conjugate(), rows(), cols(), internal::structured_reverse_symbol(m_symbol).
conjugate());
194 ColGeneratorType c = m_h.segment(cols() - 1, rows());
195 RowGeneratorType r = m_h.head(cols()).reverse();
202 static constexpr int SolveRowsAtCompileTime = Cols_ != Dynamic ? Cols_ : Rows_;
211 template <
typename Rhs>
213 EIGEN_STATIC_ASSERT(RowsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic ||
214 int(RowsAtCompileTime) ==
int(Rhs::RowsAtCompileTime),
215 YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)
216 eigen_assert(rows() == cols() &&
"Hankel::solve requires a square matrix");
217 eigen_assert(b.rows() == rows() &&
"right-hand side has the wrong number of rows");
220 "Hankel::solve: the Levinson recursion broke down; "
221 "use LookAheadLevinson on toToeplitz() for diagnostics");
222 return levinson.
solve(b).colwise().reverse();
228 template <
typename Dest>
229 void evalTo(Dest& dst)
const {
230 EIGEN_IF_CONSTEXPR (Dest::IsRowMajor) {
231 for (Index i = 0; i < rows(); ++i) dst.row(i) = m_h.segment(i, cols()).transpose();
234 for (Index j = 0; j < cols(); ++j) dst.col(j) = m_h.segment(j, rows());
238 template <
typename Dest>
239 void addTo(Dest& dst)
const {
240 EIGEN_IF_CONSTEXPR (Dest::IsRowMajor) {
241 for (
Index i = 0; i < rows(); ++i) dst.row(i) += m_h.segment(i, cols()).transpose();
244 for (
Index j = 0; j < cols(); ++j) dst.col(j) += m_h.segment(j, rows());
248 template <
typename Dest>
249 void subTo(Dest& dst)
const {
250 EIGEN_IF_CONSTEXPR (Dest::IsRowMajor) {
251 for (
Index i = 0; i < rows(); ++i) dst.row(i) -= m_h.segment(i, cols()).transpose();
254 for (
Index j = 0; j < cols(); ++j) dst.col(j) -= m_h.segment(j, rows());
261 template <
typename Rhs>
263 EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic ||
264 int(ColsAtCompileTime) ==
int(Rhs::RowsAtCompileTime),
265 INVALID_MATRIX_PRODUCT)
266 eigen_assert(x.rows() == cols() &&
"invalid product: dimensions do not match");
278 template <
typename Dest,
typename Rhs,
typename ProductScalar>
279 void addProduct(Dest& dst,
const Rhs& rhs,
const ProductScalar& alpha)
const {
280 const Index m = rows(), n = cols();
281 eigen_assert(rhs.rows() == n &&
"invalid product: dimensions do not match");
282 const bool small = m == 1 || n == 1 ||
283 (m <= internal::structured_direct_threshold() && n <= internal::structured_direct_threshold());
285 directProduct(dst, rhs, alpha);
288 internal::structured_fft_apply(dst, m_symbol, m, rhs.colwise().reverse(), alpha);
292 template <
typename OtherScalar,
int OtherRows,
int OtherCols>
299 Hankel(
const GeneratorType& h,
Index rows,
Index cols,
const ComplexVector&
symbol)
300 : m_rows(rows), m_cols(cols), m_h(h), m_symbol(
symbol) {}
306 template <
typename Dest,
typename Rhs,
typename ProductScalar>
307 void directProductColumn(Dest& dst,
const Rhs& rhs,
Index k,
const ProductScalar& alpha)
const {
308 const Index m = rows(), n = cols();
311 const bool unitAlpha = alpha == ProductScalar(1);
315 const ProductScalar xj = unitAlpha ? ProductScalar(rhs.coeff(0, k)) : ProductScalar(alpha * rhs.
coeff(0, k));
316 dst.col(k) += xj * m_h.head(m);
321 const ProductScalar acc = m_h.head(n).cwiseProduct(rhs.col(k)).sum();
322 dst.coeffRef(0, k) += unitAlpha ? acc : ProductScalar(alpha * acc);
326 if (m <= internal::structured_scalar_threshold() && n <= internal::structured_scalar_threshold()) {
329 for (
Index i = 0; i < m; ++i) {
330 ProductScalar acc(0);
331 for (
Index j = 0; j < n; ++j) acc +=
coeff(i, j) * rhs.coeff(j, k);
332 dst.coeffRef(i, k) += unitAlpha ? acc : ProductScalar(alpha * acc);
338 auto dstCol = dst.col(k);
339 for (
Index j = 0; j < n; ++j) {
340 const ProductScalar xj = unitAlpha ? ProductScalar(rhs.coeff(j, k)) : ProductScalar(alpha * rhs.
coeff(j, k));
341 dstCol += xj * m_h.segment(j, m);
347 template <
typename Dest,
typename Rhs,
typename ProductScalar>
348 void directProduct(Dest& dst,
const Rhs& rhs,
const ProductScalar& alpha)
const {
349 for (
Index k = 0; k < rhs.cols(); ++k) directProductColumn(dst, rhs, k, alpha);
355 ComplexVector computeSymbol()
const {
356 const Index m = rows(), n = cols();
357 const Index p = internal::fft_next_good_size(m + n - 1);
358 ComplexVector embedding = ComplexVector::Zero(p);
359 embedding.head(m) = m_h.tail(m).template cast<Complex>();
360 embedding.tail(n - 1) = m_h.head(n - 1).template cast<Complex>();
361 if (p == 1)
return embedding;
363 auto&& fft = internal::structured_fft_engine<RealScalar>();
364 fft.fwd(
symbol, embedding, p);
373 ComplexVector transposedSymbol()
const {
374 ComplexVector sym = m_symbol;
375 const Index p = sym.size();
376 if (p > 0 && rows() != cols()) {
377 Index s = (rows() - cols()) % p;
381 Array<RealScalar, 64, 1> angles, values;
382 Matrix<Complex, 64, 1> phases;
384 for (
Index f = 0; f < p;) {
385 const Index count = numext::mini<Index>(64, p - f);
386 for (
Index i = 0; i < count; ++i) {
387 angles[i] = RealScalar(2 * EIGEN_PI) * RealScalar(fs) / RealScalar(p);
389 if (fs >= p) fs -= p;
391 values.head(count) = angles.head(count).cos();
392 phases.head(count).real() = values.head(count);
393 values.head(count) = angles.head(count).sin();
394 phases.head(count).imag() = values.head(count);
395 sym.segment(f, count).array() *= phases.head(count).array();
404 internal::variable_if_dynamic<Index, RowsAtCompileTime> m_rows;
405 internal::variable_if_dynamic<Index, ColsAtCompileTime> m_cols;
407 ComplexVector m_symbol;