From 8394ead07347f855b6a39c45b42753b85e5cf482 Mon Sep 17 00:00:00 2001 From: Anton Te Date: Mon, 16 Jul 2018 00:26:59 -0700 Subject: [PATCH] Implement Gaussian Elimination in C++ --- .../code/c++/gaussian_elimination.cpp | 133 ++++++++++++++++++ .../gaussian_elimination.md | 8 ++ 2 files changed, 141 insertions(+) create mode 100644 contents/gaussian_elimination/code/c++/gaussian_elimination.cpp diff --git a/contents/gaussian_elimination/code/c++/gaussian_elimination.cpp b/contents/gaussian_elimination/code/c++/gaussian_elimination.cpp new file mode 100644 index 000000000..fff28e2b3 --- /dev/null +++ b/contents/gaussian_elimination/code/c++/gaussian_elimination.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include + +void gaussian_elimination(std::vector& a, int cols) { + assert(a.size() % cols == 0); + int rows = a.size() / cols; + + int row = 0; + + // Main loop going through all columns + for (int col = 0; col < cols - 1; ++col) { + // Step 1: finding the maximum element for each column + int max_index = [&]() { + int res = row; + int max_element = a[col + row * cols]; + for (int r = row + 1; r < rows; ++r) + if (max_element < std::abs(a[col + r * cols])) { + max_element = std::abs(a[col + r * cols]); + res = r; + } + return res; + }(); + + // Check to make sure matrix is good! + if (a[col + max_index * cols] == 0) { + std::cout << "matrix is singular!\n"; + continue; + } + + // Step 2: swap row with highest value for that column to the top + for (int c = 0; c < cols; ++c) + std::swap(a[c + row * cols], a[c + max_index * cols]); + + // Loop for all remaining rows + for (int i = row + 1; i < rows; ++i) { + + // Step 3: finding fraction + auto fraction = a[col + i * cols] / a[col + row * cols]; + + // loop through all columns for that row + for (int j = col + 1; j < cols; ++j) { + + // Step 4: re-evaluate each element + a[j + i * cols] -= a[j + row * cols] * fraction; + } + + // Step 5: Set lower elements to 0 + a[col + i * cols] = 0; + } + ++row; + } +} + +std::vector back_substitution(const std::vector& a, int cols) { + assert(a.size() % cols == 0); + int rows = a.size() / cols; + + // Creating the solution Vector + std::vector soln(rows); + + // initialize the final element + soln[rows - 1] = + a[cols - 1 + (rows - 1) * cols] / a[cols - 1 - 1 + (rows - 1) * cols]; + + for (int i = rows - 1; i >= 0; --i) { + auto sum = 0.0; + for (int j = cols - 2; j > i; --j) { + sum += soln[j] * a[j + i * cols]; + } + + soln[i] = (a[cols - 1 + i * cols] - sum) / a[i + i * cols]; + } + + return soln; +} + +void gauss_jordan_elimination(std::vector& a, int cols) { + assert(a.size() % cols == 0); + // After this, we know what row to start on (r-1) + // to go back through the matrix + int row = 0; + for (int col = 0; col < cols - 1; ++col) { + if (a[col + row * cols] != 0) { + + // divide row by pivot and leaving pivot as 1 + for (int i = cols - 1; i >= static_cast(col); --i) + a[i + row * cols] /= a[col + row * cols]; + + // subtract value from above row and set values above pivot to 0 + for (int i = 0; i < static_cast(row - 1); ++i) + for (int j = cols - 1; j >= static_cast(col); --j) + a[j + i * cols] -= a[col + i * cols] * a[j + row * cols]; + ++row; + } + } +} + +void print_matrix(const std::vector& a, int cols) { + assert(a.size() % cols == 0); + int rows = a.size() / cols; + for (int i = 0; i < rows; ++i) { + std::cout << "["; + for (int j = 0; j < cols; ++j) { + std::cout << a[j + i * cols] << " "; + } + std::cout << "]\n"; + } +} + +int main() { + std::vector a = {2, 3, 4, 6, 1, 2, 3, 4, 3, -4, 0, 10}; + const int cols = 4; + assert(a.size() % cols == 0); + + gaussian_elimination(a, cols); + print_matrix(a, cols); + + auto soln = back_substitution(a, 4); + + for (auto element : soln) + std::cout << element << std::endl; + + gauss_jordan_elimination(a, cols); + print_matrix(a, cols); + + soln = back_substitution(a, 4); + + for (auto element : soln) + std::cout << element << std::endl; +} diff --git a/contents/gaussian_elimination/gaussian_elimination.md b/contents/gaussian_elimination/gaussian_elimination.md index 6548edd05..01419307a 100644 --- a/contents/gaussian_elimination/gaussian_elimination.md +++ b/contents/gaussian_elimination/gaussian_elimination.md @@ -356,6 +356,8 @@ In code, this looks like: [import:1-45, lang:"julia"](code/julia/gaussian_elimination.jl) {% sample lang="c" %} [import:13-44, lang:"c_cpp"](code/c/gaussian_elimination.c) +{% sample lang="cpp" %} +[import:6-54, lang:"c_cpp"](code/c++/gaussian_elimination.cpp) {% sample lang="rs" %} [import:41-78, lang:"rust"](code/rust/gaussian_elimination.rs) {% endmethod %} @@ -387,6 +389,8 @@ Here it is in code: {% sample lang="c" %} This code does not exist yet in C, so here's Julia code (sorry for the inconvenience) [import:70-96, lang:"julia"](code/julia/gaussian_elimination.jl) +{% sample lang="cpp" %} +[import:79-98, lang:"c_cpp"](code/c++/gaussian_elimination.cpp) {% sample lang="rs" %} This code does not exist yet in rust, so here's Julia code (sorry for the inconvenience) [import:70-96, lang:"julia"](code/julia/gaussian_elimination.jl) @@ -416,6 +420,8 @@ In code, this involves keeping a rolling sum of all the values we substitute in [import:47-67, lang:"julia"](code/julia/gaussian_elimination.jl) {% sample lang="c" %} [import:46-58, lang:"c_cpp"](code/c/gaussian_elimination.c) +{% sample lang="cpp" %} +[import:56-77, lang:"c_cpp"](code/c++/gaussian_elimination.cpp) {% sample lang="rs" %} [import:79-94, lang:"rust"](code/rust/gaussian_elimination.rs) {% endmethod %} @@ -436,6 +442,8 @@ As for what's next... Well, we are in for a treat! The above algorithm clearly h [import, lang:"julia"](code/julia/gaussian_elimination.jl) {% sample lang="c" %} [import, lang:"c_cpp"](code/c/gaussian_elimination.c) +{% sample lang="cpp" %} +[import, lang:"c_cpp"](code/c++/gaussian_elimination.cpp) {% sample lang="rs" %} [import, lang:"rust"](code/rust/gaussian_elimination.rs) {% endmethod %}