-
-
Notifications
You must be signed in to change notification settings - Fork 360
"Gaussian Elimination" Implementation in C++ #555
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
Changes from 2 commits
e9527bb
53dbd1f
daa272e
08bf7f4
64426a1
fbe7bbc
70ca766
8ae70e6
e04518e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
#include <iostream> | ||
#include <algorithm> | ||
#include <stdexcept> | ||
#include <vector> | ||
#include <cmath> | ||
using namespace std; | ||
|
||
class EquationSolver | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There really is no need in making a class for solving Gaussian elimination. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, should I just define each function individually, because I thought encapsulating it would make it more user-friendly and show how it can be used to solve equations. |
||
{ | ||
private: | ||
|
||
// subtract row from another row after multiplcation | ||
void subRow(vector<long double> &toBeSubtracted, const vector<long double> &toSubtract, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no need of making this function if it's used in one place. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the row subtraction function was being showcased in the documentation, I thought a special mention would be necessary. |
||
long double mult, int start) | ||
{ | ||
for (int i = start; i < toBeSubtracted.size(); i++) | ||
toBeSubtracted[i] -= mult * toSubtract[i]; | ||
} | ||
// A start variable is given since if we know all values are 0, we don't need | ||
// to subtract. | ||
|
||
|
||
// swap two rows | ||
void swapRow(vector<long double> &eqn1, vector<long double> &eqn2, int start) | ||
{ | ||
for (int i = start; i < eqn1.size(); i++) | ||
swap(eqn1[i], eqn2[i]); | ||
} | ||
// A start variable is given since if we know all values are 0, we don't need | ||
// to swap. | ||
|
||
|
||
int gaussianElimination(vector<vector<long double>> &eqns, int varc) | ||
{ | ||
// 'eqns' is the matrix, 'varc' is no. of vars | ||
int err = 0; // marker for if matrix is singular | ||
for (int i = 0; i < varc - 1; i++) | ||
{ | ||
long double pivot = fabsl(eqns[i][i]); | ||
int newRow = i; | ||
for (int j = i + 1; j < varc; j++) | ||
{ | ||
if (fabsl(eqns[j][i]) > pivot) | ||
{ | ||
pivot = fabsl(eqns[j][i]); | ||
newRow = j; | ||
} | ||
} | ||
|
||
if (pivot == 0.0) | ||
{ | ||
err = 1; // Marking that matrix is singular | ||
continue; | ||
} | ||
if (newRow != i) | ||
swapRow(eqns[newRow], eqns[i], i); | ||
|
||
for (int j = i + 1; j < varc; j++) | ||
if (eqns[j][i]) | ||
subRow(eqns[j], eqns[i], (eqns[j][i] / eqns[i][i]), i); | ||
} | ||
|
||
if (eqns[varc - 1][varc - 1] == 0 || err) | ||
{ | ||
if (eqns[varc - 1][varc] == 0 || err) | ||
return 1; // Error code: Singular matrix | ||
else | ||
return 2; // Error code: No solutions | ||
// Cannot solve since final equation is '0*xn = c' | ||
} | ||
return 0; // Successful | ||
} | ||
|
||
|
||
void gaussJordan(vector<vector<long double>> &eqns, int varc) | ||
{ | ||
// 'eqns' is the (Row-echelon) matrix, 'varc' is no. of vars | ||
for (int i = varc - 1; i >= 0; i--) | ||
{ | ||
eqns[i][varc] /= eqns[i][i]; | ||
eqns[i][i] = 1; // We know that the only entry in this row is 1 | ||
|
||
for (int j = i - 1; j >= 0; j--) // subtracting rows from below | ||
{ | ||
eqns[j][varc] -= eqns[j][i] * eqns[i][varc]; | ||
eqns[j][i] = 0; // We also set all the other values in row to 0 directly | ||
} | ||
} | ||
} | ||
|
||
|
||
vector<long double> backSubs(vector<vector<long double>> &eqns, int varc) | ||
{ | ||
// 'eqns' is matrix, 'varc' is no. of variables | ||
vector<long double> ans(varc); | ||
for (int i = varc - 1; i >= 0; i--) | ||
{ | ||
long double sum = 0; | ||
for (int j = i + 1; j < varc; j++) | ||
sum += eqns[i][j] * ans[j]; | ||
|
||
ans[i] = (eqns[i][varc] - sum) / eqns[i][i]; | ||
} | ||
return ans; | ||
} | ||
|
||
public: | ||
vector<long double> solveByGaussJordan(vector< vector<long double> > eqns, int varc) | ||
{ | ||
int status = this->gaussianElimination(eqns, varc); | ||
switch (status) | ||
{ | ||
case 0: | ||
break; | ||
|
||
case 1: | ||
throw runtime_error("Singular matrix"); | ||
|
||
case 2: | ||
throw runtime_error("No solutions"); | ||
} | ||
|
||
this->gaussJordan(eqns, varc); | ||
|
||
vector<long double> ans(varc); | ||
for (int i = 0; i < varc; i++) | ||
ans[i] = eqns[i][varc]; | ||
return ans; | ||
} | ||
|
||
vector<long double> solveByBacksubs(vector< vector<long double> > eqns, int varc) | ||
{ | ||
int status = this->gaussianElimination(eqns, varc); | ||
switch (status) | ||
{ | ||
case 0: | ||
break; | ||
|
||
case 1: | ||
throw runtime_error("Singular matrix"); | ||
|
||
case 2: | ||
throw runtime_error("No solutions"); | ||
} | ||
|
||
vector<long double> ans = this->backSubs(eqns, varc); | ||
return ans; | ||
} | ||
}; | ||
|
||
int main() { | ||
int varc = 3; | ||
vector< vector<long double> > equations { { 2, 3, 4, 6 }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why use |
||
{ 1, 2, 3, 4 }, | ||
{ 3, -4, 0, 10 }}; | ||
EquationSolver solver; | ||
vector<long double> ans; | ||
try | ||
{ | ||
ans = solver.solveByGaussJordan(equations, varc); | ||
} | ||
catch(runtime_error &e) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a big fan of try catch. |
||
{ | ||
cout << "Error found: " << e.what() << endl; | ||
return -1; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Print the matrix after the eliminations. |
||
cout << "The solution is (by Gauss-Jordan)," << endl | ||
<< "x == " << ans[0] << endl | ||
<< "y == " << ans[1] << endl | ||
<< "z == " << ans[2] << endl << endl; | ||
|
||
try | ||
{ | ||
ans = solver.solveByBacksubs(equations, varc); | ||
} | ||
catch (runtime_error &e) | ||
{ | ||
cout << "Error found: " << e.what() << endl; | ||
return -1; | ||
} | ||
|
||
cout << "The solution is (by Backsubstitution)," << endl | ||
<< "x == " << ans[0] << endl | ||
<< "y == " << ans[1] << endl | ||
<< "z == " << ans[2] << endl; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the use of
using namespace std
is a good idea for the philosophy of AAA is. The idea is for the AAA to be used by new comers to the language to learn, also for people to use the algorithm in real work cases and show case the algorithm. I don't believe thatusing namespace std
achieves this.