Project: A matrix class

The goal of this project is to fill in the rest of the details of the Matrix and Vector classes we wrote during the last 2 weeks. More final versions of the header and source files are given below. Some of the methods and operators have been implemented some have not. Your tasks are as follows:

  1. Implement the missing methods and operators
  2. Write a print() method that prints the matrix or vector to the screen MATLAB-style.
  3. Write a small main program that uses the matrix and vector class and demonstrates all of the major operations and prints out results.
  4. Write a corresponding MATLAB file and verify the Matrix class works as expected.

Code

matrix.h

#ifndef __UNIT3_EXAMPLES_MATRIX_H__
#define __UNIT3_EXAMPLES_MATRIX_H__

#include <cstdlib>

#include "vector.h"

namespace math {

class Matrix
{
public:
    // Creates an empty matrix
    Matrix();

    // Creates an uninitialized matrix of the given size
    Matrix(size_t width, size_t height);

    /* Creates a matrix of the given size with d on the diagonal and
     * zero off the diagonal*/
    Matrix(size_t width, size_t height, double d);

    // Destructor
    ~Matrix();

    // Copies a matrix
    Matrix(const Matrix& other);
    Matrix& operator=(const Matrix& other);

    // Creates a matrix from a single column-vector
    Matrix(const Vector& vec);
    Matrix& operator=(const Vector& vec);

    // Resizes a matrix.  The contents of the matrix is undefined after
    // this operation.
    void resize(size_t width, size_t height);

    // Retrieves the matrix's size;
    size_t rows() const;
    size_t cols() const;

    // Prints the matrix to standard output
    void print() const;

    // Gets the element in the given row and column (parens operator)
    double operator()(size_t row, size_t col) const;
    double& operator()(size_t row, size_t col);

    Matrix transpose() const;

    // Matrix-Scalar operations
    Matrix operator*(double s) const;
    Matrix operator/(double s) const;

    // Matrix-Vector operations
    Matrix operator*(const Vector& v) const;

    // Matrix-Matrix operations
    Matrix operator+(const Matrix& other) const;
    Matrix operator-(const Matrix& other) const;
    Matrix operator*(const Matrix& other) const;

private:
    double *_data;
    size_t _rows, _cols;
};

// Allow scalar multiplication on the left as well as the right.
static inline Matrix
operator*(double left, const Matrix& right)
{
    return right * left;
}

} // namespace math

#endif // ! defined __UNIT3_EXAMPLES_MATRIX_H__

vector.h

#ifndef __UNIT3_EXAMPLES_VECTOR_H__
#define __UNIT3_EXAMPLES_VECTOR_H__

#include <cstdlib>

namespace math {

class Vector
{
public:
    // Creates an empty vector
    Vector();
    
    // Creates an uninitialized vector with the given length
    Vector(size_t len);

    // Destructor
    ~Vector();

    // Copies a vector
    Vector(const Vector& other);
    Vector& operator=(const Vector& other);

    // Resizes a vector.  The contents of the vector is undefined after
    // this operation.
    void resize(size_t len);

    // Retrieves the length of the vector
    size_t length() const;

    // Prints the vector to standard output
    void print() const;

    // Gets the n'th entry of the vector (bracket operator)
    double operator[](size_t n) const;
    double& operator[](size_t n);

    // Computes the 2-norm of the matrix
    double norm() const;
    // Computes the p-norm of the matrix (Infinity is allowed)
    double norm(double p) const;

    // Vector-Scalar operations
    Vector operator*(double d) const;
    Vector operator/(double d) const;

    // Vector-Vector operations
    Vector operator+(const Vector& other) const;
    Vector operator-(const Vector& other) const;

private:
    double *_data;
    size_t _len;
};

// Allow scalar multiplication on the left as well as the right.
static inline Vector
operator*(double left, const Vector& right)
{
    return right * left;
}

} // namespace math

#endif // ! defined __UNIT3_EXAMPLES_VECTOR_H__

matrix.cpp

#include "matrix.h"

#include <cmath>
#include <cassert>

using namespace math;

Matrix::Matrix()
{
    _rows = 0;
    _cols = 0;
    _data = NULL;
}

Matrix::Matrix(size_t rows, size_t cols)
{
    _rows = rows;
    _cols = cols;

    if (rows * cols == 0) {
        _data = NULL;
    } else {
        _data = new double[rows * cols];
    }
}

Matrix::~Matrix()
{
    delete[] _data;
}

Matrix::Matrix(const Matrix& other)
{
    _rows = other._rows;
    _cols = other._cols;
    
    if (_rows * _cols == 0) {
        _data = NULL;
    } else {
        _data = new double[_rows * _cols];
        for (size_t i = 0; i < _rows * _cols; ++i)
            _data[i] = other._data[i];
    }
}

Matrix&
Matrix::operator=(const Matrix& other)
{
    resize(other._rows, other._cols);

    for (size_t i = 0; i < _rows * _cols; ++i)
        _data[i] = other._data[i];

    return *this;
}

Matrix::Matrix(const Vector& vec)
{
    _cols = 1;
    _rows = vec.length();
    
    if (_rows * _cols == 0) {
        _data = NULL;
    } else {
        _data = new double[_rows];
        for (size_t i = 0; i < _rows; ++i)
            _data[i] = vec[i];
    }
}

Matrix&
Matrix::operator=(const Vector& vec)
{
    resize(vec.length(), 1);

    for (size_t i = 0; i < _rows; ++i)
        _data[i] = vec[i];

    return *this;
}

void
Matrix::resize(size_t rows, size_t cols)
{
    delete[] _data;

    _rows = rows;
    _cols = cols;

    if (rows * cols == 0) {
        _data = NULL;
    } else {
        _data = new double[rows * cols];
    }
}

size_t
Matrix::rows() const
{
    return _rows;
}

size_t
Matrix::cols() const
{
    return _cols;
}

double &
Matrix::operator()(size_t r, size_t c)
{
    assert(r < _rows && c < _cols);

    return _data[c + r * _cols];
}

double
Matrix::operator()(size_t r, size_t c) const
{
    assert(r < _rows && c < _cols);

    return _data[c + r * _cols];
}

Matrix
Matrix::operator/(double s) const
{
    return (*this) * (1/s);
}

Matrix
Matrix::operator*(const Matrix& B) const
{
    assert(cols() == B.rows());

    Matrix C(rows(), B.cols());

    for (size_t i = 0; i < rows(); ++i) {
        for (size_t j = 0; j < B.cols(); ++j) {
            C(i, j) = 0;
        }

        for (size_t k = 0; k < cols(); ++k) {
            for (size_t j = 0; j < B.cols(); ++j) {
                C(i, j) += (*this)(i, k) * B(k, j);
            }
        }
    }

    return C;
}

vector.cpp

#include "vector.h"

#include <cassert>
#include <cmath>

using namespace math;

Vector::Vector()
{
    _len = 0;
    _data = NULL;
}

Vector::Vector(size_t len)
{
    _len = len;

    if (len == 0) {
        _data = NULL;
    } else {
        _data = new double[len];
    }
}

Vector::~Vector()
{
    delete[] _data;
}

Vector::Vector(const Vector& other)
{
    _len = other._len;

    if (_len == 0) {
        _data = NULL;
    } else {
        _data = new double[_len];
        for (size_t i = 0; i < _len; ++i)
            _data[i] = other._data[i];
    }
}

size_t
Vector::length() const
{
    return _len;
}

double
Vector::norm() const
{
    norm(2);
}

double
Vector::norm(double p) const
{
    if (p < 1) {
        return NAN;
    } else if (p == 1) {
        double sum = 0;
        for (size_t i = 0; i < _len; ++i) {
            sum += abs(_data[i]);
        }
        return sum;
    } else if (p == 2) {
        double sum = 0;
        for (size_t i = 0; i < _len; ++i) {
            sum += _data[i] * _data[i];
        }
        return sqrt(sum);
    } else if (! std::isfinite(p)) {
        double max = 0;
        for (size_t i = 0; i < _len; ++i) {
            if (abs(_data[i]) > max)
                max = abs(_data[i]);
        }
        return max;
    } else {
        double sum = 0;
        for (size_t i = 0; i < _len; ++i) {
            sum += pow(_data[i], p);
        }
        return pow(sum, 1/p);
    }
}

Vector
Vector::operator+(const Vector& other) const
{
    assert(_len == other._len);

    Vector out(_len);
    for (size_t i = 0; i < _len; ++i)
        out[i] = (*this)[i] + other[i];
}

Vector
Vector::operator-(const Vector& other) const
{
    assert(_len == other._len);

    Vector out(_len);
    for (size_t i = 0; i < _len; ++i)
        out[i] = (*this)[i] - other[i];
}