Program Listing for File llt.hpp

Return to documentation for file (include/nanoeigenpy/decompositions/llt.hpp)

#pragma once

#include "nanoeigenpy/fwd.hpp"
#include "nanoeigenpy/eigen-base.hpp"
#include <Eigen/Cholesky>

namespace nanoeigenpy {
namespace nb = nanobind;
using namespace nb::literals;

template <typename MatrixType, typename MatrixOrVector>
MatrixOrVector solve(const Eigen::LLT<MatrixType> &c,
                     const MatrixOrVector &vec) {
  return c.solve(vec);
}

template <typename _MatrixType>
void exposeLLT(nb::module_ m, const char *name) {
  using MatrixType = _MatrixType;
  using Chol = Eigen::LLT<MatrixType>;
  using Scalar = typename MatrixType::Scalar;
  using VectorType = Eigen::Matrix<Scalar, -1, 1>;

  if (check_registration_alias<Chol>(m)) {
    return;
  }
  nb::class_<Chol>(
      m, name,
      "Standard Cholesky decomposition (LL^T) of a matrix and associated "
      "features.\n\n"
      "This class performs a LL^T Cholesky decomposition of a symmetric, "
      "positive definite matrix A such that A = LL^* = U^*U, where L is "
      "lower triangular.\n\n"
      "While the Cholesky decomposition is particularly useful to solve "
      "selfadjoint problems like D^*D x = b, for that purpose, we "
      "recommend "
      "the Cholesky decomposition without square root which is more stable "
      "and even faster. Nevertheless, this standard Cholesky decomposition "
      "remains useful in many other situations like generalised eigen "
      "problems with hermitian matrices.")

      .def(nb::init<>(), "Default constructor.")
      .def(nb::init<Eigen::DenseIndex>(), "size"_a,
           "Default constructor with memory preallocation.")
      .def(nb::init<const MatrixType &>(), "matrix"_a,
           "Constructs a LLT factorization from a given matrix.")

      .def(EigenBaseVisitor())

      .def(
          "matrixL", [](const Chol &c) -> MatrixType { return c.matrixL(); },
          "Returns the lower triangular matrix L.")
      .def(
          "matrixU", [](const Chol &c) -> MatrixType { return c.matrixU(); },
          "Returns the upper triangular matrix U.")
      .def("matrixLLT", &Chol::matrixLLT,
           "Returns the LLT decomposition matrix made of the lower matrix "
           "L, plus the remaining part that corresponds to A.",
           nb::rv_policy::reference_internal)

#if EIGEN_VERSION_AT_LEAST(3, 3, 90)
      .def(
          "rankUpdate",
          [](Chol &c, const VectorType &w, Scalar sigma) -> Chol & {
            return c.rankUpdate(w, sigma);
          },
          "If LL^* = A, then it becomes A + sigma * v v^*", "w"_a, "sigma"_a,
          nb::rv_policy::reference)
#else
      .def(
          "rankUpdate",
          [](Chol &c, const VectorType &w, Scalar sigma) -> Chol & {
            return c.rankUpdate(w, sigma);
          },
          "If LL^* = A, then it becomes A + sigma * v v^*", "w"_a, "sigma"_a)
#endif

      .def("adjoint", &Chol::adjoint,
           "Returns the adjoint, that is, a reference to the decomposition "
           "itself as if the underlying matrix is self-adjoint.",
           nb::rv_policy::reference)

      .def(
          "compute",
          [](Chol &c, const MatrixType &matrix) -> Chol & {
            return c.compute(matrix);
          },
          "matrix"_a, "Computes the LDLT of given matrix.",
          nb::rv_policy::reference)
      .def("info", &Chol::info,
           "NumericalIssue if the input contains INF or NaN values or "
           "overflow occured. Returns Success otherwise.")

      .def("rcond", &Chol::rcond,
           "Returns an estimate of the reciprocal condition number of the "
           "matrix.")

      .def("reconstructedMatrix", &Chol::reconstructedMatrix,
           "Returns the matrix represented by the decomposition, i.e., it "
           "returns the product: L L^*. This function is provided for debug "
           "purpose.")

      .def(
          "solve",
          [](const Chol &c, const VectorType &b) -> VectorType {
            return solve(c, b);
          },
          "b"_a,
          "Returns the solution x of A x = b using the current "
          "decomposition of A.")
      .def(
          "solve",
          [](const Chol &c, const MatrixType &B) -> MatrixType {
            return solve(c, B);
          },
          "B"_a,
          "Returns the solution X of A X = B using the current "
          "decomposition of A where B is a right hand side matrix.")

      .def(IdVisitor());
}

}  // namespace nanoeigenpy