add hw3 solution

This commit is contained in:
JamesFlare1212
2025-02-10 20:49:15 -05:00
parent 2c07e10ea4
commit 4054554203
5 changed files with 513 additions and 17 deletions

View File

@@ -50,6 +50,7 @@
"sstream": "cpp", "sstream": "cpp",
"stdexcept": "cpp", "stdexcept": "cpp",
"streambuf": "cpp", "streambuf": "cpp",
"typeinfo": "cpp" "typeinfo": "cpp",
"cassert": "cpp"
} }
} }

292
hws/matrix_class/Matrix.cpp Normal file
View File

@@ -0,0 +1,292 @@
#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;
}

76
hws/matrix_class/Matrix.h Normal file
View File

@@ -0,0 +1,76 @@
#ifndef MATRIX_H
#define MATRIX_H
#include <iostream>
#include <cmath>
class Matrix {
private:
unsigned int rows;
unsigned int cols;
double** data;
//allocate memory and fill with a given value
void allocateMemory(unsigned int r, unsigned int c, double fill);
//deallocate memory
void deallocateMemory();
public:
////Constructors
Matrix();
Matrix(unsigned int r, unsigned int c, double fill);
//copy constructor
Matrix(const Matrix& other);
////Destructor
~Matrix();
////Accessors
Matrix& operator=(const Matrix& other);
unsigned int num_rows() const;
unsigned int num_cols() const;
//deallocates memory and resets rows/cols to 0)
void clear();
//if (row, col) is within bounds, stores the element in `value` and returns true;
//otherwise, returns false
bool get(unsigned int row, unsigned int col, double &value) const;
////Modifier
//if (row, col) is within bounds, sets the element to `value` and returns true;
//otherwise, returns false.
bool set(unsigned int row, unsigned int col, double value);
//multiplies every element in the matrix by the provided coefficient
void multiply_by_coefficient(double coeff);
//swaps two rows of the matrix. Returns true if both indices are valid,
//false otherwise
bool swap_row(unsigned int row1, unsigned int row2);
//transposes the matrix in place (switches rows and columns).
void transpose();
//adds another matrix to this one element-wise (if dimensions match) and returns true;
//otherwise, returns false.
bool add(const Matrix& other);
//subtracts another matrix from this one element-wise (if dimensions match)
//and returns true; otherwise, returns false.
bool subtract(const Matrix& other);
//returns a new dynamically allocated array (of size num_cols)
//containing the elements in the specified row.
double* get_row(unsigned int row) const;
//returns a new dynamically allocated array (of size num_rows)
//containing the elements in the specified column.
double* get_col(unsigned int col) const;
//divides the matrix into four quadrants and returns a pointer to an array of
//4 Matrix objects: Upper Left, Upper Right, Lower Left, Lower Right.
//each quadrant is of size ceil(rows/2) x ceil(cols/2)
//and the quadrants overlap when the dimensions are odd.
Matrix* quarter() const;
////Operators
//equality operator: two matrices are equal if they have the same dimensions and
//every corresponding element differs by no more than a small epsilon.
bool operator==(const Matrix& other) const;
//inequality operator
bool operator!=(const Matrix& other) const;
//overloaded output operator for printing the matrix
friend std::ostream& operator<<(std::ostream& out, const Matrix& m);
};
#endif

View File

@@ -1,7 +1,7 @@
HOMEWORK 3: MATRIX CLASS HOMEWORK 3: MATRIX CLASS
NAME: < insert name > NAME: Jinshan Zhou
COLLABORATORS AND OTHER RESOURCES: COLLABORATORS AND OTHER RESOURCES:
@@ -10,13 +10,13 @@ List the names of everyone you talked to about this assignment
LMS, etc.), and all of the resources (books, online reference LMS, etc.), and all of the resources (books, online reference
material, etc.) you consulted in completing this assignment. material, etc.) you consulted in completing this assignment.
< insert collaborators / resources > cmath fabs method. Lecture notes about ** pointers and destructors.
Remember: Your implementation for this assignment must be done on your Remember: Your implementation for this assignment must be done on your
own, as described in "Academic Integrity for Homework" handout. own, as described in "Academic Integrity for Homework" handout.
ESTIMATE OF # OF HOURS SPENT ON THIS ASSIGNMENT: < insert # hours > ESTIMATE OF # OF HOURS SPENT ON THIS ASSIGNMENT: 14 hr
@@ -27,25 +27,25 @@ number of columns. You should assume that calling new [] or delete []
on an array will take time proportional to the number of elements in on an array will take time proportional to the number of elements in
the array. the array.
get get -> O(1)
set set -> O(1)
num_rows num_rows -> O(1)
get_column get_column -> O(m)
operator<< operator<< -> O(m*n)
quarter quarter -> O(m*n)
operator== operator== -> O(m*n)
operator!= operator!= -> O(m*n)
swap_rows swap_rows -> O(1)
rref (provided in matrix_main.cpp) rref (provided in matrix_main.cpp) -> O(m^2 * n)
@@ -55,6 +55,17 @@ What tools did you use (gdb/lldb/Visual Studio debugger,
Valgrind/Dr. Memory, std::cout & print, etc.)? How did you test the Valgrind/Dr. Memory, std::cout & print, etc.)? How did you test the
"corner cases" of your Matrix class design & implementation? "corner cases" of your Matrix class design & implementation?
I used gdb inside VSCode to debug my program. I also used the information
from the submitty autograder (Dr. Memory) to help me find bugs in my code.
I basiclly find what's name and function of the methods of Martix class,
and change my code bit by bit to fit the expected output.
MISC. COMMENTS TO GRADER: MISC. COMMENTS TO GRADER:
(optional, please be concise!) (optional, please be concise!)
REFLECTION:
As the pointer adding up, the complexity of the program will increase.
I think it is important to understand where do pointers points to and
delete them when they are not needed anymore. It's quiet tricky and I
got a lot of memory leaks in my code at first. But the error message in
Dr. Memory shows which line caused the problem, so I was able to fix it.

View File

@@ -33,10 +33,8 @@ int main(){
std::cout << "Completed all simple tests." << std::endl; std::cout << "Completed all simple tests." << std::endl;
//Uncomment this to allocate a lot of 100x100 matrices so leaks will be bigger. //Uncomment this to allocate a lot of 100x100 matrices so leaks will be bigger.
/*
BatchTest(100,0.1,100,100,50); BatchTest(100,0.1,100,100,50);
std::cout << "Completed all batch tests." << std::endl; std::cout << "Completed all batch tests." << std::endl;
*/
StudentTest(); StudentTest();
std::cout << "Completed all student tests." << std::endl; std::cout << "Completed all student tests." << std::endl;
@@ -199,10 +197,128 @@ void SimpleTest(){ //well behaved getrow/read after
} }
//Write your own test cases here //Write your own test cases here
void StudentTest(){ void StudentTest() {
//Test transpose
Matrix m(2, 3, 0);
m.set(0, 0, 1);
m.set(0, 1, 2);
m.set(0, 2, 3);
m.set(1, 0, 4);
m.set(1, 1, 5);
m.set(1, 2, 6);
m.transpose();
assert(m.num_rows() == 3);
assert(m.num_cols() == 2);
double val;
m.get(0, 0, val);
assert(double_compare(val, 1.0));
m.get(0, 1, val);
assert(double_compare(val, 4.0));
m.get(1, 0, val);
assert(double_compare(val, 2.0));
m.get(2, 1, val);
assert(double_compare(val, 6.0));
//Test quarter with odd dimensions
Matrix q(5, 5, 1);
Matrix* quarters = q.quarter();
assert(quarters != nullptr);
//each quadrant should be 3x3 (ceiling: (5+1)/2 == 3)
assert(quarters[0].num_rows() == 3);
assert(quarters[0].num_cols() == 3);
assert(quarters[1].num_rows() == 3);
assert(quarters[1].num_cols() == 3);
assert(quarters[2].num_rows() == 3);
assert(quarters[2].num_cols() == 3);
assert(quarters[3].num_rows() == 3);
assert(quarters[3].num_cols() == 3);
//verify that the quadrants hold the expected values.
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
quarters[0].get(i, j, val);
assert(double_compare(val, 1.0));
quarters[1].get(i, j, val);
assert(double_compare(val, 1.0));
quarters[2].get(i, j, val);
assert(double_compare(val, 1.0));
quarters[3].get(i, j, val);
assert(double_compare(val, 1.0));
}
}
delete[] quarters;
//Test add and subtract
Matrix a(2, 2, 2);
Matrix b(2, 2, 3);
assert(a.add(b)); // Now a is all 5's.
double v;
a.get(0, 0, v);
assert(double_compare(v, 5.0));
assert(a.subtract(b)); // Now a is back to all 2's.
a.get(0, 0, v);
assert(double_compare(v, 2.0));
//Test multiply by coefficient
a.multiply_by_coefficient(2.5); //Now a is all 5's (2*2.5).
a.get(0, 0, v);
assert(double_compare(v, 5.0));
//Test get_row
double* row = a.get_row(0);
assert(row != nullptr);
assert(double_compare(row[0], 5.0));
assert(double_compare(row[1], 5.0));
delete[] row;
// Test get_col
double* col = a.get_col(1);
assert(col != nullptr);
assert(double_compare(col[0], 5.0));
assert(double_compare(col[1], 5.0));
delete[] col;
//Test clear
a.clear();
assert(a.num_rows() == 0 && a.num_cols() == 0);
//Test swap_row
Matrix s(3, 2, 0);
s.set(0, 0, 1); s.set(0, 1, 2);
s.set(1, 0, 3); s.set(1, 1, 4);
s.set(2, 0, 5); s.set(2, 1, 6);
//swap row 0 and row 2
assert(s.swap_row(0, 2));
s.get(0, 0, val);
assert(double_compare(val, 5.0));
s.get(0, 1, val);
assert(double_compare(val, 6.0));
s.get(2, 0, val);
assert(double_compare(val, 1.0));
s.get(2, 1, val);
assert(double_compare(val, 2.0));
//invalid swap should return false.
assert(!s.swap_row(0, 3));
//Test copy constructor and assignment operator.
Matrix orig(2, 3, 7);
Matrix copy(orig); // Using copy constructor.
Matrix assign;
assign = orig; // Using assignment operator.
//change orig to ensure copy and assign remain unchanged.
orig.set(0, 0, 10);
orig.get(0, 0, val);
assert(double_compare(val, 10.0));
copy.get(0, 0, val);
assert(double_compare(val, 7.0));
assign.get(0, 0, val);
assert(double_compare(val, 7.0));
//Test out-of-bound get and set
assert(!orig.get(5, 5, val));
assert(!orig.set(5, 5, 3.0));
} }
////////////////Utility functions////////////////////// ////////////////Utility functions//////////////////////
/* Function that quickly populates a rows x cols matrix with values from /* Function that quickly populates a rows x cols matrix with values from