Program Listing for File Matrix.cpp

Return to documentation for file (src/LouLib/Math/Matrix.cpp)

#include "Matrix.hpp"

namespace LouLib {
    namespace Math {
        Matrix::MatrixRow::MatrixRow(int n) {
            data.resize(n, 0);
        }

        Matrix::MatrixRow::MatrixRow(std::initializer_list<double> rowData) : data(rowData) {}

        Matrix::MatrixRow::MatrixRow(std::vector<double> rowData) : data(std::move(rowData)) {}

        Matrix::MatrixRow::MatrixRow(const Matrix::MatrixRow &other) : data(other.data) {}

        double &Matrix::MatrixRow::operator[](int i) {
            if(i < 0 || i >= data.size()){
                throw std::invalid_argument("Index out of bounds");
            }
            return data[i];
        }

        const double &Matrix::MatrixRow::operator[](int i) const {
            if(i < 0 || i >= data.size()){
                throw std::invalid_argument("Index out of bounds");
            }
            return data[i];
        }

        int Matrix::MatrixRow::size() const {
            return (int) data.size();
        }

        Vector Matrix::MatrixRow::getVector() {
            return Vector(data);
        }

        Matrix::Matrix(int rows, int cols) {
            data.resize(rows, MatrixRow(cols));
        }

        Matrix::Matrix(std::initializer_list<std::initializer_list<double>> matrixData) {
            data.resize(0, MatrixRow(0));
            for(auto it = matrixData.begin(); it != matrixData.end(); it++){
                data.emplace_back(*it);
            }
        }

        Matrix::Matrix(std::vector<std::vector<double>> matrixData) {
            data.resize(0, MatrixRow(0));
            for(auto it = matrixData.begin(); it != matrixData.end(); it++){
                data.emplace_back(*it);
            }
        }

        Matrix::Matrix(std::vector<MatrixRow> matrixData) {
            data = std::move(matrixData);
        }

        Matrix::Matrix(const Matrix &other) : data(other.data) {}

        Matrix::MatrixRow &Matrix::operator[](int i) {
            if(i < 0 || i >= data.size()){
                throw std::invalid_argument("Index out of bounds");
            }
            return data[i];
        }

        const Matrix::MatrixRow &Matrix::operator[](int i) const {
            if(i < 0 || i >= data.size()){
                throw std::invalid_argument("Index out of bounds");
            }
            return data[i];
        }

        Vector Matrix::getCol(int i) {
            if(i < 0 || i >= cols()){
                throw std::invalid_argument("Index out of bounds");
            }
            Vector sol(rows());
            for(int j = 0; j < rows(); j++){
                sol[j] = data[j][i];
            }
            return sol;
        }

        Vector Matrix::getRow(int i) {
            if(i < 0 || i >= data.size()){
                throw std::invalid_argument("Index out of bounds");
            }
            return data[i].getVector();
        }

        int Matrix::rows() const {
            return (int) data.size();
        }

        int Matrix::cols() const {
            return (int) data[0].size();
        }

        Matrix Matrix::transpose() {
            Matrix sol(cols(), rows());
            for(int i = 0; i < rows(); i++){
                for(int j = 0; j < cols(); j++){
                    sol[j][i] = data[i][j];
                }
            }
            return sol;
        }

        double Matrix::norm() {
            double sol = 0;
            for(int i = 0; i < rows(); i++){
                for(int j = 0; j < cols(); j++){
                    sol += data[i][j] * data[i][j];
                }
            }
            return std::sqrt(sol);
        }

        double Matrix::det() {
            if(rows() != cols()){
                throw std::invalid_argument("Cannot calculate determinant of a non-square matrix");
            }

            if(rows() == 2){
                return data[0][0]*data[1][1]-data[1][0]*data[0][1];
            }

            double sol = 0;
            for(int i = 0; i < rows(); i++){
                sol += (data[i][0]) * cofactor(i, 0);
            }
            return sol;
        }

        Matrix Matrix::minor(int i, int j){
            Matrix sol(rows()-1, cols()-1);
            for(int r = 0; r < rows(); r++){
                if(r == i) continue;
                int newR = (r < i) ? r : r-1;
                for(int c = 0; c < cols(); c++){
                    if(c == j) continue;
                    int newC = (c < j) ? c : c-1;
                    sol[newR][newC] = data[r][c];
                }
            }
            return sol;
        }

        double Matrix::cofactor(int i, int j) {
            return std::pow(-1, i+j) * minor(i, j).det();
        }

        Matrix Matrix::inverse() {
            Matrix cofactorMatrix(rows(), cols());
            for(int i = 0; i < rows(); i++){
                for(int j = 0; j < cols(); j++){
                    cofactorMatrix[i][j] = cofactor(i, j);
                }
            }
            Matrix sol = cofactorMatrix.transpose();
            double determinant = det();
            for(int i = 0; i < sol.rows(); i++){
                for(int j = 0; j < sol.cols(); j++){
                    sol[i][j] /= determinant;
                }
            }
            return sol;
        }

        std::string Matrix::toString() {
            std::string sol = "{";
            for(int i = 0; i < rows(); i++){
                sol += data[i].getVector().toString();
                if(i != rows()-1) sol += ",\n";
            }
            sol += "}";
            return sol;
        }

        Matrix operator+(const Matrix &a, const Matrix &b) {
            if(a.rows() != b.rows() || a.cols() != b.cols()){
                throw std::invalid_argument("Matrix dimensions don't match");
            }
            Matrix sol(a.rows(), a.cols());
            for(int i = 0; i < a.rows(); i++){
                for(int j = 0; j < a.cols(); j++){
                    sol[i][j] = a[i][j] + b[i][j];
                }
            }
            return sol;
        }

        Matrix operator-(const Matrix &a, const Matrix &b) {
            if(a.rows() != b.rows() || a.cols() != b.cols()){
                throw std::invalid_argument("Matrix dimensions don't match");
            }
            Matrix sol(a.rows(), a.cols());
            for(int i = 0; i < a.rows(); i++){
                for(int j = 0; j < a.cols(); j++){
                    sol[i][j] = a[i][j] - b[i][j];
                }
            }
            return sol;
        }

        Matrix operator*(const Matrix &a, const Matrix &b) {
            if(a.cols() != b.rows()){
                throw std::invalid_argument("Matrix dimensions can't be multiplied");
            }

            Matrix sol(a.rows(), b.cols());

            for(int i = 0; i < a.rows(); i++){
                for(int j = 0; j < b.cols(); j++){
                    double sum = 0;
                    for(int k = 0; k < a.cols(); k++){
                        sum += a[i][k] * b[k][j];
                    }
                    sol[i][j] = sum;
                }
            }

            return sol;
        }

        Matrix operator*(const Matrix &a, const double &b) {
            Matrix sol(a.rows(), a.cols());
            for(int i = 0; i < a.rows(); i++){
                for(int j = 0; j < a.cols(); i++){
                    sol[i][j] = b * a[i][j];
                }
            }
            return sol;
        }

        Matrix operator*(const double &a, const Matrix &b) {
            Matrix sol(b.rows(), b.cols());
            for(int i = 0; i < b.rows(); i++){
                for(int j = 0; j < b.cols(); j++){
                    sol[i][j] = a * b[i][j];
                }
            }
            return sol;
        }

        Vector operator*(const Matrix &a, const Vector &b) {
            if(a.cols() != b.size()){
                throw std::invalid_argument("Matrix and vector dimensions can't be multiplied");
            }

            Vector sol(a.rows());
            for(int i = 0; i < a.rows(); i++){
                double sum = 0;
                for(int j = 0; j < a.cols(); j++){
                    sum += a[i][j] * b[j];
                }
                sol[i] = sum;
            }

            return sol;
        }


    } // LouLib
} // Math