Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Gaussian Elimination in C++ #258

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions contents/gaussian_elimination/code/c++/gaussian_elimination.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <vector>
#include <iomanip>

void gaussian_elimination(std::vector<double>& a, int cols) {
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 = row;
for (int r = row + 1; r < rows; ++r) {
if (a[col + max_index * cols] < std::abs(a[col + r * cols])) {
max_index = r;
}
}

// 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
if (row != max_index) {
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<double> back_substitution(const std::vector<double>& a, int cols) {
int rows = a.size() / cols;

// Creating the solution Vector
std::vector<double> soln(rows);

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<double>& a, int cols) {
// 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 >= 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 < row; ++i)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add brackets to this for loop.

for (int j = cols - 1; j >= col; --j)
a[j + i * cols] -= a[col + i * cols] * a[j + row * cols];
++row;
}
}
}

void print_matrix(const std::vector<double>& a, int cols) {
int rows = a.size() / cols;
for (int i = 0; i < rows; ++i) {
std::cout << "[";
for (int j = 0; j < cols; ++j) {
std::cout << std::fixed << a[j + i * cols] << "\t";
}
std::cout << "]\n";
}
}

int main() {
std::vector<double> a = { 2, 3, 4, 6,
1, 2, 3, 4,
3, -4, 0, 10 };
const int cols = 4;
if (a.size() % cols != 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not have the if statement in the other functions replacing assert. People are going to take them and not the main function when they need a Gaussian Elimination.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above I explained different solutions instead of assert, majority of solutions implied using if. So it is not clear for me what you want to put inside if-statement? As I mentioned above:

  • log the error and crash
  • return the error code
  • throw an exception
    ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should get rid of all asserts and not even replace them with ifs. We can just always assume that the input is correct for the sake of simplicity.
If you still want to have some checks, then inside the if you can have return 0; or a zero matrix or something.

{
std::cout << "The input dimentions are incorrect\n";
return 1;
}

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;
}
8 changes: 8 additions & 0 deletions contents/gaussian_elimination/gaussian_elimination.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:8-53, lang:"c_cpp"](code/c++/gaussian_elimination.cpp)
{% sample lang="rs" %}
[import:41-78, lang:"rust"](code/rust/gaussian_elimination.rs)
{% sample lang="hs" %}
Expand Down Expand Up @@ -389,6 +391,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:67-93, lang:"julia"](code/julia/gaussian_elimination.jl)
{% sample lang="cpp" %}
[import:73-91, 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:67-93, lang:"julia"](code/julia/gaussian_elimination.jl)
Expand Down Expand Up @@ -420,6 +424,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:55-71, lang:"c_cpp"](code/c++/gaussian_elimination.cpp)
{% sample lang="rs" %}
[import:79-94, lang:"rust"](code/rust/gaussian_elimination.rs)
{% sample lang="hs" %}
Expand All @@ -442,6 +448,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)
{% sample lang="hs" %}
Expand Down