2 #include <Caribou/config.h>
3 #include <Caribou/macros.h>
4 #include <Caribou/traits.h>
5 #include <sofa/defaulttype/BaseMatrix.h>
7 #include <Eigen/Sparse>
9 namespace SofaCaribou::Algebra {
49 template <
typename Derived,
typename Enable =
void>
53 std::is_base_of_v<Eigen::EigenBase<std::decay_t<Derived> >, std::decay_t<Derived> >,
54 "The class template argument 'Derived' must be derived from Eigen::EigenBase<Derived>."
58 using EigenType = std::remove_cv_t<std::remove_reference_t<Derived>>;
59 using Base = sofa::defaulttype::BaseMatrix;
60 using Index = Base::Index;
69 explicit EigenMatrix(std::remove_reference_t<Derived> & eigen_matrix) : p_eigen_matrix(eigen_matrix) {}
76 EigenMatrix(Eigen::Index rows, Eigen::Index cols) : p_eigen_matrix(rows, cols) {}
79 inline Index rowSize() const final {
return p_eigen_matrix.rows(); }
80 inline Index colSize() const final {
return p_eigen_matrix.cols(); }
81 inline Real element(Index i, Index j)
const final {
return p_eigen_matrix(i,j); }
84 inline void resize(Index nbRow, Index nbCol)
final { p_eigen_matrix.setConstant(nbRow, nbCol, 0); }
87 inline void clear()
override {p_eigen_matrix.setZero();}
90 inline void set(Index i, Index j,
double v)
final {
91 p_eigen_matrix(i, j) = v;
95 inline void add(Index i, Index j,
double v)
final {
96 p_eigen_matrix(i, j) += v;
100 inline void add(Index i, Index j,
const sofa::defaulttype::Mat3x3d & m)
override { add_block<double, 3, 3>(i, j, m);}
101 inline void add(Index i, Index j,
const sofa::defaulttype::Mat3x3f & m)
override { add_block<float, 3, 3>(i, j, m);}
102 inline void add(Index i, Index j,
const sofa::defaulttype::Mat2x2d & m)
override { add_block<double, 2, 2>(i, j, m);}
103 inline void add(Index i, Index j,
const sofa::defaulttype::Mat2x2f & m)
override { add_block<float, 2, 2>(i, j, m);}
107 p_eigen_matrix.row(i).setZero();
112 p_eigen_matrix.middleRows(imin, (imax-imin)+1).setZero();
117 p_eigen_matrix.col(i).setZero();
122 p_eigen_matrix.middleCols(imin, (imax-imin)+1).setZero();
126 const EigenType &
matrix()
const {
return p_eigen_matrix;}
130 template <
typename Scalar,
unsigned int nrows,
unsigned int ncols>
131 void add_block(Index i, Index j,
const sofa::defaulttype::Mat<nrows, ncols, Scalar> & m) {
132 const Eigen::Map<const Eigen::Matrix<Scalar, nrows, ncols, Eigen::RowMajor>> block(&(m[0][0]));
133 p_eigen_matrix.block(i, j, nrows, ncols) += block.
template cast<typename EigenType::Scalar>();
137 Derived p_eigen_matrix;
143 template <
typename Derived>
144 class EigenMatrix<Derived, CLASS_REQUIRES(std::is_base_of_v<Eigen::SparseMatrixBase<std::decay_t<Derived>>, std::decay_t<Derived>>)> :
public sofa::defaulttype::BaseMatrix
148 using EigenType = std::remove_cv_t<std::remove_reference_t<Derived>>;
149 using Base = sofa::defaulttype::BaseMatrix;
150 using Index = Base::Index;
159 explicit EigenMatrix(std::remove_reference_t<Derived> & eigen_matrix) : p_eigen_matrix(eigen_matrix) {}
166 EigenMatrix(Eigen::Index rows, Eigen::Index cols) : p_eigen_matrix(rows, cols) {}
169 inline Index rowSize() const final {
return p_eigen_matrix.rows(); }
170 inline Index colSize() const final {
return p_eigen_matrix.cols(); }
180 inline void set_symmetric(
bool is_symmetric) { p_is_symmetric = is_symmetric; }
187 inline Real
element(Index i, Index j)
const final {
188 caribou_assert(p_initialized &&
"Accessing an element on an uninitialized matrix.");
189 return this->p_eigen_matrix.coeff(i,j);
193 inline void resize(Index nbRow, Index nbCol)
final {
195 this->p_eigen_matrix.resize(nbRow, nbCol);
196 p_initialized =
false;
202 this->p_eigen_matrix.setZero();
203 p_initialized =
false;
214 inline void set(Index i, Index j,
double v)
final {
215 if (not p_initialized) {
219 this->p_eigen_matrix.coeffRef(i, j) = v;
228 inline void add(Index i, Index j,
double v)
final {
232 if (not p_initialized) {
233 p_triplets.emplace_back(i, j, v);
235 p_eigen_matrix.coeffRef(i, j) += v;
246 if (not p_initialized) {
249 p_eigen_matrix.makeCompressed();
254 inline void add(Index i, Index j,
const sofa::defaulttype::Mat3x3d & m)
override { add_block<double, 3, 3>(i, j, m);}
255 inline void add(Index i, Index j,
const sofa::defaulttype::Mat3x3f & m)
override { add_block<float, 3, 3>(i, j, m);}
256 inline void add(Index i, Index j,
const sofa::defaulttype::Mat2x2d & m)
override { add_block<double, 2, 2>(i, j, m);}
257 inline void add(Index i, Index j,
const sofa::defaulttype::Mat2x2f & m)
override { add_block<float, 2, 2>(i, j, m);}
261 if (not p_initialized) {
265 using StorageIndex =
typename EigenType::StorageIndex;
266 using Scalar =
typename EigenType::Scalar;
268 if constexpr (EigenType::IsRowMajor) {
269 const auto & start = p_eigen_matrix.outerIndexPtr()[row_id];
270 const auto & end = p_eigen_matrix.outerIndexPtr()[row_id+1];
271 memset(&(p_eigen_matrix.data().valuePtr()[start]),
static_cast<const Scalar &
>(0), (end-start)*
sizeof(Scalar));
273 for (
int col_id=0; col_id<p_eigen_matrix.outerSize(); ++col_id) {
274 const auto & start = p_eigen_matrix.outerIndexPtr()[col_id];
275 const auto & end = p_eigen_matrix.outerIndexPtr()[col_id+1];
276 const auto id = p_eigen_matrix.data().searchLowerIndex(start, end,
static_cast<StorageIndex
>(row_id));
277 if ((
id<end) && (p_eigen_matrix.data().index(
id)==row_id)) {
278 p_eigen_matrix.data().value(
id) =
static_cast<const Scalar &
>(0);
286 if (not p_initialized) {
290 using StorageIndex =
typename EigenType::StorageIndex;
291 using Scalar =
typename EigenType::Scalar;
293 if constexpr (EigenType::IsRowMajor) {
294 const auto & start = p_eigen_matrix.outerIndexPtr()[imin];
295 const auto & end = p_eigen_matrix.outerIndexPtr()[imax+1];
296 memset(&(p_eigen_matrix.data().valuePtr()[start]),
static_cast<const Scalar &
>(0), (end-start)*
sizeof(Scalar));
298 for (
int col_id=0; col_id<p_eigen_matrix.outerSize(); ++col_id) {
299 const auto & start = p_eigen_matrix.outerIndexPtr()[col_id];
300 const auto & end = p_eigen_matrix.outerIndexPtr()[col_id+1];
301 auto id = p_eigen_matrix.data().searchLowerIndex(start, end,
static_cast<StorageIndex
>(imin));
303 if (imin <= p_eigen_matrix.data().index(
id) and p_eigen_matrix.data().index(
id) <= imax) {
304 p_eigen_matrix.data().value(
id) =
static_cast<const Scalar &
>(0);
305 }
else if (p_eigen_matrix.data().index(
id) > imax) {
315 if (not p_initialized) {
319 using StorageIndex =
typename EigenType::StorageIndex;
320 using Scalar =
typename EigenType::Scalar;
322 if constexpr (not EigenType::IsRowMajor) {
323 const auto & start = p_eigen_matrix.outerIndexPtr()[col_id];
324 const auto & end = p_eigen_matrix.outerIndexPtr()[col_id+1];
325 memset(&(p_eigen_matrix.data().valuePtr()[start]),
static_cast<const Scalar &
>(0), (end-start)*
sizeof(Scalar));
327 for (
int row_id=0; row_id<p_eigen_matrix.outerSize(); ++row_id) {
328 const auto & start = p_eigen_matrix.outerIndexPtr()[row_id];
329 const auto & end = p_eigen_matrix.outerIndexPtr()[row_id+1];
330 const auto id = p_eigen_matrix.data().searchLowerIndex(start, end,
static_cast<StorageIndex
>(col_id));
331 if ((
id<end) && (p_eigen_matrix.data().index(
id)==col_id)) {
332 p_eigen_matrix.data().value(
id) =
static_cast<const Scalar &
>(0);
340 if (not p_initialized) {
344 using StorageIndex =
typename EigenType::StorageIndex;
345 using Scalar =
typename EigenType::Scalar;
347 if constexpr (not EigenType::IsRowMajor) {
348 const auto & start = p_eigen_matrix.outerIndexPtr()[imin];
349 const auto & end = p_eigen_matrix.outerIndexPtr()[imax+1];
350 memset(&(p_eigen_matrix.data().valuePtr()[start]),
static_cast<const Scalar &
>(0), (end-start)*
sizeof(Scalar));
352 for (
int row_id=0; row_id<p_eigen_matrix.outerSize(); ++row_id) {
353 const auto & start = p_eigen_matrix.outerIndexPtr()[row_id];
354 const auto & end = p_eigen_matrix.outerIndexPtr()[row_id+1];
355 auto id = p_eigen_matrix.data().searchLowerIndex(start, end,
static_cast<StorageIndex
>(imin));
357 if (imin <= p_eigen_matrix.data().index(
id) and p_eigen_matrix.data().index(
id) <= imax) {
358 p_eigen_matrix.data().value(
id) =
static_cast<const Scalar &
>(0);
359 }
else if (p_eigen_matrix.data().index(
id) > imax) {
369 if (not p_initialized) {
373 using StorageIndex =
typename EigenType::StorageIndex;
374 using Scalar =
typename EigenType::Scalar;
377 const auto & start = p_eigen_matrix.outerIndexPtr()[i];
378 const auto & end = p_eigen_matrix.outerIndexPtr()[i+1];
379 memset(&(p_eigen_matrix.data().valuePtr()[start]),
static_cast<const Scalar &
>(0), (end-start)*
sizeof(Scalar));
382 if (symmetric() and p_eigen_matrix.rows() == p_eigen_matrix.cols()) {
386 for (
typename EigenType::InnerIterator it(p_eigen_matrix, i); it; ++it) {
387 const auto inner_index = EigenType::IsRowMajor ? it.col() : it.row();
388 const auto & start = p_eigen_matrix.outerIndexPtr()[inner_index];
389 const auto & end = p_eigen_matrix.outerIndexPtr()[inner_index+1];
390 const auto id = p_eigen_matrix.data().searchLowerIndex(start, end,
static_cast<StorageIndex
>(i));
391 if ((
id<end) && (p_eigen_matrix.data().index(
id)==i)) {
392 p_eigen_matrix.data().value(
id) =
static_cast<const Scalar &
>(0);
396 for (
int outer_id=0; outer_id<p_eigen_matrix.outerSize(); ++outer_id) {
397 const auto & start = p_eigen_matrix.outerIndexPtr()[outer_id];
398 const auto & end = p_eigen_matrix.outerIndexPtr()[outer_id+1];
399 const auto id = p_eigen_matrix.data().searchLowerIndex(start, end,
static_cast<StorageIndex
>(i));
400 if ((
id<end) && (p_eigen_matrix.data().index(
id)==i)) {
401 p_eigen_matrix.data().value(
id) =
static_cast<const Scalar &
>(0);
408 const Derived &
matrix()
const {
return p_eigen_matrix;}
414 template <
typename Scalar,
unsigned int N,
unsigned int C>
415 void add_block(Index i, Index j,
const sofa::defaulttype::Mat<N, C, Scalar> & m) {
416 for (
size_t k=0;k<N;++k) {
417 for (
size_t l=0;l<C;++l) {
418 const auto value =
static_cast<typename EigenType::Scalar
>(m[k][l]);
419 if (not p_initialized) {
420 p_triplets.emplace_back(i+k, j+l, value);
422 p_eigen_matrix.coeffRef(i+k, j+l) += value;
434 p_eigen_matrix.setFromTriplets(p_triplets.begin(), p_triplets.end());
436 p_initialized =
true;
441 std::vector<Eigen::Triplet<typename EigenType::Scalar>> p_triplets;
446 bool p_initialized =
false;
449 Derived p_eigen_matrix;
453 bool p_is_symmetric =
false;