10#ifndef EIGEN_STRUCTURED_LOOK_AHEAD_LEVINSON_H
11#define EIGEN_STRUCTURED_LOOK_AHEAD_LEVINSON_H
14#include "./InternalHeaderCheck.h"
18template <
typename Scalar_>
23template <
typename Scalar_>
24struct traits<LookAheadLevinson<Scalar_>> : traits<Matrix<Scalar_, Dynamic, Dynamic>> {
25 using XprKind = MatrixXpr;
26 using StorageKind = SolverStorage;
27 using StorageIndex = int;
28 using BaseTraits = traits<Matrix<Scalar_, Dynamic, Dynamic>>;
29 static constexpr int Flags = BaseTraits::Flags &
RowMajorBit;
30 static constexpr int CoeffReadCost = Dynamic;
34template <
typename D1,
typename D2>
35typename D1::Scalar structured_tdot(
const MatrixBase<D1>& a,
const MatrixBase<D2>& b) {
36 return a.cwiseProduct(b).sum();
39template <
typename Scalar>
40Matrix<Scalar, Dynamic, 1> structured_upshift(
const Matrix<Scalar, Dynamic, 1>& v) {
41 const Index k = v.size();
42 Matrix<Scalar, Dynamic, 1> w = Matrix<Scalar, Dynamic, 1>::Zero(k);
43 if (k > 1) w.head(k - 1) = v.tail(k - 1);
83template <
typename Scalar_>
97 template <
int Rows_,
int Cols_>
99 : m_maxBlockSize(4), m_n(0), m_isInitialized(false), m_info(
InvalidInput) {
107 eigen_assert(p >= 1);
115 Index rows() const noexcept {
return m_n; }
116 Index cols() const noexcept {
return m_n; }
119 template <
int Rows_,
int Cols_>
122#ifdef EIGEN_PARSED_BY_DOXYGEN
128 template <
typename Rhs>
132#ifndef EIGEN_PARSED_BY_DOXYGEN
140 template <
typename RhsType,
typename DstType>
141 void _solve_impl(
const RhsType& rhs, DstType& dst)
const {
142 dst.noalias() = solveForward(rhs);
149 template <
bool Conjugate,
typename RhsType,
typename DstType>
150 void _solve_impl_transposed(
const RhsType& rhs, DstType& dst)
const {
151 const DenseMatrix reversed = rhs.template conjugateIf<Conjugate>().colwise().reverse();
152 dst = solveForward(reversed).colwise().reverse().template conjugateIf<Conjugate>();
159 eigen_assert(m_isInitialized &&
"LookAheadLevinson is not initialized.");
166 eigen_assert(m_isInitialized &&
"LookAheadLevinson is not initialized.");
173 template <
typename Rhs>
174 DenseMatrix solveForward(
const Rhs& b)
const {
175 const Index nrhs = b.cols();
176 DenseMatrix x = m_luInit.solve(b.topRows(m_k0));
177 DenseMatrix rhs, a, xn;
178 for (
const Step& s : m_steps) {
179 rhs.noalias() = b.middleRows(s.k, s.p) - s.WspEk * x;
180 a = s.luGamma.solve(rhs);
181 xn.resize(s.k + s.p, nrhs);
182 xn.topRows(s.k).noalias() = x + s.EkYp * a;
183 xn.bottomRows(s.p) = a;
195 FullPivLU<DenseMatrix> luGamma;
199 static DenseMatrix leadingBlock(
const DenseVector& c,
const DenseVector& r,
Index p) {
201 for (
Index j = 0; j < p; ++j) {
202 B.col(j).head(j) = r.segment(1, j).reverse();
203 B.col(j).tail(p - j) = c.head(p - j);
210 static DenseMatrix shiftBlock(
const DenseVector& v,
Index first,
Index len,
Index cols) {
211 DenseMatrix B(len, cols);
212 for (
Index j = 0; j < cols; ++j) B.col(j) = v.segment(first + j, len);
216 static RealScalar smallestSingularValue(
const DenseMatrix& M) {
217 if (M.rows() == 1)
return numext::abs(M(0, 0));
218 JacobiSVD<DenseMatrix> svd(M);
219 return svd.singularValues()(svd.singularValues().
size() - 1);
222 Index m_maxBlockSize;
225 FullPivLU<DenseMatrix> m_luInit;
226 std::vector<Step> m_steps;
227 bool m_isInitialized;
230 RealScalar m_normEst;
233template <
typename Scalar_>
234template <
int Rows_,
int Cols_>
236 using internal::structured_tdot;
237 using internal::structured_upshift;
239 EIGEN_STATIC_ASSERT(Rows_ == Dynamic || Cols_ == Dynamic || Rows_ == Cols_, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES)
240 eigen_assert(T.rows() == T.cols() &&
"LookAheadLevinson requires a square Toeplitz matrix");
241 const Index n = T.rows();
242 const DenseVector c = T.column();
243 const DenseVector r = T.row();
244 const Scalar rho0 = c[0];
249 m_normEst = c.cwiseAbs().sum() + r.cwiseAbs().sum();
256 RealScalar best = RealScalar(-1);
257 const Index kmax = numext::mini<Index>(m_maxBlockSize, n);
258 for (Index i = 1; i <= kmax; ++i) {
259 RealScalar sv = smallestSingularValue(leadingBlock(c, r, i));
266 m_luInit.compute(leadingBlock(c, r, k));
270 bool lastWasBlock =
false;
271 DenseVector yPrev, zPrev;
273 Index kp = 0, pp = 0;
274 DenseMatrix Ypp, Zpp;
276 DenseVector y_kp_1, z_kp_1;
279 y = m_luInit.transpose().solve((-r.segment(1, k)).eval());
280 z = m_luInit.solve((-c.segment(1, k)).eval());
281 gamma = rho0 + structured_tdot(c.segment(1, k), y);
283 lastWasBlock =
false;
284 yPrev = DenseVector::Zero(0);
285 zPrev = DenseVector::Zero(0);
291 Ypp = DenseMatrix::Zero(0, k);
292 Zpp = DenseMatrix::Zero(0, k);
293 luGammaPP = m_luInit;
294 y_kp_1 = DenseVector::Zero(0);
295 z_kp_1 = DenseVector::Zero(0);
300 const Index pcap = numext::mini<Index>(m_maxBlockSize, n - k);
301 const DenseVector Ek_y = y.reverse(), Ek_z = z.reverse();
303 DenseVector g_k, h_k;
304 bool gh_ready =
false;
305 auto ensure_gh = [&]() {
306 if (gh_ready)
return;
311 g_k.head(k - 1) = zPrev.reverse();
312 g_k[k - 1] = Scalar(1);
314 h_k.head(k - 1) = yPrev.reverse();
315 h_k[k - 1] = Scalar(1);
319 DenseVector rhs_y = -r.segment(kp + 2, pp);
320 DenseVector rhs_z = -c.segment(kp + 2, pp);
322 const DenseMatrix Rpp = shiftBlock(r, 1, kp, pp);
323 const DenseMatrix Spp = shiftBlock(c, 1, kp, pp);
324 rhs_y.noalias() -= Rpp.transpose() * y_kp_1.reverse();
325 rhs_z.noalias() -= Spp.transpose() * z_kp_1.reverse();
327 const DenseVector a_y = luGammaPP.transpose().solve(rhs_y);
328 const DenseVector a_z = luGammaPP.solve(rhs_z);
329 DenseVector yk1 = DenseVector::Zero(k), zk1 = DenseVector::Zero(k);
331 yk1.head(kp) = y_kp_1 + (Zpp * a_y).reverse();
332 zk1.head(kp) = z_kp_1 + (Ypp * a_z).reverse();
336 const Scalar c1 = -r[k + 1] - structured_tdot(r.segment(1, k), Ek_y);
337 const Scalar d1 = -c[k + 1] - structured_tdot(c.segment(1, k), Ek_z);
338 g_k = (yk1 - structured_upshift<Scalar>(y) + y[0] * y) / c1;
339 h_k = (zk1 - structured_upshift<Scalar>(z) + z[0] * z) / d1;
345 DenseMatrix Yp(k, pcap), Zp(k, pcap);
350 RealScalar bestPsi = RealScalar(-1);
351 DenseMatrix bestGamma;
353 for (Index p = 1; p <= pcap; ++p) {
356 const Index i = p - 1;
357 const Scalar ci = -r[k + i] - structured_tdot(r.segment(i, k), Ek_y);
358 const Scalar di = -c[k + i] - structured_tdot(c.segment(i, k), Ek_z);
359 Yp.col(i) = structured_upshift<Scalar>(Yp.col(i - 1)) - Yp.col(i - 1)[0] * y + ci * g_k;
360 Zp.col(i) = structured_upshift<Scalar>(Zp.col(i - 1)) - Zp.col(i - 1)[0] * z + di * h_k;
362 const DenseMatrix Sp = shiftBlock(c, 1, k, p);
363 DenseMatrix Gamma = leadingBlock(c, r, p) + Sp.transpose() * Yp.leftCols(p);
364 const RealScalar muY = Yp.leftCols(p).cwiseAbs().maxCoeff();
365 const RealScalar muZ = Zp.leftCols(p).cwiseAbs().maxCoeff();
366 const RealScalar denom = numext::maxi(numext::maxi(RealScalar(1), muY), numext::maxi(muZ, muY * muZ));
367 const RealScalar psi = smallestSingularValue(Gamma) / denom;
373 if (psi > RealScalar(0.1) * m_sMin) {
380 DenseMatrix Gamma = bestGamma;
389 const Index K = k + p;
390 const bool finalStep = (K == n);
392 const DenseMatrix Sp = shiftBlock(c, 1, k, p);
393 const DenseMatrix Rp = shiftBlock(r, 1, k, p);
400 step.EkYp = Yp.leftCols(p).colwise().reverse();
401 step.WspEk = Sp.transpose().rowwise().reverse();
403 m_steps.push_back(step);
406 const DenseVector rhs_e = -r.segment(k + 1, p) - Rp.transpose() * Ek_y;
407 const DenseVector rhs_f = -c.segment(k + 1, p) - Sp.transpose() * Ek_z;
408 const DenseVector e_p = luG.transpose().solve(rhs_e);
409 const DenseVector f_p = luG.solve(rhs_f);
411 DenseVector y_new(K), z_new(K);
412 y_new.head(k) = y + (Zp.leftCols(p) * e_p).reverse();
414 z_new.head(k) = z + (Yp.leftCols(p) * f_p).reverse();
417 const DenseVector y_save = y, z_save = z;
418 const Scalar gamma_save = gamma;
420 gamma = (Scalar(1) - e_p[0] * f_p[0]) * gamma;
422 gamma = rho0 + structured_tdot(c.segment(1, K), y_new);
427 lastWasBlock =
false;
430 gammaPrev = gamma_save;
435 Ypp = Yp.leftCols(p);
436 Zpp = Zp.leftCols(p);
447 m_isInitialized =
true;
Look-ahead Levinson direct solver for general Toeplitz systems.
Definition LookAheadLevinson.h:84
ComputationInfo info() const
Definition LookAheadLevinson.h:158
LookAheadLevinson(const Toeplitz< Scalar, Rows_, Cols_ > &T)
Definition LookAheadLevinson.h:98
LookAheadLevinson()
Definition LookAheadLevinson.h:93
LookAheadLevinson & setMaxBlockSize(Index p)
Definition LookAheadLevinson.h:106
Index maxBlockSize() const
Definition LookAheadLevinson.h:113
RealScalar conditionEstimate() const
Definition LookAheadLevinson.h:165
LookAheadLevinson & compute(const Toeplitz< Scalar, Rows_, Cols_ > &T)
const Solve< LookAheadLevinson, Rhs > solve(const MatrixBase< Rhs > &b) const
An m x n Toeplitz matrix represented by its first column and row.
Definition Toeplitz.h:81
constexpr unsigned int RowMajorBit
Namespace containing all symbols from the Eigen library.
constexpr Index size() const noexcept