tinyopt 700
Tinyopt, a lightweight, header only optimization library
Loading...
Searching...
No Matches
covariance.h
1// Copyright 2026 Julien Michot.
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include <optional>
7#include <type_traits>
8
9#include <Eigen/SparseCholesky>
10#include <tinyopt/types.h>
11
12namespace tinyopt {
13
14template <typename Derived>
15std::optional<Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime,
16 Derived::ColsAtCompileTime>>
17DenseInvCov(const MatrixBase<Derived> &m) {
18 using MatType =
19 Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime>;
20 if constexpr (Derived::ColsAtCompileTime == 1) {
21 return MatType(m.cwiseInverse().asDiagonal());
22 } else if (m.cols() == 1) {
23 return MatType(m.inverse());
24 } else if (m.cols() > 0) {
25 const auto &chol = m.template selfadjointView<Upper>().ldlt();
26 if (chol.info() == Eigen::Success && chol.isPositive())
27 return chol.solve(MatType::Identity(m.rows(), m.cols()));
28 }
29 return std::nullopt;
30}
31
32template <typename Derived>
33auto InvCov(const MatrixBase<Derived> &m) {
34 return DenseInvCov(m);
35}
36
37template <typename T>
38std::optional<SparseMatrix<typename T::Scalar>> SparseInvCov(
39 const T &m, typename T::Scalar retry_with_shift_offset = typename T::Scalar(0.0)) {
40 using Scalar = typename T::Scalar;
41 if (m.size() == 0) return std::nullopt;
42 Eigen::SimplicialLDLT<SparseMatrix<Scalar>, Eigen::Upper> solver;
43 solver.compute(m);
44 if (solver.info() != Eigen::Success) {
45 if (retry_with_shift_offset > 0 && solver.info() == Eigen::NumericalIssue) {
46 solver.setShift(retry_with_shift_offset);
47 solver.compute(m);
48 }
49 if (solver.info() != Eigen::Success) return std::nullopt;
50 }
51 SparseMatrix<Scalar> identity(m.rows(), m.cols());
52 identity.setIdentity();
53 auto inverse = solver.solve(identity);
54 if (solver.info() != Eigen::Success) return std::nullopt;
55 return inverse;
56}
57
58template <typename Scalar>
59std::optional<SparseMatrix<Scalar>> InvCov(
60 const SparseMatrix<Scalar> &m, Scalar retry_with_shift_offset = Scalar(0.0)) {
61 return SparseInvCov(m, retry_with_shift_offset);
62}
63
64template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
65auto InvCov(const Block<XprType, BlockRows, BlockCols, InnerPanel> &m) {
66 using Scalar = typename XprType::Scalar;
67 if constexpr (std::is_same_v<std::decay_t<XprType>, SparseMatrix<Scalar>>)
68 return SparseInvCov(m);
69 else
70 return DenseInvCov(m);
71}
72
73} // namespace tinyopt