Skip to content

Commit

Permalink
Refactor code
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-foo committed Feb 3, 2024
1 parent 64bee25 commit 9acb0a8
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 22 deletions.
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,40 +35,48 @@ make test / ctest

### Example

### After building the project using make, the following example program can found in build/src directory. Navigate to that directory and run ./Demo to execute the program.

Consider a system of equations in 5 variables: x1 - x5, which is represented as a coefficient matrix A and column vector of constants b. Note that the types of these matrices must be parametrised with `Double`, in the cases where solving equations are involved.

An example program of solving a system with an infinite number of solutions:

```cpp
#include <iostream>

#include "Matrix.h"

// make your own aliases
typedef linalg::Matrix<double> Md;

int main() {

using std::cout;

// A is the coefficient matrix
Md A = {{0,2,2,1,-2},{0,0,1,1,1},{0,0,0,0,2}};
Md A {{0,2,2,1,-2},{0,0,1,1,1},{0,0,0,0,2}};

// b is the column matrix of constants
Md b = {{2},{3},{4}};
Md b {{2},{3},{4}};

linalg::Solution::SystemSolution solution = linalg::solve_linear_system(A, b);

// prints "x1:a1, x2:2+0.5a2, x3:1-a2, x4:a2, x5:2 where a1, a2 are arbitrary parameters"
std::cout << solution << "\n";
cout << solution << "\n";

// prints 2, which is the number of free variables (a1, a2)
std::cout << solution.num_free_variables << "\n";
cout << solution.num_free_variables << "\n";

// fun is a function that takes in a list of initialiser values (each corresponding to the free variables in their natural order (a1, a2, ..., an) and returns the values of all the variables for that particular combination of values
auto fun = solution.get_compute_function();

// setting a1 = 1, a2 = 2
// prints: (1, 3, -1, 2, 2), which corresponds to x1: 1, x2: 3, x3: -1, x4: 2, x5: 2
std::cout << fun({1, 2}) << "\n";
cout << fun({1, 2}) << "\n";

// prints: (2, 3.5, -2, 3, 2)
std::cout << fun({2, 3}) << "\n";
cout << fun({2, 3}) << "\n";

return 0;
}
```
8 changes: 4 additions & 4 deletions include/linalg/Matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,23 +117,23 @@ class Matrix {
friend Solution::SystemSolution solve_linear_system(const Matrix<double>& A, const Matrix<double>& b);
};


int compute_max_in_col(int r, int c, const Matrix<double>& matrix);

//produces a matrix of Row Echelon Form (REF), note: all zero rows are guaranteed to be at bottom of both the REF and RREF.
Matrix<double> gaussian_elimination(const Matrix<double>& matrix);

//produces a matrix of Reduced Row Echelon Form (RREF). note: RREF is unique while REF is not.
Matrix<double> gauss_jordan_elimination(const Matrix<double>& matrix);

int get_rank(const Matrix<double>& m);

// row space and col space are obtained from RREF for simplicity.
TwoDVector<double> get_row_space(const Matrix<double>& m);

TwoDVector<double> get_col_space(const Matrix<double>& m);

Matrix<double> inverse(const Matrix<double>& m);

Solution::SolutionType get_solution_type(const Matrix<double>& A);

Solution::SystemSolution solve_linear_system(const Matrix<double>& A, const Matrix<double>& b);

template <class T>
class IdentityMatrix: public Matrix<T> {
Expand Down
8 changes: 6 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
include_directories(${PROJECT_SOURCE_DIR}/include/linalg)
file(GLOB SOURCES "linalg/*.cpp")
# file(GLOB SOURCES "linalg/*.cpp")
set(SOURCES linalg/Matrix.cpp linalg/Solution.cpp linalg/Vectors.cpp)
add_library(linalg-lib SHARED ${SOURCES})

add_executable (demo linalg/Main.cpp)
add_executable (demo linalg/Demo.cpp)
add_executable (theorems linalg/Theorems.cpp)

target_link_libraries (demo linalg-lib)
target_link_libraries(theorems linalg-lib)
37 changes: 37 additions & 0 deletions src/linalg/Demo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <iostream>

#include "Matrix.h"

// make your own aliases
typedef linalg::Matrix<double> Md;

int main() {

using std::cout;

// A is the coefficient matrix
Md A {{0,2,2,1,-2},{0,0,1,1,1},{0,0,0,0,2}};

// b is the column matrix of constants
Md b {{2},{3},{4}};

linalg::Solution::SystemSolution solution = linalg::solve_linear_system(A, b);

// prints "x1:a1, x2:2+0.5a2, x3:1-a2, x4:a2, x5:2 where a1, a2 are arbitrary parameters"
cout << solution << "\n";

// prints 2, which is the number of free variables (a1, a2)
cout << solution.num_free_variables << "\n";

// fun is a function that takes in a list of initialiser values (each corresponding to the free variables in their natural order (a1, a2, ..., an) and returns the values of all the variables for that particular combination of values
auto fun = solution.get_compute_function();

// setting a1 = 1, a2 = 2
// prints: (1, 3, -1, 2, 2), which corresponds to x1: 1, x2: 3, x3: -1, x4: 2, x5: 2
cout << fun({1, 2}) << "\n";

// prints: (2, 3.5, -2, 3, 2)
cout << fun({2, 3}) << "\n";

return 0;
}
4 changes: 1 addition & 3 deletions src/linalg/Solution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@

#include "Solution.h"

using namespace linalg::Solution;

std::ostream& operator<< (std::ostream& out, SystemSolution s) {
std::ostream& operator<< (std::ostream& out, linalg::Solution::SystemSolution s) {
//to 3sf, if necessary.
out << std::setprecision(3);
if (!s.contains_free_variables()) {
Expand Down
2 changes: 1 addition & 1 deletion src/linalg/Main.cpp → src/linalg/Theorems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ int main() {
// fun theorem stuff
Theorems::verify();

std::cout << "all tests pass!" << "\n";
std::cout << "All theorems verified!" << "\n";

return 0;
}
14 changes: 8 additions & 6 deletions test/EquationSolverTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,32 @@

typedef linalg::Matrix<double> Md;

using namespace linalg::Solution;
using namespace linalg;

// checking types of solutions

TEST(EquationSolverTest, TypeNoSolution) {
// REF of augmented matrix of inconsistent system
Md A {{3,2,3,4},{0,0,1,1},{0,0,0,2}};
EXPECT_EQ(get_solution_type(A), SolutionType::NO_SOLUTION);
EXPECT_EQ(get_solution_type(A), Solution::SolutionType::NO_SOLUTION);
}

TEST(EquationSolverTest, TypeOneSolution) {
// REF of augmented matrix of consistent system (with one soln)
using enum Solution::SolutionType;
Md A {{1,2,3,4},{0,2,0,1},{0,0,-1,2}};
Md B {{1,1,2,3,4},{0,2,0,1,-1},{0,0,4,-1,2},{0,0,0,-1,2},{0,0,0,0,0}};
EXPECT_EQ(get_solution_type(A), SolutionType::ONE_SOLUTION);
EXPECT_EQ(get_solution_type(B), SolutionType::ONE_SOLUTION);
EXPECT_EQ(get_solution_type(A), ONE_SOLUTION);
EXPECT_EQ(get_solution_type(B), ONE_SOLUTION);
}

TEST(EquationSolverTest, TypeInfiniteSolutions) {
// REF of augmented matrix of consistent system (with infinitely many solns)
using enum Solution::SolutionType;
Md A {{5,1,2,3,4},{0,0,-1,0,1},{0,0,0,1,2}};
Md B {{0,1,2,3,4},{0,0,-1,0,1},{0,0,0,1,2}};
EXPECT_EQ(get_solution_type(A), SolutionType::INFINITELY_MANY_SOLUTIONS);
EXPECT_EQ(get_solution_type(B), SolutionType::INFINITELY_MANY_SOLUTIONS);
EXPECT_EQ(get_solution_type(A), INFINITELY_MANY_SOLUTIONS);
EXPECT_EQ(get_solution_type(B), INFINITELY_MANY_SOLUTIONS);
}

// solving the linear systems
Expand Down

0 comments on commit 9acb0a8

Please sign in to comment.