#include "Matrix.h" #include #include //helper function to allocate memory for a matrix of size r x c and fill it with "fill" void Matrix::allocateMemory(unsigned int r, unsigned int c, double fill) { if(r == 0 || c == 0) { rows = 0; cols = 0; data = nullptr; return; } rows = r; cols = c; data = new double*[rows]; for (unsigned int i = 0; i < rows; i++) { data[i] = new double[cols]; for (unsigned int j = 0; j < cols; j++) { data[i][j] = fill; } } } //helper function to deallocate memory void Matrix::deallocateMemory() { if(data != nullptr) { for (unsigned int i = 0; i < rows; i++) { delete [] data[i]; } delete [] data; data = nullptr; } rows = 0; cols = 0; } //default constructor: creates an empty 0 x 0 matrix Matrix::Matrix() : rows(0), cols(0), data(nullptr) { } //parameterized constructor Matrix::Matrix(unsigned int r, unsigned int c, double fill) : rows(0), cols(0), data(nullptr) { allocateMemory(r, c, fill); } //copy constructor Matrix::Matrix(const Matrix& other) : rows(0), cols(0), data(nullptr) { allocateMemory(other.rows, other.cols, 0.0); for (unsigned int i = 0; i < rows; i++) { for (unsigned int j = 0; j < cols; j++) { data[i][j] = other.data[i][j]; } } } //destructor Matrix::~Matrix() { deallocateMemory(); } //assignment operator Matrix& Matrix::operator=(const Matrix& other) { if (this == &other) return *this; deallocateMemory(); allocateMemory(other.rows, other.cols, 0.0); for (unsigned int i = 0; i < rows; i++) { for (unsigned int j = 0; j < cols; j++) { data[i][j] = other.data[i][j]; } } return *this; } //returns the number of rows unsigned int Matrix::num_rows() const { return rows; } //returns the number of columns unsigned int Matrix::num_cols() const { return cols; } //clears the matrix by deallocating its memory void Matrix::clear() { deallocateMemory(); } bool Matrix::get(unsigned int row, unsigned int col, double &value) const { if(row >= rows || col >= cols) { return false; } value = data[row][col]; return true; } //modifier bool Matrix::set(unsigned int row, unsigned int col, double value) { if(row >= rows || col >= cols) { return false; } data[row][col] = value; return true; } //equality operator bool Matrix::operator==(const Matrix& other) const { //two matrices are equal if dimensions match //and every element is equal within a small epsilon if(rows != other.rows || cols != other.cols) return false; for (unsigned int i = 0; i < rows; i++) { for (unsigned int j = 0; j < cols; j++) { if (fabs(data[i][j] - other.data[i][j]) > 1e-10) return false; } } return true; } bool Matrix::operator!=(const Matrix& other) const { return !(*this == other); } //multiplies every element by the given coefficient void Matrix::multiply_by_coefficient(double coeff) { for (unsigned int i = 0; i < rows; i++) { for (unsigned int j = 0; j < cols; j++) { data[i][j] *= coeff; } } } //swaps two rows of the matrix (by swapping the row pointers) bool Matrix::swap_row(unsigned int row1, unsigned int row2) { if(row1 >= rows || row2 >= rows) { return false; } double* temp = data[row1]; data[row1] = data[row2]; data[row2] = temp; return true; } //transposes the matrix in place void Matrix::transpose() { if(rows == 0 || cols == 0) return; unsigned int newRows = cols; unsigned int newCols = rows; double** newData = new double*[newRows]; for (unsigned int i = 0; i < newRows; i++) { newData[i] = new double[newCols]; for (unsigned int j = 0; j < newCols; j++) { newData[i][j] = data[j][i]; } } deallocateMemory(); rows = newRows; cols = newCols; data = newData; } //adds another matrix to this one element-wise bool Matrix::add(const Matrix& other) { if(rows != other.rows || cols != other.cols) return false; for (unsigned int i = 0; i < rows; i++) { for (unsigned int j = 0; j < cols; j++) { data[i][j] += other.data[i][j]; } } return true; } //subtracts another matrix from this one element-wise bool Matrix::subtract(const Matrix& other) { if(rows != other.rows || cols != other.cols) return false; for (unsigned int i = 0; i < rows; i++) { for (unsigned int j = 0; j < cols; j++) { data[i][j] -= other.data[i][j]; } } return true; } //returns a dynamically allocated copy of the specified row //caller must delete[] the returned array double* Matrix::get_row(unsigned int row) const { if(row >= rows) return NULL; double* rowArray = new double[cols]; for (unsigned int j = 0; j < cols; j++) { rowArray[j] = data[row][j]; } return rowArray; } //returns a dynamically allocated copy of the specified column //caller must delete[] the returned array double* Matrix::get_col(unsigned int col) const { if(col >= cols) return NULL; double* colArray = new double[rows]; for (unsigned int i = 0; i < rows; i++) { colArray[i] = data[i][col]; } return colArray; } //divides the matrix into four quadrants and returns a pointer to an array of four matrices //each quadrant size = ceil(rows/2) x ceil(cols/2) Matrix* Matrix::quarter() const { if (rows == 0 || cols == 0) { return nullptr; } // Determine quadrant size so that all four quadrants are identical. // For overlapping, use ceil for both dimensions. unsigned int q_rows = (rows % 2 == 0) ? (rows / 2) : (rows / 2 + 1); unsigned int q_cols = (cols % 2 == 0) ? (cols / 2) : (cols / 2 + 1); // For an overlapping quarter, the top quadrants start at row 0, // the bottom quadrants start at floor(rows/2), similarly for columns. unsigned int start_row_bottom = rows / 2; unsigned int start_col_right = cols / 2; Matrix* quadrants = new Matrix[4]{ Matrix(q_rows, q_cols, 0.0), // Upper Left Matrix(q_rows, q_cols, 0.0), // Upper Right Matrix(q_rows, q_cols, 0.0), // Lower Left Matrix(q_rows, q_cols, 0.0) // Lower Right }; // Fill Upper Left quadrant from original (starting at (0,0)). for (unsigned int i = 0; i < q_rows; i++) { for (unsigned int j = 0; j < q_cols; j++) { double value; if (i < rows && j < cols && get(i, j, value)) quadrants[0].set(i, j, value); } } // Fill Upper Right quadrant from original (starting at (0, start_col_right)). for (unsigned int i = 0; i < q_rows; i++) { for (unsigned int j = 0; j < q_cols; j++) { double value; if (i < rows && (j + start_col_right) < cols && get(i, j + start_col_right, value)) quadrants[1].set(i, j, value); } } // Fill Lower Left quadrant from original (starting at (start_row_bottom, 0)). for (unsigned int i = 0; i < q_rows; i++) { for (unsigned int j = 0; j < q_cols; j++) { double value; if ((i + start_row_bottom) < rows && j < cols && get(i + start_row_bottom, j, value)) quadrants[2].set(i, j, value); } } // Fill Lower Right quadrant from original (starting at (start_row_bottom, start_col_right)). for (unsigned int i = 0; i < q_rows; i++) { for (unsigned int j = 0; j < q_cols; j++) { double value; if ((i + start_row_bottom) < rows && (j + start_col_right) < cols && get(i + start_row_bottom, j + start_col_right, value)) quadrants[3].set(i, j, value); } } return quadrants; } //overloaded output operator to print the matrix // 4 x 4 matrix: // [ 14 14 14 14 // 14 14 14 14 // 14 9 14 14 // 14 14 14 13 ] std::ostream& operator<<(std::ostream& out, const Matrix& m) { out << m.rows << " x " << m.cols << " matrix:" << std::endl; out << "[ "; for (unsigned int i = 0; i < m.rows; i++) { for (unsigned int j = 0; j < m.cols; j++) { out << m.data[i][j]; if(j < m.cols - 1) out << " "; } if(i < m.rows - 1) out << std::endl << " "; } out << " ]"; return out; }