|
| 1 | +/* |
| 2 | + * Copyright 2024 INRIA |
| 3 | + */ |
| 4 | + |
| 5 | +#ifndef __eigenpy_decompositions_complete_orthogonal_decomposition_hpp__ |
| 6 | +#define __eigenpy_decompositions_complete_orthogonal_decomposition_hpp__ |
| 7 | + |
| 8 | +#include "eigenpy/eigenpy.hpp" |
| 9 | +#include "eigenpy/utils/scalar-name.hpp" |
| 10 | + |
| 11 | +#include <Eigen/QR> |
| 12 | + |
| 13 | +namespace eigenpy { |
| 14 | + |
| 15 | +template <typename _MatrixType> |
| 16 | +struct CompleteOrthogonalDecompositionSolverVisitor |
| 17 | + : public boost::python::def_visitor< |
| 18 | + CompleteOrthogonalDecompositionSolverVisitor<_MatrixType> > { |
| 19 | + typedef _MatrixType MatrixType; |
| 20 | + typedef typename MatrixType::Scalar Scalar; |
| 21 | + typedef typename MatrixType::RealScalar RealScalar; |
| 22 | + typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1, MatrixType::Options> |
| 23 | + VectorXs; |
| 24 | + typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, |
| 25 | + MatrixType::Options> |
| 26 | + MatrixXs; |
| 27 | + typedef Eigen::CompleteOrthogonalDecomposition<MatrixType> Solver; |
| 28 | + typedef Solver Self; |
| 29 | + |
| 30 | + template <class PyClass> |
| 31 | + void visit(PyClass &cl) const { |
| 32 | + cl.def(bp::init<>(bp::arg("self"), |
| 33 | + "Default constructor.\n" |
| 34 | + "The default constructor is useful in cases in which the " |
| 35 | + "user intends to perform decompositions via " |
| 36 | + "CompleteOrthogonalDecomposition.compute(matrix)")) |
| 37 | + .def(bp::init<Eigen::DenseIndex, Eigen::DenseIndex>( |
| 38 | + bp::args("self", "rows", "cols"), |
| 39 | + "Default constructor with memory preallocation.\n" |
| 40 | + "Like the default constructor but with preallocation of the " |
| 41 | + "internal data according to the specified problem size. ")) |
| 42 | + .def(bp::init<MatrixType>(bp::args("self", "matrix"), |
| 43 | + "Constructs a complete orthogonal " |
| 44 | + "factorization from a given matrix.\n" |
| 45 | + "This constructor computes the complete " |
| 46 | + "orthogonal factorization of the matrix " |
| 47 | + "matrix by calling the method compute().")) |
| 48 | + |
| 49 | + .def("absDeterminant", &Self::absDeterminant, bp::arg("self"), |
| 50 | + "Returns the absolute value of the determinant of the matrix " |
| 51 | + "associated with the complete orthogonal decomposition.\n" |
| 52 | + "It has only linear complexity (that is, O(n) where n is the " |
| 53 | + "dimension of the square matrix) as the complete orthogonal " |
| 54 | + "decomposition has " |
| 55 | + "already been computed.\n" |
| 56 | + "Note: This is only for square matrices.") |
| 57 | + .def("logAbsDeterminant", &Self::logAbsDeterminant, bp::arg("self"), |
| 58 | + "Returns the natural log of the absolute value of the determinant " |
| 59 | + "of the matrix of which *this is the complete orthogonal " |
| 60 | + "decomposition.\n" |
| 61 | + "It has only linear complexity (that is, O(n) where n is the " |
| 62 | + "dimension of the square matrix) as the complete orthogonal " |
| 63 | + "decomposition has " |
| 64 | + "already been computed.\n" |
| 65 | + "Note: This is only for square matrices. This method is useful to " |
| 66 | + "work around the risk of overflow/underflow that's inherent to " |
| 67 | + "determinant computation.") |
| 68 | + .def("dimensionOfKernel", &Self::dimensionOfKernel, bp::arg("self"), |
| 69 | + "Returns the dimension of the kernel of the matrix of which *this " |
| 70 | + "is the complete orthogonal decomposition.") |
| 71 | + .def("info", &Self::info, bp::arg("self"), |
| 72 | + "Reports whether the complete orthogonal factorization was " |
| 73 | + "successful.\n" |
| 74 | + "Note: This function always returns Success. It is provided for " |
| 75 | + "compatibility with other factorization routines.") |
| 76 | + .def("isInjective", &Self::isInjective, bp::arg("self"), |
| 77 | + "Returns true if the matrix associated with this complete " |
| 78 | + "orthogonal decomposition " |
| 79 | + "represents an injective linear map, i.e. has trivial kernel; " |
| 80 | + "false otherwise.\n" |
| 81 | + "\n" |
| 82 | + "Note: This method has to determine which pivots should be " |
| 83 | + "considered nonzero. For that, it uses the threshold value that " |
| 84 | + "you can control by calling setThreshold(threshold).") |
| 85 | + .def("isInvertible", &Self::isInvertible, bp::arg("self"), |
| 86 | + "Returns true if the matrix associated with the complete " |
| 87 | + "orthogonal decomposition " |
| 88 | + "is invertible.\n" |
| 89 | + "\n" |
| 90 | + "Note: This method has to determine which pivots should be " |
| 91 | + "considered nonzero. For that, it uses the threshold value that " |
| 92 | + "you can control by calling setThreshold(threshold).") |
| 93 | + .def("isSurjective", &Self::isSurjective, bp::arg("self"), |
| 94 | + "Returns true if the matrix associated with this complete " |
| 95 | + "orthogonal decomposition " |
| 96 | + "represents a surjective linear map; false otherwise.\n" |
| 97 | + "\n" |
| 98 | + "Note: This method has to determine which pivots should be " |
| 99 | + "considered nonzero. For that, it uses the threshold value that " |
| 100 | + "you can control by calling setThreshold(threshold).") |
| 101 | + .def("maxPivot", &Self::maxPivot, bp::arg("self"), |
| 102 | + "Returns the absolute value of the biggest pivot, i.e. the " |
| 103 | + "biggest diagonal coefficient of U.") |
| 104 | + .def("nonzeroPivots", &Self::nonzeroPivots, bp::arg("self"), |
| 105 | + "Returns the number of nonzero pivots in the complete orthogonal " |
| 106 | + "decomposition. " |
| 107 | + "Here nonzero is meant in the exact sense, not in a fuzzy sense. " |
| 108 | + "So that notion isn't really intrinsically interesting, but it is " |
| 109 | + "still useful when implementing algorithms.") |
| 110 | + .def("rank", &Self::rank, bp::arg("self"), |
| 111 | + "Returns the rank of the matrix associated with the complete " |
| 112 | + "orthogonal " |
| 113 | + "decomposition.\n" |
| 114 | + "\n" |
| 115 | + "Note: This method has to determine which pivots should be " |
| 116 | + "considered nonzero. For that, it uses the threshold value that " |
| 117 | + "you can control by calling setThreshold(threshold).") |
| 118 | + |
| 119 | + .def("setThreshold", |
| 120 | + (Self & (Self::*)(const RealScalar &)) & Self::setThreshold, |
| 121 | + bp::args("self", "threshold"), |
| 122 | + "Allows to prescribe a threshold to be used by certain methods, " |
| 123 | + "such as rank(), who need to determine when pivots are to be " |
| 124 | + "considered nonzero. This is not used for the complete orthogonal " |
| 125 | + "decomposition " |
| 126 | + "itself.\n" |
| 127 | + "\n" |
| 128 | + "When it needs to get the threshold value, Eigen calls " |
| 129 | + "threshold(). By default, this uses a formula to automatically " |
| 130 | + "determine a reasonable threshold. Once you have called the " |
| 131 | + "present method setThreshold(const RealScalar&), your value is " |
| 132 | + "used instead.\n" |
| 133 | + "\n" |
| 134 | + "Note: A pivot will be considered nonzero if its absolute value " |
| 135 | + "is strictly greater than |pivot| ⩽ threshold×|maxpivot| where " |
| 136 | + "maxpivot is the biggest pivot.", |
| 137 | + bp::return_self<>()) |
| 138 | + .def("threshold", &Self::threshold, bp::arg("self"), |
| 139 | + "Returns the threshold that will be used by certain methods such " |
| 140 | + "as rank().") |
| 141 | + |
| 142 | + .def("matrixQTZ", &Self::matrixQTZ, bp::arg("self"), |
| 143 | + "Returns the matrix where the complete orthogonal decomposition " |
| 144 | + "is stored.", |
| 145 | + bp::return_value_policy<bp::copy_const_reference>()) |
| 146 | + .def("matrixT", &Self::matrixT, bp::arg("self"), |
| 147 | + "Returns the matrix where the complete orthogonal decomposition " |
| 148 | + "is stored.", |
| 149 | + bp::return_value_policy<bp::copy_const_reference>()) |
| 150 | + .def("matrixZ", &Self::matrixZ, bp::arg("self"), |
| 151 | + "Returns the matrix Z.") |
| 152 | + |
| 153 | + .def( |
| 154 | + "compute", |
| 155 | + (Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> &matrix)) & |
| 156 | + Solver::compute, |
| 157 | + bp::args("self", "matrix"), |
| 158 | + "Computes the complete orthogonal factorization of given matrix.", |
| 159 | + bp::return_self<>()) |
| 160 | + |
| 161 | + .def("pseudoInverse", pseudoInverse, bp::arg("self"), |
| 162 | + "Returns the pseudo-inverse of the matrix associated with the " |
| 163 | + "complete orthogonal " |
| 164 | + "decomposition.") |
| 165 | + |
| 166 | + .def("solve", &solve<MatrixXs>, bp::args("self", "B"), |
| 167 | + "Returns the solution X of A X = B using the current " |
| 168 | + "decomposition of A where B is a right hand side matrix."); |
| 169 | + } |
| 170 | + |
| 171 | + static void expose() { |
| 172 | + static const std::string classname = |
| 173 | + "CompleteOrthogonalDecomposition" + scalar_name<Scalar>::shortname(); |
| 174 | + expose(classname); |
| 175 | + } |
| 176 | + |
| 177 | + static void expose(const std::string &name) { |
| 178 | + bp::class_<Solver>( |
| 179 | + name.c_str(), |
| 180 | + "This class performs a rank-revealing complete orthogonal " |
| 181 | + "decomposition of a matrix A into matrices P, Q, T, and Z such that:\n" |
| 182 | + "AP=Q[T000]Z" |
| 183 | + "by using Householder transformations. Here, P is a permutation " |
| 184 | + "matrix, Q and Z are unitary matrices and T an upper triangular matrix " |
| 185 | + "of size rank-by-rank. A may be rank deficient.", |
| 186 | + bp::no_init) |
| 187 | + .def(CompleteOrthogonalDecompositionSolverVisitor()) |
| 188 | + .def(IdVisitor<Solver>()); |
| 189 | + } |
| 190 | + |
| 191 | + private: |
| 192 | + template <typename MatrixOrVector> |
| 193 | + static MatrixOrVector solve(const Solver &self, const MatrixOrVector &vec) { |
| 194 | + return self.solve(vec); |
| 195 | + } |
| 196 | + static MatrixXs pseudoInverse(const Self &self) { |
| 197 | + return self.pseudoInverse(); |
| 198 | + } |
| 199 | +}; |
| 200 | + |
| 201 | +} // namespace eigenpy |
| 202 | + |
| 203 | +#endif // ifndef |
| 204 | + // __eigenpy_decompositions_complete_orthogonal_decomposition_hpp__ |
0 commit comments