// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #pragma once #include #include #include #include #include namespace frc { template concept EigenMatrixLike = std::derived_from>; /** * Compile-time wrapper for Eigen::Matrix. * * @tparam Rows Rows of matrix. * @tparam Cols Columns of matrix. */ template class ct_matrix { public: constexpr ct_matrix() = default; /** * Constructs a scalar VariableMatrix from a nested list of Variables. * * @param list The nested list of Variables. */ constexpr ct_matrix( // NOLINT (runtime/explicit) std::initializer_list> list) : m_storage{list} {} template requires std::derived_from> // NOLINTNEXTLINE (runtime/explicit) constexpr ct_matrix(const Derived& mat) : m_storage{mat} {} /** * Returns number of rows. * * @return Number of rows. */ constexpr int rows() const { return m_storage.rows(); } /** * Returns number of columns. * * @return Number of columns. */ constexpr int cols() const { return m_storage.cols(); } /** * Returns reference to matrix element. * * @param row Row index. * @param col Column index. */ constexpr const Scalar& operator()(int row, int col) const { return m_storage(row, col); } /** * Returns reference to matrix element. * * @param row Row index. * @param col Column index. */ constexpr Scalar& operator()(int row, int col) { return m_storage(row, col); } /** * Returns reference to matrix element. * * @param index Index. */ constexpr const Scalar& operator()(int index) const requires(Rows == 1 || Cols == 1) { return m_storage(index); } /** * Returns reference to matrix element. * * @param index Index. */ constexpr Scalar& operator()(int index) requires(Rows == 1 || Cols == 1) { return m_storage(index); } /** * Constexpr version of Eigen's scalar multiplication operator. * * @param lhs LHS scalar. * @param rhs RHS matrix. * @return Result of multiplication. */ friend constexpr ct_matrix operator*( Scalar lhs, const ct_matrix& rhs) { if (std::is_constant_evaluated()) { ct_matrix result; for (int i = 0; i < rhs.rows(); ++i) { for (int j = 0; j < rhs.cols(); ++j) { result(i, j) = lhs * rhs(i, j); } } return result; } else { return lhs * rhs.m_storage; } } /** * Constexpr version of Eigen's matrix multiplication operator. * * @tparam Cols2 Columns of RHS matrix. * @param lhs LHS matrix. * @param rhs RHS matrix. * @return Result of multiplication. */ template friend constexpr ct_matrix operator*( const ct_matrix& lhs, const ct_matrix& rhs) { if (std::is_constant_evaluated()) { ct_matrix result; for (int i = 0; i < lhs.rows(); ++i) { for (int j = 0; j < rhs.cols(); ++j) { Scalar sum = 0.0; for (int k = 0; k < lhs.cols(); ++k) { sum += lhs(i, k) * rhs(k, j); } result(i, j) = sum; } } return result; } else { return lhs.m_storage * rhs.storage(); } } /** * Constexpr version of Eigen's matrix addition operator. * * @param lhs LHS matrix. * @param rhs RHS matrix. * @return Result of addition. */ friend constexpr ct_matrix operator+( const ct_matrix& lhs, const ct_matrix& rhs) { if (std::is_constant_evaluated()) { ct_matrix result; for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { result(row, col) = lhs(row, col) + rhs(row, col); } } return result; } else { return lhs.m_storage + rhs.m_storage; } } /** * Constexpr version of Eigen's matrix subtraction operator. * * @param lhs LHS matrix. * @param rhs RHS matrix. * @return Result of subtraction. */ friend constexpr ct_matrix operator-( const ct_matrix& lhs, const ct_matrix& rhs) { if (std::is_constant_evaluated()) { ct_matrix result; for (int row = 0; row < 3; ++row) { for (int col = 0; col < 3; ++col) { result(row, col) = lhs(row, col) - rhs(row, col); } } return result; } else { return lhs.m_storage - rhs.m_storage; } } /** * Constexpr version of Eigen's transpose member function. * * @return Transpose of matrix. */ constexpr ct_matrix transpose() const { if (std::is_constant_evaluated()) { ct_matrix result; for (int row = 0; row < rows(); ++row) { for (int col = 0; col < cols(); ++col) { result(col, row) = (*this)(row, col); } } return result; } else { return m_storage.transpose().eval(); } } /** * Constexpr version of Eigen's identity function. * * @return Identity matrix of the specified size. */ static constexpr ct_matrix Identity() requires(Rows != Eigen::Dynamic && Cols != Eigen::Dynamic) { if (std::is_constant_evaluated()) { ct_matrix result; for (int row = 0; row < Rows; ++row) { for (int col = 0; col < Cols; ++col) { if (row == col) { result(row, row) = 1.0; } else { result(row, col) = 0.0; } } } return result; } else { return Eigen::Matrix::Identity(); } } /** * Constexpr version of Eigen's vector dot member function. * * @tparam RhsRows Rows of RHS vector. * @tparam RhsCols Columns of RHS vector. * @param rhs RHS vector. * @return Dot product of two vectors. */ template requires(Rows == 1 || Cols == 1) && (RhsRows == 1 || RhsCols == 1) && (Rows * Cols == RhsRows * RhsCols) constexpr Scalar dot(const ct_matrix& rhs) const { if (std::is_constant_evaluated()) { Scalar sum = 0.0; for (int index = 0; index < rows() * rhs.cols(); ++index) { sum += (*this)(index)*rhs(index); } return sum; } else { return m_storage.dot(rhs.storage()); } } /** * Constexpr version of Eigen's norm member function. * * @return Norm of matrix. */ constexpr Scalar norm() const { if (std::is_constant_evaluated()) { Scalar sum = 0.0; for (int row = 0; row < Rows; ++row) { for (int col = 0; col < Cols; ++col) { sum += (*this)(row, col) * (*this)(row, col); } } return gcem::sqrt(sum); } else { return m_storage.norm(); } } /** * Constexpr version of Eigen's 3D vector cross member function. * * @param rhs RHS vector. * @return Cross product of two vectors. */ constexpr ct_matrix cross(const ct_matrix& rhs) requires(Rows == 3 && Cols == 1) { return Eigen::Vector3d{{(*this)(1) * rhs(2) - rhs(1) * (*this)(2), rhs(0) * (*this)(2) - (*this)(0) * rhs(2), (*this)(0) * rhs(1) - rhs(0) * (*this)(1)}}; } /** * Constexpr version of Eigen's 3x3 matrix determinant member function. * * @return Determinant of matrix. */ constexpr Scalar determinant() const requires(Rows == 3 && Cols == 3) { // |a b c| // |d e f| = aei + bfg + cgh - ceg - bdi - afh // |g h i| Scalar a = (*this)(0, 0); Scalar b = (*this)(0, 1); Scalar c = (*this)(0, 2); Scalar d = (*this)(1, 0); Scalar e = (*this)(1, 1); Scalar f = (*this)(1, 2); Scalar g = (*this)(2, 0); Scalar h = (*this)(2, 1); Scalar i = (*this)(2, 2); return a * e * i + b * f * g + c * g * h - c * e * g - b * d * i - a * f * h; } /** * Returns the internal Eigen matrix. * * @return The internal Eigen matrix. */ constexpr const Eigen::Matrix& storage() const { return m_storage; } /** * Implicit cast to an Eigen matrix. */ constexpr operator Eigen::Matrix() const { // NOLINT return m_storage; } private: Eigen::Matrix m_storage; }; template requires std::derived_from> ct_matrix(const Derived&) -> ct_matrix; template using ct_vector = ct_matrix; template using ct_row_vector = ct_matrix; using ct_matrix3d = ct_matrix; using ct_vector3d = ct_vector; } // namespace frc