|
1 |
| -#include <iostream> |
2 | 1 | #include <algorithm>
|
| 2 | +#include <cmath> |
| 3 | +#include <iostream> |
3 | 4 | #include <stdexcept>
|
4 | 5 | #include <vector>
|
5 |
| -#include <cmath> |
6 |
| -using namespace std; |
7 |
| - |
8 |
| -class EquationSolver |
9 |
| -{ |
10 |
| -private: |
11 |
| - |
12 |
| - // subtract row from another row after multiplcation |
13 |
| - void subRow(vector<long double> &toBeSubtracted, const vector<long double> &toSubtract, |
14 |
| - long double mult, int start) |
15 |
| - { |
16 |
| - for (int i = start; i < toBeSubtracted.size(); i++) |
17 |
| - toBeSubtracted[i] -= mult * toSubtract[i]; |
18 |
| - } |
19 |
| - // A start variable is given since if we know all values are 0, we don't need |
20 |
| - // to subtract. |
21 | 6 |
|
22 | 7 |
|
23 |
| - // swap two rows |
24 |
| - void swapRow(vector<long double> &eqn1, vector<long double> &eqn2, int start) |
25 |
| - { |
26 |
| - for (int i = start; i < eqn1.size(); i++) |
27 |
| - swap(eqn1[i], eqn2[i]); |
28 |
| - } |
29 |
| - // A start variable is given since if we know all values are 0, we don't need |
30 |
| - // to swap. |
31 |
| - |
32 |
| - |
33 |
| - int gaussianElimination(vector<vector<long double>> &eqns, int varc) |
34 |
| - { |
35 |
| - // 'eqns' is the matrix, 'varc' is no. of vars |
36 |
| - int err = 0; // marker for if matrix is singular |
37 |
| - for (int i = 0; i < varc - 1; i++) |
38 |
| - { |
39 |
| - long double pivot = fabsl(eqns[i][i]); |
40 |
| - int newRow = i; |
41 |
| - for (int j = i + 1; j < varc; j++) |
42 |
| - { |
43 |
| - if (fabsl(eqns[j][i]) > pivot) |
44 |
| - { |
45 |
| - pivot = fabsl(eqns[j][i]); |
46 |
| - newRow = j; |
47 |
| - } |
48 |
| - } |
| 8 | +int gaussianElimination(std::vector< std::vector<double> > &eqns, int varc) { |
| 9 | + // 'eqns' is the matrix, 'varc' is no. of vars |
| 10 | + int err = 0; // marker for if matrix is singular |
| 11 | + for (int i = 0; i < varc - 1; i++) { |
| 12 | + double pivot = fabs(eqns[i][i]); |
| 13 | + int newRow = i; |
49 | 14 |
|
50 |
| - if (pivot == 0.0) |
51 |
| - { |
52 |
| - err = 1; // Marking that matrix is singular |
53 |
| - continue; |
| 15 | + for (int j = i + 1; j < varc; j++) { |
| 16 | + if (fabs(eqns[j][i]) > pivot) { |
| 17 | + pivot = fabs(eqns[j][i]); |
| 18 | + newRow = j; |
54 | 19 | }
|
55 |
| - if (newRow != i) |
56 |
| - swapRow(eqns[newRow], eqns[i], i); |
57 |
| - |
58 |
| - for (int j = i + 1; j < varc; j++) |
59 |
| - if (eqns[j][i]) |
60 |
| - subRow(eqns[j], eqns[i], (eqns[j][i] / eqns[i][i]), i); |
61 | 20 | }
|
62 | 21 |
|
63 |
| - if (eqns[varc - 1][varc - 1] == 0 || err) |
64 |
| - { |
65 |
| - if (eqns[varc - 1][varc] == 0 || err) |
66 |
| - return 1; // Error code: Singular matrix |
67 |
| - else |
68 |
| - return 2; // Error code: No solutions |
69 |
| - // Cannot solve since final equation is '0*xn = c' |
| 22 | + if (pivot == 0.0) { |
| 23 | + err = 1; // Marking that matrix is singular |
| 24 | + continue; |
70 | 25 | }
|
71 |
| - return 0; // Successful |
72 |
| - } |
73 | 26 |
|
| 27 | + if (newRow != i) // Swapping the rows if new row with higher pivot is found |
| 28 | + std::swap(eqns[newRow], eqns[i]); // C++ swap function |
74 | 29 |
|
75 |
| - void gaussJordan(vector<vector<long double>> &eqns, int varc) |
76 |
| - { |
77 |
| - // 'eqns' is the (Row-echelon) matrix, 'varc' is no. of vars |
78 |
| - for (int i = varc - 1; i >= 0; i--) |
79 |
| - { |
80 |
| - eqns[i][varc] /= eqns[i][i]; |
81 |
| - eqns[i][i] = 1; // We know that the only entry in this row is 1 |
82 |
| - |
83 |
| - for (int j = i - 1; j >= 0; j--) // subtracting rows from below |
84 |
| - { |
85 |
| - eqns[j][varc] -= eqns[j][i] * eqns[i][varc]; |
86 |
| - eqns[j][i] = 0; // We also set all the other values in row to 0 directly |
87 |
| - } |
| 30 | + for (int j = i + 1; j < varc; j++) { |
| 31 | + if (eqns[j][i]) { |
| 32 | + double mult = eqns[j][i] / eqns[i][i]; |
| 33 | + eqns[j][i] = 0.0; |
| 34 | + for (int k = i + 1; k < (varc + 1); k++) // k doesn't start at 0, since |
| 35 | + eqns[j][k] -= mult * eqns[i][k]; // values before from 0 to i |
| 36 | + } // are already 0 |
88 | 37 | }
|
89 | 38 | }
|
90 | 39 |
|
| 40 | + if (eqns[varc - 1][varc - 1] == 0 || err) { |
| 41 | + if (eqns[varc - 1][varc] == 0 || err) |
| 42 | + return 1; // Error code: Singular matrix |
| 43 | + else |
| 44 | + return 2; // Error code: No solutions |
| 45 | + // Cannot solve since final equation is '0*xn = c' |
| 46 | + } |
| 47 | + |
| 48 | + return 0; // Successful |
| 49 | +} |
| 50 | + |
91 | 51 |
|
92 |
| - vector<long double> backSubs(vector<vector<long double>> &eqns, int varc) |
93 |
| - { |
94 |
| - // 'eqns' is matrix, 'varc' is no. of variables |
95 |
| - vector<long double> ans(varc); |
96 |
| - for (int i = varc - 1; i >= 0; i--) |
97 |
| - { |
98 |
| - long double sum = 0; |
99 |
| - for (int j = i + 1; j < varc; j++) |
100 |
| - sum += eqns[i][j] * ans[j]; |
| 52 | +void gaussJordan(std::vector< std::vector<double> > &eqns, int varc) { |
| 53 | + // 'eqns' is the (Row-echelon) matrix, 'varc' is no. of vars |
| 54 | + for (int i = varc - 1; i >= 0; i--) { |
| 55 | + eqns[i][varc] /= eqns[i][i]; |
| 56 | + eqns[i][i] = 1; // We know that the only entry in this row is 1 |
101 | 57 |
|
102 |
| - ans[i] = (eqns[i][varc] - sum) / eqns[i][i]; |
| 58 | + // subtracting rows from below |
| 59 | + for (int j = i - 1; j >= 0; j--) { |
| 60 | + eqns[j][varc] -= eqns[j][i] * eqns[i][varc]; |
| 61 | + eqns[j][i] = 0; // We also set all the other values in row to 0 directly |
103 | 62 | }
|
104 |
| - return ans; |
105 | 63 | }
|
| 64 | +} |
| 65 | + |
106 | 66 |
|
107 |
| -public: |
108 |
| - vector<long double> solveByGaussJordan(vector< vector<long double> > eqns, int varc) |
109 |
| - { |
110 |
| - int status = this->gaussianElimination(eqns, varc); |
111 |
| - switch (status) |
112 |
| - { |
113 |
| - case 0: |
114 |
| - break; |
| 67 | +std::vector<double> backSubs(std::vector<std::vector<double>> &eqns, int varc) |
| 68 | +{ |
| 69 | + // 'eqns' is matrix, 'varc' is no. of variables |
| 70 | + std::vector<double> ans(varc); |
| 71 | + for (int i = varc - 1; i >= 0; i--) { |
| 72 | + double sum = 0; |
| 73 | + for (int j = i + 1; j < varc; j++) |
| 74 | + sum += eqns[i][j] * ans[j]; |
| 75 | + |
| 76 | + ans[i] = (eqns[i][varc] - sum) / eqns[i][i]; |
| 77 | + } |
| 78 | + return ans; |
| 79 | +} |
115 | 80 |
|
116 |
| - case 1: |
117 |
| - throw runtime_error("Singular matrix"); |
118 | 81 |
|
119 |
| - case 2: |
120 |
| - throw runtime_error("No solutions"); |
121 |
| - } |
| 82 | +std::vector<double> solveByGaussJordan(std::vector<std::vector<double>> eqns, int varc) { |
| 83 | + int status = gaussianElimination(eqns, varc); |
| 84 | + switch (status) { |
| 85 | + case 0: |
| 86 | + break; |
122 | 87 |
|
123 |
| - this->gaussJordan(eqns, varc); |
| 88 | + case 1: |
| 89 | + std::cout << "Singular matrix" << std::endl; |
| 90 | + return std::vector<double>(0); // return empty vector in case of no solutions |
124 | 91 |
|
125 |
| - vector<long double> ans(varc); |
126 |
| - for (int i = 0; i < varc; i++) |
127 |
| - ans[i] = eqns[i][varc]; |
128 |
| - return ans; |
| 92 | + case 2: |
| 93 | + std::cout << "No solutions" << std::endl; |
| 94 | + return std::vector<double>(0); // return empty vectors in case of no solutions |
129 | 95 | }
|
130 | 96 |
|
131 |
| - vector<long double> solveByBacksubs(vector< vector<long double> > eqns, int varc) |
132 |
| - { |
133 |
| - int status = this->gaussianElimination(eqns, varc); |
134 |
| - switch (status) |
135 |
| - { |
136 |
| - case 0: |
137 |
| - break; |
| 97 | + gaussJordan(eqns, varc); |
138 | 98 |
|
139 |
| - case 1: |
140 |
| - throw runtime_error("Singular matrix"); |
| 99 | + std::vector<double> ans(varc); |
| 100 | + for (int i = 0; i < varc; i++) |
| 101 | + ans[i] = eqns[i][varc]; |
| 102 | + return ans; |
| 103 | +} |
141 | 104 |
|
142 |
| - case 2: |
143 |
| - throw runtime_error("No solutions"); |
144 |
| - } |
145 | 105 |
|
146 |
| - vector<long double> ans = this->backSubs(eqns, varc); |
147 |
| - return ans; |
| 106 | +std::vector<double> solveByBacksubs(std::vector<std::vector<double>> eqns, int varc) { |
| 107 | + int status = gaussianElimination(eqns, varc); |
| 108 | + switch (status) { |
| 109 | + case 0: |
| 110 | + break; |
| 111 | + |
| 112 | + case 1: |
| 113 | + std::cout << "Singular matrix" << std::endl; |
| 114 | + return std::vector<double>(0); // return empty vectors in case of no solutions |
| 115 | + |
| 116 | + case 2: |
| 117 | + std::cout << "No solutions" << std::endl; |
| 118 | + return std::vector<double>(0); // return empty vectors in case of no solutions |
148 | 119 | }
|
149 |
| -}; |
| 120 | + |
| 121 | + std::vector<double> ans = backSubs(eqns, varc); |
| 122 | + return ans; |
| 123 | +} |
| 124 | + |
150 | 125 |
|
151 | 126 | int main() {
|
152 | 127 | int varc = 3;
|
153 |
| - vector< vector<long double> > equations { { 2, 3, 4, 6 }, |
154 |
| - { 1, 2, 3, 4 }, |
155 |
| - { 3, -4, 0, 10 }}; |
156 |
| - EquationSolver solver; |
157 |
| - vector<long double> ans; |
158 |
| - try |
159 |
| - { |
160 |
| - ans = solver.solveByGaussJordan(equations, varc); |
161 |
| - } |
162 |
| - catch(runtime_error &e) |
163 |
| - { |
164 |
| - cout << "Error found: " << e.what() << endl; |
165 |
| - return -1; |
| 128 | + std::vector< std::vector<double> > equations{ |
| 129 | + {2, 3, 4, 6}, |
| 130 | + {1, 2, 3, 4}, |
| 131 | + {3, -4, 0, 10}}; |
| 132 | + |
| 133 | + std::vector<double> ans; |
| 134 | + |
| 135 | + ans = solveByGaussJordan(equations, varc); |
| 136 | + |
| 137 | + if (ans.empty()) { // If ans is empty, then no unique solutions exist |
| 138 | + std::cout << "No solution" << std::endl; |
| 139 | + } else { |
| 140 | + std::cout << "The solution is (by Gauss Jordan)," << std::endl |
| 141 | + << "x == " << ans[0] << std::endl |
| 142 | + << "y == " << ans[1] << std::endl |
| 143 | + << "z == " << ans[2] << std::endl; |
166 | 144 | }
|
167 | 145 |
|
168 |
| - cout << "The solution is (by Gauss-Jordan)," << endl |
169 |
| - << "x == " << ans[0] << endl |
170 |
| - << "y == " << ans[1] << endl |
171 |
| - << "z == " << ans[2] << endl << endl; |
| 146 | + ans = solveByBacksubs(equations, varc); |
172 | 147 |
|
173 |
| - try |
174 |
| - { |
175 |
| - ans = solver.solveByBacksubs(equations, varc); |
| 148 | + if (ans.empty()) { // If ans is empty, then no unique solutions exist |
| 149 | + std::cout << "No solution" << std::endl; |
| 150 | + } else { |
| 151 | + std::cout << "The solution is (by Backsubstitution)," << std::endl |
| 152 | + << "x == " << ans[0] << std::endl |
| 153 | + << "y == " << ans[1] << std::endl |
| 154 | + << "z == " << ans[2] << std::endl; |
176 | 155 | }
|
177 |
| - catch (runtime_error &e) |
178 |
| - { |
179 |
| - cout << "Error found: " << e.what() << endl; |
180 |
| - return -1; |
181 |
| - } |
182 |
| - |
183 |
| - cout << "The solution is (by Backsubstitution)," << endl |
184 |
| - << "x == " << ans[0] << endl |
185 |
| - << "y == " << ans[1] << endl |
186 |
| - << "z == " << ans[2] << endl; |
187 | 156 | }
|
0 commit comments