Files
CSCI-1200/hws/matrix_class/Matrix.cpp
JamesFlare1212 4054554203 add hw3 solution
2025-02-10 20:49:28 -05:00

293 lines
8.4 KiB
C++

#include "Matrix.h"
#include <iostream>
#include <iomanip>
//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;
}