proxsuite-nlp  0.10.0
A primal-dual augmented Lagrangian-type solver for nonlinear programming on manifolds.
Loading...
Searching...
No Matches
bunchkaufman.hpp
Go to the documentation of this file.
1
4#pragma once
5
6#include "Eigen/Core"
7
8namespace Eigen {
9template <typename MatrixType_, int UpLo_ = Lower> struct BunchKaufman;
10
11namespace internal {
12template <typename MatrixType_, int UpLo_>
13struct traits<BunchKaufman<MatrixType_, UpLo_>> : traits<MatrixType_> {
14 typedef MatrixXpr XprKind;
15 typedef SolverStorage StorageKind;
16 typedef int StorageIndex;
17 enum { Flags = 0 };
18};
19
20template <typename MatrixType, typename IndicesType>
21ComputationInfo bunch_kaufman_in_place_unblocked(MatrixType &a,
22 IndicesType &pivots,
23 Index &pivot_count) {
24 using Scalar = typename MatrixType::Scalar;
25 using Real = typename Eigen::NumTraits<Scalar>::Real;
26 const Real alpha = (Real(1) + numext::sqrt(Real(17))) / Real(8);
27 using std::swap;
28
29 pivot_count = 0;
30
31 const Index n = a.rows();
32 if (n == 0) {
33 return Success;
34 } else if (n == 1) {
35 if (numext::abs(numext::real(a(0, 0))) == Real(0)) {
36 return NumericalIssue;
37 } else {
38 a(0, 0) = Real(1) / numext::real(a(0, 0));
39 return Success;
40 }
41 }
42
43 Index k = 0;
44 while (k < n) {
45 Index k_step = 1;
46 Real abs_akk = numext::abs(numext::real(a(k, k)));
47 Index imax = 0;
48 Real colmax = Real(0);
49
50 if (k + 1 < n) {
51 colmax = a.col(k).segment(k + 1, n - k - 1).cwiseAbs().maxCoeff(&imax);
52 }
53 imax += k + 1;
54
55 Index kp;
56 if (numext::maxi(abs_akk, colmax) == Real(0)) {
57 return NumericalIssue;
58 } else {
59 if (abs_akk >= colmax * alpha) {
60 kp = k;
61 } else {
62 Real rowmax = Real(0);
63 if (imax - k > 0) {
64 rowmax = a.row(imax).segment(k, imax - k).cwiseAbs().maxCoeff();
65 }
66 if (n - imax - 1 > 0) {
67 rowmax = numext::maxi(rowmax, a.col(imax)
68 .segment(imax + 1, n - imax - 1)
69 .cwiseAbs()
70 .maxCoeff());
71 }
72
73 if (abs_akk >= (alpha * colmax) * (colmax / rowmax)) {
74 kp = k;
75 } else if (numext::abs(numext::real(a(imax, imax))) >= alpha * rowmax) {
76 kp = imax;
77 } else {
78 kp = imax;
79 k_step = 2;
80 }
81 }
82
83 Index kk = k + k_step - 1;
84 if (kp != kk) {
85 pivot_count += 1;
86 a.col(kk)
87 .segment(kp + 1, n - kp - 1)
88 .swap(a.col(kp).segment(kp + 1, n - kp - 1));
89
90 for (Index j = kk + 1; j < kp; ++j) {
91 Scalar tmp = a(j, kk);
92 a(j, kk) = numext::conj(a(kp, j));
93 a(kp, j) = numext::conj(tmp);
94 }
95 a(kp, kk) = numext::conj(a(kp, kk));
96 swap(a(kk, kk), a(kp, kp));
97
98 if (k_step == 2) {
99 swap(a(k + 1, k), a(kp, k));
100 }
101 }
102
103 if (k_step == 1) {
104 Real d11 = Real(1) / numext::real(a(k, k));
105 a(k, k) = Scalar(d11);
106
107 auto x = a.middleRows(k + 1, n - k - 1).col(k);
108 auto trailing =
109 a.middleRows(k + 1, n - k - 1).middleCols(k + 1, n - k - 1);
110
111 for (Index j = 0; j < n - k - 1; ++j) {
112 Scalar d11xj = numext::conj(x(j)) * d11;
113 for (Index i = j; i < n - k - 1; ++i) {
114 Scalar xi = x(i);
115 trailing(i, j) -= d11xj * xi;
116 }
117 trailing(j, j) = Scalar(numext::real(trailing(j, j)));
118 }
119
120 x *= d11;
121 } else {
122 Real d21_abs = numext::abs(a(k + 1, k));
123 Real d21_inv = Real(1) / d21_abs;
124 Real d11 = d21_inv * numext::real(a(k + 1, k + 1));
125 Real d22 = d21_inv * numext::real(a(k, k));
126
127 Real t = Real(1) / ((d11 * d22) - Real(1));
128 Real d = t * d21_inv;
129 Scalar d21 = a(k + 1, k) * d21_inv;
130
131 a(k, k) = Scalar(d11 * d);
132 a(k + 1, k) = -d21 * d;
133 a(k + 1, k + 1) = Scalar(d22 * d);
134
135 for (Index j = k + 2; j < n; ++j) {
136 Scalar wk = ((a(j, k) * d11) - (a(j, k + 1) * d21)) * d;
137 Scalar wkp1 =
138 ((a(j, k + 1) * d22) - (a(j, k) * numext::conj(d21))) * d;
139
140 for (Index i = j; i < n; ++i) {
141 a(i, j) -=
142 a(i, k) * numext::conj(wk) + a(i, k + 1) * numext::conj(wkp1);
143 }
144 a(j, j) = Scalar(numext::real(a(j, j)));
145
146 a(j, k) = wk;
147 a(j, k + 1) = wkp1;
148 }
149 }
150 }
151
152 // pivots matrix store int by default
153 // Like Eigen, we assume that we will never
154 // have a matrix that will have more rows/columns
155 // than int can old
156 if (k_step == 1) {
157 pivots[k] = static_cast<int>(kp);
158 } else {
159 pivots[k] = static_cast<int>(-1 - kp);
160 pivots[k + 1] = static_cast<int>(-1 - kp);
161 }
162
163 k += k_step;
164 }
165
166 return Success;
167}
168
169template <typename MatrixType, typename WType, typename IndicesType>
170ComputationInfo
171bunch_kaufman_in_place_one_block(MatrixType &a, WType &w, IndicesType &pivots,
172 Index &pivot_count, Index &processed_cols) {
173 using Scalar = typename MatrixType::Scalar;
174 using Real = typename Eigen::NumTraits<Scalar>::Real;
175
176 pivot_count = 0;
177 processed_cols = 0;
178 Real alpha = (Real(1) + numext::sqrt(Real(17))) / Real(8);
179
180 Index n = a.rows();
181 if (n == 0) {
182 return Success;
183 }
184
185 Index nb = w.cols();
186 Index k = 0;
187 while (k < n && k + 1 < nb) {
188 w.col(k).segment(k, n - k) = a.col(k).segment(k, n - k);
189 {
190 auto w_row = w.row(k).segment(0, k);
191 auto w_col = w.col(k).segment(k, n - k);
192 w_col.noalias() -= a.block(k, 0, n - k, k) * w_row.transpose();
193 }
194 w(k, k) = Scalar(numext::real(w(k, k)));
195
196 Index k_step = 1;
197 Real abs_akk = numext::abs(numext::real(w(k, k)));
198 Index imax = 0;
199 Real colmax = Real(0);
200
201 if (k + 1 < n) {
202 colmax = w.col(k).segment(k + 1, n - k - 1).cwiseAbs().maxCoeff(&imax);
203 }
204 imax += k + 1;
205
206 Index kp;
207 if (numext::maxi(abs_akk, colmax) == Real(0)) {
208 return NumericalIssue;
209 } else {
210 if (abs_akk >= colmax * alpha) {
211 kp = k;
212 } else {
213 w.col(k + 1).segment(k, imax - k) =
214 a.row(imax).segment(k, imax - k).adjoint();
215 w.col(k + 1).segment(imax, n - imax) =
216 a.col(imax).segment(imax, n - imax);
217
218 {
219 auto w_row = w.row(imax).segment(0, k);
220 auto w_col = w.col(k + 1).segment(k, n - k);
221 w_col.noalias() -= a.block(k, 0, n - k, k) * w_row.transpose();
222 }
223 w(imax, k + 1) = Scalar(numext::real(w(imax, k + 1)));
224
225 Real rowmax = Real(0);
226 if (imax - k > 0) {
227 rowmax = w.col(k + 1).segment(k, imax - k).cwiseAbs().maxCoeff();
228 }
229 if (n - imax - 1 > 0) {
230 rowmax = numext::maxi(rowmax, w.col(k + 1)
231 .segment(imax + 1, n - imax - 1)
232 .cwiseAbs()
233 .maxCoeff());
234 }
235
236 if (abs_akk >= (alpha * colmax) * (colmax / rowmax)) {
237 kp = k;
238 } else if (numext::abs(numext::real(w(imax, k + 1))) >=
239 alpha * rowmax) {
240 kp = imax;
241 w.col(k).segment(k, n - k) = w.col(k + 1).segment(k, n - k);
242 } else {
243 kp = imax;
244 k_step = 2;
245 }
246 }
247
248 Index kk = k + k_step - 1;
249 if (kp != kk) {
250 pivot_count += 1;
251
252 a(kp, kp) = a(kk, kk);
253 for (Index j = kk + 1; j < kp; ++j) {
254 a(kp, j) = numext::conj(a(j, kk));
255 }
256 a.col(kp).segment(kp + 1, n - kp - 1) =
257 a.col(kk).segment(kp + 1, n - kp - 1);
258 a.row(kk).segment(0, k).swap(a.row(kp).segment(0, k));
259 w.row(kk).segment(0, kk + 1).swap(w.row(kp).segment(0, kk + 1));
260 }
261
262 if (k_step == 1) {
263 a.col(k).segment(k, n - k) = w.col(k).segment(k, n - k);
264
265 Real d11 = Real(1) / numext::real(w(k, k));
266 a(k, k) = Scalar(d11);
267 auto x = a.middleRows(k + 1, n - k - 1).col(k);
268 x *= d11;
269 w.col(k).segment(k + 1, n - k - 1) =
270 w.col(k).segment(k + 1, n - k - 1).conjugate();
271 } else {
272 Real d21_abs = numext::abs(w(k + 1, k));
273 Real d21_inv = Real(1) / d21_abs;
274 Real d11 = d21_inv * numext::real(w(k + 1, k + 1));
275 Real d22 = d21_inv * numext::real(w(k, k));
276
277 Real t = Real(1) / ((d11 * d22) - Real(1));
278 Scalar d21 = w(k + 1, k) * d21_inv;
279 Real d = t * d21_inv;
280
281 a(k, k) = Scalar(d11 * d);
282 a(k + 1, k) = -d21 * d;
283 a(k + 1, k + 1) = Scalar(d22 * d);
284
285 for (Index j = k + 2; j < n; ++j) {
286 Scalar wk = ((w(j, k) * d11) - (w(j, k + 1) * d21)) * d;
287 Scalar wkp1 =
288 ((w(j, k + 1) * d22) - (w(j, k) * numext::conj(d21))) * d;
289
290 a(j, k) = wk;
291 a(j, k + 1) = wkp1;
292 }
293
294 w.col(k).segment(k + 1, n - k - 1) =
295 w.col(k).segment(k + 1, n - k - 1).conjugate();
296 w.col(k + 1).segment(k + 2, n - k - 2) =
297 w.col(k + 1).segment(k + 2, n - k - 2).conjugate();
298 }
299 }
300
301 // pivots matrix store int by default
302 // Like Eigen, we assume that we will never
303 // have a matrix that will have more rows/columns
304 // than int can old
305 if (k_step == 1) {
306 pivots[k] = static_cast<int>(kp);
307 } else {
308 pivots[k] = static_cast<int>(-1 - kp);
309 pivots[k + 1] = static_cast<int>(-1 - kp);
310 }
311
312 k += k_step;
313 }
314
315 auto a_left = a.bottomRows(n - k).leftCols(k);
316 auto a_right = a.bottomRows(n - k).rightCols(n - k);
317
318 a_right.template triangularView<Lower>() -=
319 a_left * w.block(k, 0, n - k, k).transpose();
320 Index j = k - 1;
321 processed_cols = k;
322
323 while (true) {
324 Index jj = j;
325 Index jp = pivots[j];
326 if (jp < 0) {
327 jp = -1 - jp;
328 j -= 1;
329 }
330
331 if (j == 0) {
332 return Success;
333 }
334 j -= 1;
335 if (jp != jj) {
336 a.row(jp).segment(0, j + 1).swap(a.row(jj).segment(0, j + 1));
337 }
338 if (j == 0) {
339 return Success;
340 }
341 }
342}
343
344template <typename MatrixType, typename VecType, typename IndicesType,
345 typename WorkspaceType>
346ComputationInfo bunch_kaufman_in_place(MatrixType &a, VecType &subdiag,
347 IndicesType &pivots, WorkspaceType &w,
348 Index &pivot_count) {
349 Index n = a.rows();
350
351 const Index blocksize = w.cols();
352
353 Index k = 0;
354 while (k < n) {
355 Index kb = 0;
356 Index k_pivot_count = 0;
357 auto a_block = a.block(k, k, n - k, n - k);
358 auto pivots_block = pivots.segment(k, n - k);
359 ComputationInfo info = InvalidInput;
360 if (blocksize != 0 && blocksize < n - k) {
361 info = internal::bunch_kaufman_in_place_one_block(
362 a_block, w, pivots_block, k_pivot_count, kb);
363 } else {
364 info = internal::bunch_kaufman_in_place_unblocked(a_block, pivots_block,
365 k_pivot_count);
366 kb = n - k;
367 }
368 if (info != Success) {
369 return info;
370 }
371
372 for (Index j = k; j < k + kb; ++j) {
373 auto &p = pivots.coeffRef(j);
374 // pivots matrix store int by default
375 // Like Eigen, we assume that we will never
376 // have a matrix that will have more rows/columns
377 // than int can old
378 if (p >= 0) {
379 p += static_cast<int>(k);
380 } else {
381 p -= static_cast<int>(k);
382 }
383 }
384
385 pivot_count += k_pivot_count;
386 k += kb;
387 }
388
389 using Scalar = typename MatrixType::Scalar;
390
391 k = 0;
392 while (k < n) {
393 if (pivots[k] < 0) {
394 subdiag(k) = a(k + 1, k);
395 subdiag(k + 1) = Scalar(0);
396 a(k + 1, k) = Scalar(0);
397 k += 2;
398 } else {
399 subdiag(k) = Scalar(0);
400 k += 1;
401 }
402 }
403
404 k = 0;
405 while (k < n) {
406 Index p = pivots[k];
407 if (p < 0) {
408 p = -1 - p;
409 a.row(k + 1).segment(0, k).swap(a.row(p).segment(0, k));
410 k += 2;
411 } else {
412 a.row(k).segment(0, k).swap(a.row(p).segment(0, k));
413 k += 1;
414 }
415 }
416
417 return Success;
418}
419
420template <typename MatrixType, bool Conjugate> struct BK_Traits;
421
422template <typename MatrixType> struct BK_Traits<MatrixType, false> {
423 typedef TriangularView<const MatrixType, UnitLower> MatrixL;
424 typedef TriangularView<const typename MatrixType::AdjointReturnType,
425 UnitUpper>
426 MatrixU;
427 static inline MatrixL getL(const MatrixType &m) { return MatrixL(m); }
428 static inline MatrixU getU(const MatrixType &m) {
429 return MatrixU(m.adjoint());
430 }
431};
432
433template <typename MatrixType> struct BK_Traits<MatrixType, true> {
434 typedef typename MatrixType::ConjugateReturnType ConjugateReturnType;
435 typedef TriangularView<const ConjugateReturnType, UnitLower> MatrixL;
436 typedef TriangularView<const typename MatrixType::TransposeReturnType,
437 UnitUpper>
438 MatrixU;
439 static inline MatrixL getL(const MatrixType &m) {
440 return MatrixL(m.conjugate());
441 }
442 static inline MatrixU getU(const MatrixType &m) {
443 return MatrixU(m.transpose());
444 }
445};
446
447template <bool Conjugate, typename MatrixType, typename VecType,
448 typename IndicesType, typename Rhs>
449void bunch_kaufman_solve_in_place(MatrixType const &L, VecType const &subdiag,
450 IndicesType const &pivots, Rhs &x) {
451 Index n = L.rows();
452
453 Index k;
454
455 k = 0;
456 while (k < n) {
457 Index p = pivots(k);
458 if (p < 0) {
459 p = -1 - p;
460 x.row(k + 1).swap(x.row(p));
461 k += 2;
462 } else {
463 x.row(k).swap(x.row(p));
464 k += 1;
465 }
466 }
467
468 using Traits = BK_Traits<MatrixType, Conjugate>;
469
470 Traits::getL(L).solveInPlace(x);
471
472 k = 0;
473 while (k < n) {
474 Index p = pivots(k);
475 if (p < 0) {
476 using Scalar = typename MatrixType::Scalar;
477 using Real = typename Eigen::NumTraits<Scalar>::Real;
478
479 Scalar akp1k = subdiag(k);
480 Real ak = numext::real(L(k, k));
481 Real akp1 = numext::real(L(k + 1, k + 1));
482
483 if (Conjugate) {
484 akp1k = numext::conj(akp1k);
485 }
486
487 for (Index j = 0; j < x.cols(); ++j) {
488 Scalar xk = x(k, j);
489 Scalar xkp1 = x(k + 1, j);
490
491 x(k, j) = xk * ak + xkp1 * numext::conj(akp1k);
492 x(k + 1, j) = xkp1 * akp1 + xk * akp1k;
493 }
494
495 k += 2;
496 } else {
497 x.row(k) *= numext::real(L(k, k));
498 k += 1;
499 }
500 }
501
502 Traits::getU(L).solveInPlace(x);
503
504 k = n;
505 while (k > 0) {
506 k -= 1;
507 Index p = pivots(k);
508 if (p < 0) {
509 p = -1 - p;
510 x.row(k).swap(x.row(p));
511 k -= 1;
512 } else {
513 x.row(k).swap(x.row(p));
514 }
515 }
516}
517} // namespace internal
518
519template <typename MatrixType_, int UpLo_>
520struct BunchKaufman : SolverBase<BunchKaufman<MatrixType_, UpLo_>> {
521 enum {
522 MaxRowsAtCompileTime = MatrixType_::MaxRowsAtCompileTime,
523 MaxColsAtCompileTime = MatrixType_::MaxColsAtCompileTime,
524 UpLo = UpLo_
525 };
526 using MatrixType = MatrixType_;
527 using PlainObject = typename MatrixType::PlainObject;
528 using Base = SolverBase<BunchKaufman>;
529 static constexpr Index BlockSize = 32;
530 EIGEN_GENERIC_PUBLIC_INTERFACE(BunchKaufman)
531 using VecType = Matrix<Scalar, RowsAtCompileTime, 1, Eigen::DontAlign,
533 friend class SolverBase<BunchKaufman>;
534
536 typename Transpositions<RowsAtCompileTime,
539 PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime>;
540
542 : m_matrix(), m_subdiag(), m_pivot_count(0), m_pivots(),
543 m_isInitialized(false), m_info(ComputationInfo::InvalidInput),
544 m_blocksize(), m_workspace() {}
545 explicit BunchKaufman(Index size)
546 : m_matrix(size, size), m_subdiag(size), m_pivot_count(0), m_pivots(size),
547 m_isInitialized(false), m_info(ComputationInfo::InvalidInput),
548 m_blocksize(size <= BlockSize ? 0 : BlockSize),
549 m_workspace(size, m_blocksize) {}
550
551 template <typename InputType>
552 explicit BunchKaufman(const EigenBase<InputType> &matrix)
553 : m_matrix(matrix.rows(), matrix.cols()), m_subdiag(matrix.rows()),
554 m_pivot_count(0), m_pivots(matrix.rows()), m_isInitialized(false),
555 m_info(ComputationInfo::InvalidInput),
556 m_blocksize(matrix.rows() <= BlockSize ? 0 : BlockSize),
557 m_workspace(matrix.rows(), m_blocksize) {
558 this->compute(matrix.derived());
559 }
560
561 // EIGEN_DEVICE_FUNC inline EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT
562 // { return m_matrix.rows(); }
563 EIGEN_DEVICE_FUNC inline Index rows() const EIGEN_NOEXCEPT {
564 return m_matrix.rows();
565 }
566 // EIGEN_DEVICE_FUNC inline EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT
567 // { return m_matrix.cols(); }
568 EIGEN_DEVICE_FUNC inline Index cols() const EIGEN_NOEXCEPT {
569 return m_matrix.cols();
570 }
571
572 inline const MatrixType &matrixLDLT() const { return m_matrix; }
573
574 inline const IndicesType &pivots() const { return m_pivots; }
575
576 inline const VecType &subdiag() const { return m_subdiag; }
577
578 template <typename InputType>
579 BunchKaufman &compute(const EigenBase<InputType> &matrix);
580
581 ComputationInfo info() const { return m_info; }
582
583#ifdef EIGEN_PARSED_BY_DOXYGEN
584 template <typename Rhs>
585 inline const Solve<LDLT, Rhs> solve(const MatrixBase<Rhs> &b) const;
586#endif
587
588#ifndef EIGEN_PARSED_BY_DOXYGEN
589 template <typename RhsType, typename DstType>
590 void _solve_impl(const RhsType &rhs, DstType &dst) const;
591
592 template <bool Conjugate, typename RhsType, typename DstType>
593 void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
594
595 template <typename RhsType>
596 bool solveInPlace(Eigen::MatrixBase<RhsType> &bAndX) const;
597#endif
598
599private:
600 MatrixType m_matrix;
601 VecType m_subdiag;
602 Index m_pivot_count;
603 IndicesType m_pivots;
604 bool m_isInitialized;
605 ComputationInfo m_info;
606 Index m_blocksize;
607 PlainObject m_workspace;
608};
609
610#ifndef EIGEN_PARSED_BY_DOXYGEN
611template <typename MatrixType_, int UpLo_>
612template <typename RhsType, typename DstType>
614 DstType &dst) const {
615 dst = rhs;
616 internal::bunch_kaufman_solve_in_place<false>(this->m_matrix, this->m_subdiag,
617 this->m_pivots, dst);
618}
619
620template <typename MatrixType_, int UpLo_>
621template <bool Conjugate, typename RhsType, typename DstType>
623 const RhsType &rhs, DstType &dst) const {
624 dst = rhs;
625 internal::bunch_kaufman_solve_in_place<!Conjugate>(
626 this->m_matrix, this->m_subdiag, this->m_pivots, dst);
627}
628
629template <typename MatrixType_, int UpLo_>
630template <typename RhsType>
632 Eigen::MatrixBase<RhsType> &bAndX) const {
633 bAndX = this->solve(bAndX);
634
635 return true;
636}
637#endif
638
639template <typename MatrixType_, int UpLo_>
640template <typename InputType>
642BunchKaufman<MatrixType_, UpLo_>::compute(const EigenBase<InputType> &a) {
643 eigen_assert(a.rows() == a.cols());
644 Index n = a.rows();
645 this->m_matrix.resize(n, n);
646 this->m_subdiag.resize(n);
647 this->m_pivots.resize(n);
648
649 this->m_matrix.setZero();
650 this->m_subdiag.setZero();
651 this->m_pivots.setZero();
652 this->m_blocksize = n <= BlockSize ? 0 : BlockSize;
653 this->m_workspace.setZero(n, this->m_blocksize);
654
655 this->m_matrix.template triangularView<Lower>() =
656 a.derived().template triangularView<UpLo_>();
657 this->m_info = internal::bunch_kaufman_in_place(
658 this->m_matrix, this->m_subdiag, this->m_pivots, this->m_workspace,
659 this->m_pivot_count);
660 this->m_isInitialized = true;
661 return *this;
662}
663} // namespace Eigen
typename Transpositions< RowsAtCompileTime, MaxRowsAtCompileTime >::IndicesType IndicesType
EIGEN_DEVICE_FUNC Index cols() const EIGEN_NOEXCEPT
SolverBase< BunchKaufman > Base
static constexpr Index BlockSize
typename MatrixType::PlainObject PlainObject
const MatrixType & matrixLDLT() const
void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const
BunchKaufman(const EigenBase< InputType > &matrix)
const IndicesType & pivots() const
void _solve_impl(const RhsType &rhs, DstType &dst) const
const VecType & subdiag() const
bool solveInPlace(Eigen::MatrixBase< RhsType > &bAndX) const
EIGEN_DEVICE_FUNC Index rows() const EIGEN_NOEXCEPT
ComputationInfo info() const
BunchKaufman & compute(const EigenBase< InputType > &matrix)
PermutationMatrix< RowsAtCompileTime, MaxRowsAtCompileTime > PermutationType
Matrix< Scalar, RowsAtCompileTime, 1, Eigen::DontAlign, MaxRowsAtCompileTime > VecType