Skip to content

Commit 7d906a5

Browse files
committed
Implement Gaussian Elimination in C++
1 parent c052e21 commit 7d906a5

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#include <algorithm>
2+
#include <cassert>
3+
#include <iostream>
4+
#include <vector>
5+
6+
void gaussian_elimination(std::vector<double>& a, int cols) {
7+
assert(a.size() % cols == 0);
8+
int rows = a.size() / cols;
9+
10+
int row = 0;
11+
12+
// Main loop going through all columns
13+
for (int col = 0; col < cols - 1; ++col) {
14+
// Step 1: finding the maximum element for each column
15+
int max_index = [&]() {
16+
int res = row;
17+
int max_element = a[col + row * cols];
18+
for (int r = row + 1; r < rows; ++r)
19+
if (max_element < std::abs(a[col + r * cols])) {
20+
max_element = std::abs(a[col + r * cols]);
21+
res = r;
22+
}
23+
return res;
24+
}();
25+
26+
// Check to make sure matrix is good!
27+
if (a[col + max_index * cols] == 0) {
28+
std::cout << "matrix is singular!\n";
29+
continue;
30+
}
31+
32+
// Step 2: swap row with highest value for that column to the top
33+
for (int c = 0; c < cols; ++c)
34+
std::swap(a[c + row * cols], a[c + max_index * cols]);
35+
36+
// Loop for all remaining rows
37+
for (int i = row + 1; i < rows; ++i) {
38+
39+
// Step 3: finding fraction
40+
auto fraction = a[col + i * cols] / a[col + row * cols];
41+
42+
// loop through all columns for that row
43+
for (int j = col + 1; j < cols; ++j) {
44+
45+
// Step 4: re-evaluate each element
46+
a[j + i * cols] -= a[j + row * cols] * fraction;
47+
}
48+
49+
// Step 5: Set lower elements to 0
50+
a[col + i * cols] = 0;
51+
}
52+
++row;
53+
}
54+
}
55+
56+
std::vector<double> back_substitution(const std::vector<double>& a, int cols) {
57+
assert(a.size() % cols == 0);
58+
int rows = a.size() / cols;
59+
60+
// Creating the solution Vector
61+
std::vector<double> soln(rows);
62+
63+
// initialize the final element
64+
soln[rows - 1] =
65+
a[cols - 1 + (rows - 1) * cols] / a[cols - 1 - 1 + (rows - 1) * cols];
66+
67+
for (int i = rows - 1; i >= 0; --i) {
68+
auto sum = 0.0;
69+
for (int j = cols - 2; j > i; --j) {
70+
sum += soln[j] * a[j + i * cols];
71+
}
72+
73+
soln[i] = (a[cols - 1 + i * cols] - sum) / a[i + i * cols];
74+
}
75+
76+
return soln;
77+
}
78+
79+
void gaussian_jordan(std::vector<double>& a, int cols) {
80+
assert(a.size() % cols == 0);
81+
// After this, we know what row to start on (r-1)
82+
// to go back through the matrix
83+
int row = 0;
84+
for (int col = 0; col < cols - 1; ++col) {
85+
if (a[col + row * cols] != 0) {
86+
87+
// divide row by pivot and leaving pivot as 1
88+
for (int i = cols - 1; i >= static_cast<int>(col); --i)
89+
a[i + row * cols] /= a[col + row * cols];
90+
91+
// subtract value from above row and set values above pivot to 0
92+
for (int i = 0; i < static_cast<int>(row - 1); ++i)
93+
for (int j = cols - 1; j >= static_cast<int>(col); --j)
94+
a[j + i * cols] -= a[col + i * cols] * a[j + row * cols];
95+
++row;
96+
}
97+
}
98+
}
99+
100+
void print_matrix(const std::vector<double>& a, int cols) {
101+
assert(a.size() % cols == 0);
102+
int rows = a.size() / cols;
103+
for (int i = 0; i < rows; ++i) {
104+
std::cout << "[";
105+
for (int j = 0; j < cols; ++j) {
106+
std::cout << a[j + i * cols] << " ";
107+
}
108+
std::cout << "]\n";
109+
}
110+
}
111+
112+
int main() {
113+
std::vector<double> a = {2, 3, 4, 6, 1, 2, 3, 4, 3, -4, 0, 10};
114+
const int cols = 4;
115+
assert(a.size() % cols == 0);
116+
117+
gaussian_elimination(a, cols);
118+
print_matrix(a, cols);
119+
120+
auto soln = back_substitution(a, 4);
121+
122+
for (auto element : soln)
123+
std::cout << element << std::endl;
124+
125+
gaussian_jordan(a, cols);
126+
print_matrix(a, cols);
127+
128+
soln = back_substitution(a, 4);
129+
130+
for (auto element : soln)
131+
std::cout << element << std::endl;
132+
}

chapters/algorithms/gaussian_elimination/gaussian_elimination.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@ In code, this looks like:
356356
[import:1-45, lang:"julia"](code/julia/gaussian_elimination.jl)
357357
{% sample lang="c" %}
358358
[import:13-44, lang:"c_cpp"](code/c/gaussian_elimination.c)
359+
{% sample lang="cpp" %}
360+
[import:6-54, lang:"c_cpp"](code/c++/gaussian_elimination.cpp)
359361
{% sample lang="rs" %}
360362
[import:41-78, lang:"rust"](code/rust/gaussian_elimination.rs)
361363
{% endmethod %}
@@ -387,6 +389,8 @@ Here it is in code:
387389
{% sample lang="c" %}
388390
This code does not exist yet in C, so here's Julia code (sorry for the inconvenience)
389391
[import:70-98, lang:"julia"](code/julia/gaussian_elimination.jl)
392+
{% sample lang="cpp" %}
393+
[import:79-98, lang:"c_cpp"](code/c++/gaussian_elimination.cpp)
390394
{% sample lang="rs" %}
391395
This code does not exist yet in rust, so here's Julia code (sorry for the inconvenience)
392396
[import:70-98, 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
416420
[import:47-67, lang:"julia"](code/julia/gaussian_elimination.jl)
417421
{% sample lang="c" %}
418422
[import:46-58, lang:"c_cpp"](code/c/gaussian_elimination.c)
423+
{% sample lang="cpp" %}
424+
[import:56-77, lang:"c_cpp"](code/c++/gaussian_elimination.cpp)
419425
{% sample lang="rs" %}
420426
[import:79-94, lang:"rust"](code/rust/gaussian_elimination.rs)
421427
{% endmethod %}
@@ -436,6 +442,8 @@ As for what's next... Well, we are in for a treat! The above algorithm clearly h
436442
[import, lang:"julia"](code/julia/gaussian_elimination.jl)
437443
{% sample lang="c" %}
438444
[import, lang:"c_cpp"](code/c/gaussian_elimination.c)
445+
{% sample lang="cpp" %}
446+
[import, lang:"c_cpp"](code/c++/gaussian_elimination.cpp)
439447
{% sample lang="rs" %}
440448
[import, lang:"rust"](code/rust/gaussian_elimination.rs)
441449
{% endmethod %}

0 commit comments

Comments
 (0)