#pragma once /** * @file Matrix.h * * @brief Implémentation de matrices simples. * * Nom: William Nolin * Code permanent : NOLW76060101 * Email : william.nolin.1@ens.etsmtl.ca * */ #include #include #include "MatrixBase.h" namespace gti320 { enum StorageType { ColumnStorage = 0, RowStorage = 1 }; // Déclaration avancée template class SubMatrix; /** * Classe Matrix spécialisé pour le cas générique. (defaut par colonne) * * (le cas d'un stockage par ligne fait l'objet d'une spécialisation de patron, voir plus bas) */ template class Matrix : public MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile> { public: /** * Constructeur par défaut */ Matrix() : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>() {} /** * Constructeur de copie */ Matrix(const Matrix &other) : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>(other) {} /** * Constructeur avec spécification du nombre de ligne et de colonnes */ explicit Matrix(int _rows, int _cols) : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>(_rows, _cols) {} /** * Destructeur */ ~Matrix() {} /** * Opérateur de copie à partir d'une sous-matrice. * * Exemple : Matrix B = A.block(i,j,m,n); */ template Matrix &operator=(const SubMatrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage> &submatrix) { if (this->rows() != submatrix->rows() || this->cols() != submatrix->cols()) { this->resize(submatrix->rows(), submatrix->cols()); } for (int col = 0; col < this->cols(); col++) { for (int row = 0; row < this->rows(); row++) { this(row, col) = submatrix(row, col); } } return *this; } /** * Accesseur à une entrée de la matrice (lecture seule) */ _Scalar operator()(int i, int j) const { int index = i + j * this->rows(); return this->m_storage.data()[index]; } /** * Accesseur à une entrée de la matrice (lecture ou écriture) */ _Scalar &operator()(int i, int j) { int index = i + j * this->rows(); return this->m_storage.data()[index]; } /** * Crée une sous-matrice pour un block de taille (rows, cols) à partir de l'index (i,j). */ SubMatrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType> block(int i, int j, int rows, int cols) const { return SubMatrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType>(*this, i, j, rows, cols); } /** * Calcule l'inverse de la matrice */ Matrix inverse() const { // Do nothing. return *this; } /** * Retourne la transposée de la matrice */ template Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage> transpose() const { auto transposed = Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage>(this->cols(), this->rows()); for (int col = 0; col < this->cols(); col++) { for (int row = 0; row < this->rows(); row++) { transposed(col, row) = (*this)(row, col); } } return transposed; } /** * Affecte l'identité à la matrice */ inline void setIdentity() { this->m_storage.setZero(); int smallest = std::min(this->rows(), this->cols()); for (int i = 0; i < smallest; i++) { (*this)(i, i) = 1; } } }; /** * Classe Matrix spécialisée pour un stockage par lignes */ template class Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, RowStorage> : public MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile> { public: /** * Constructeur par défaut */ Matrix() : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>() {} /** * Constructeur de copie */ Matrix(const Matrix &other) : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>(other) {} /** * Constructeur avec spécification du nombre de ligne et de colonnes */ explicit Matrix(int rows, int cols) : MatrixBase<_Scalar, _RowsAtCompile, _ColsAtCompile>(rows, cols) {} /** * Destructeur */ ~Matrix() {} /** * Opérateur de copie à partir d'une sous-matrice. * * Exemple : Matrix B = A.block(i,j,m,n); */ template Matrix &operator=(const SubMatrix<_OtherScalar, OtherRows, _OtherCols, _OtherStorage> &submatrix) { if (this->rows() != submatrix->rows() || this->cols() != submatrix->cols()) { this->resize(submatrix->rows(), submatrix->cols()); } for (int row = 0; row < this->rows(); row++) { for (int col = 0; col < this->cols(); col++) { this(row, col) = submatrix(row, col); } } return *this; } /** * Accesseur à une entrée de la matrice (lecture seule) */ _Scalar operator()(int i, int j) const { int index = i * this->cols() + j; return this->m_storage.data()[index]; } /** * Accesseur à une entrée de la matrice (lecture ou écriture) */ _Scalar &operator()(int i, int j) { int index = i * this->cols() + j; return this->m_storage.data()[index]; } /** * Crée une sous-matrice pour un block de taille (rows, cols) à partir de l'index (i,j). */ SubMatrix<_Scalar, _RowsAtCompile, _ColsAtCompile, RowStorage> block(int i, int j, int rows, int cols) const { return SubMatrix<_Scalar, _RowsAtCompile, _ColsAtCompile, RowStorage>(*this, i, j, rows, cols); } /** * Calcule l'inverse de la matrice */ Matrix inverse() const { // Do nothing. return *this; } /** * Retourne la transposée de la matrice */ Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, ColumnStorage> transpose() const { auto t = Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, ColumnStorage>(this->cols(), this->rows()); for (int row = 0; row < this->rows(); row++) { for (int col = 0; col < this->cols(); col++) { t(col, row) = (*this)(row, col); } } return t; } /** * Affecte l'identité à la matrice */ inline void setIdentity() { this->m_storage.setZero(); int small_size = std::min(this->rows(), this->cols()); for (int i = 0; i < small_size; i++) { (*this)(i, i) = 1; } } }; /** * Classe pour accéder à une sous-matrice. * * Un sous-matrice ne copie pas les données. Au lieu de cela, elle conserve une * référence à la matrice originale. */ template class SubMatrix { private: // Référence à la matrice originale Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType> &m_matrix; // Constructeur par défaut (privé) SubMatrix() {} // (i,j) est le coin supérieur gauche de la sous-matrice int m_i; // Décalage en ligne int m_j; // Décalage en colonne // la sous-matrice est de dimension : m_rows x m_cols int m_rows; // Hauteur de la sous-matrice (nombre de lignes) int m_cols; // Largeur de la sous-matrice (nombre de colonnes) public: /** * Constructeur à partir d'une référence en lecture seule à une matrice. */ SubMatrix(const Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType> &_matrix, int _i, int _j, int _rows, int _cols) : m_matrix(const_cast &>(_matrix)), m_i(_i), m_j(_j), m_rows(_rows), m_cols(_cols) { } /** * Constructeur à partir d'une référence en lecture et écriture à une matrice. */ explicit SubMatrix(Matrix<_Scalar, _RowsAtCompile, _ColsAtCompile, _StorageType> &_matrix, int _i, int _j, int _rows, int _cols) : m_matrix(_matrix), m_i(_i), m_j(_j), m_rows(_rows), m_cols(_cols) { } /** * Constructeur de copie */ SubMatrix(const SubMatrix &other) : m_matrix(other.m_matrix), m_i(other.m_i), m_j(other.m_j), m_rows(other.m_rows), m_cols(other.m_cols) { } /** * Destructeur */ ~SubMatrix() {} /** * Opérateur de copie (à partir d'une matrice) * * Copies toutes les entrées de la matrice dans la sous-matrice. * * Note : la taille de la matrice doit correspondre à la taille de la * sous-matrice. */ template SubMatrix &operator=(const Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage> &matrix) { assert(this->rows() == matrix.rows()); assert(this->cols() == matrix.cols()); for (int col = 0; col < this->cols(); col++) { for (int row = 0; row < this->rows(); row++) { (*this)(row, col) = matrix(row, col); } } return *this; } /** * Opérateur de d'addition d'une autre matrice * * Ajoute toutes les entrées de la matrice dans la sous-matrice. * * Note : la taille de la matrice doit correspondre à la taille de la * sous-matrice. */ template SubMatrix &operator+=(const Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage> &matrix) { assert(this->rows() == matrix.rows()); assert(this->cols() == matrix.cols()); for (int col = 0; col < this->cols(); col++) { for (int row = 0; row < this->rows(); row++) { (*this)(row, col) = (*this)(row, col) + matrix(row, col); } } return *this; } /** * Accesseur aux entrées de la sous-matrice (lecture seule) * * Note : il faut s'assurer que les indices respectent la taille de la * sous-matrice */ _Scalar operator()(int i, int j) const { assert(i >= 0); assert(i <= this->rows()); assert(j >= 0); assert(j <= this->cols()); int full_i = this->m_i + i; int full_j = this->m_j + j; return this->m_matrix(full_i, full_j); } /** * Accesseur aux entrées de la sous-matrice (lecture et écriture) * * Note : il faut s'assurer que les indices respectent la taille de la * sous-matrice */ _Scalar &operator()(int i, int j) { assert(i >= 0); assert(i <= this->rows()); assert(j >= 0); assert(j <= this->cols()); int full_i = this->m_i + i; int full_j = this->m_j + j; return this->m_matrix(full_i, full_j); } /** * Retourne la transposée de la sous-matrice sous la forme d'une matrice. */ template Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage> transpose() const { auto t = Matrix<_OtherScalar, _OtherRows, _OtherCols, _OtherStorage>(this->rows(), this->cols()); for (int col = 0; col < this->cols(); col++) { for (int row = 0; row < this->rows(); row++) { t(col, row) = (*this)(row, col); } } return t; } inline int rows() const { return m_rows; } inline int cols() const { return m_cols; } }; }