Skip to content

Commit 3a9e5fa

Browse files
ChrisO345pre-commit-ci[bot]cclauss
authored
Create a Simultaneous Equation Solver Algorithm (TheAlgorithms#8773)
* Added simultaneous_linear_equation_solver.py * Removed Augment class, replaced with recursive functions * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fixed edge cases * Update settings.json --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Christian Clauss <[email protected]>
1 parent 4621b0b commit 3a9e5fa

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

.vscode/settings.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"githubPullRequests.ignoredPullRequestBranches": [
3+
"master"
4+
]
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
"""
2+
https://en.wikipedia.org/wiki/Augmented_matrix
3+
4+
This algorithm solves simultaneous linear equations of the form
5+
λa + λb + λc + λd + ... = γ as [λ, λ, λ, λ, ..., γ]
6+
Where λ & γ are individual coefficients, the no. of equations = no. of coefficients - 1
7+
8+
Note in order to work there must exist 1 equation where all instances of λ and γ != 0
9+
"""
10+
11+
12+
def simplify(current_set: list[list]) -> list[list]:
13+
"""
14+
>>> simplify([[1, 2, 3], [4, 5, 6]])
15+
[[1.0, 2.0, 3.0], [0.0, 0.75, 1.5]]
16+
>>> simplify([[5, 2, 5], [5, 1, 10]])
17+
[[1.0, 0.4, 1.0], [0.0, 0.2, -1.0]]
18+
"""
19+
# Divide each row by magnitude of first term --> creates 'unit' matrix
20+
duplicate_set = current_set.copy()
21+
for row_index, row in enumerate(duplicate_set):
22+
magnitude = row[0]
23+
for column_index, column in enumerate(row):
24+
if magnitude == 0:
25+
current_set[row_index][column_index] = column
26+
continue
27+
current_set[row_index][column_index] = column / magnitude
28+
# Subtract to cancel term
29+
first_row = current_set[0]
30+
final_set = [first_row]
31+
current_set = current_set[1::]
32+
for row in current_set:
33+
temp_row = []
34+
# If first term is 0, it is already in form we want, so we preserve it
35+
if row[0] == 0:
36+
final_set.append(row)
37+
continue
38+
for column_index in range(len(row)):
39+
temp_row.append(first_row[column_index] - row[column_index])
40+
final_set.append(temp_row)
41+
# Create next recursion iteration set
42+
if len(final_set[0]) != 3:
43+
current_first_row = final_set[0]
44+
current_first_column = []
45+
next_iteration = []
46+
for row in final_set[1::]:
47+
current_first_column.append(row[0])
48+
next_iteration.append(row[1::])
49+
resultant = simplify(next_iteration)
50+
for i in range(len(resultant)):
51+
resultant[i].insert(0, current_first_column[i])
52+
resultant.insert(0, current_first_row)
53+
final_set = resultant
54+
return final_set
55+
56+
57+
def solve_simultaneous(equations: list[list]) -> list:
58+
"""
59+
>>> solve_simultaneous([[1, 2, 3],[4, 5, 6]])
60+
[-1.0, 2.0]
61+
>>> solve_simultaneous([[0, -3, 1, 7],[3, 2, -1, 11],[5, 1, -2, 12]])
62+
[6.4, 1.2, 10.6]
63+
>>> solve_simultaneous([])
64+
Traceback (most recent call last):
65+
...
66+
IndexError: solve_simultaneous() requires n lists of length n+1
67+
>>> solve_simultaneous([[1, 2, 3],[1, 2]])
68+
Traceback (most recent call last):
69+
...
70+
IndexError: solve_simultaneous() requires n lists of length n+1
71+
>>> solve_simultaneous([[1, 2, 3],["a", 7, 8]])
72+
Traceback (most recent call last):
73+
...
74+
ValueError: solve_simultaneous() requires lists of integers
75+
>>> solve_simultaneous([[0, 2, 3],[4, 0, 6]])
76+
Traceback (most recent call last):
77+
...
78+
ValueError: solve_simultaneous() requires at least 1 full equation
79+
"""
80+
if len(equations) == 0:
81+
raise IndexError("solve_simultaneous() requires n lists of length n+1")
82+
_length = len(equations) + 1
83+
if any(len(item) != _length for item in equations):
84+
raise IndexError("solve_simultaneous() requires n lists of length n+1")
85+
for row in equations:
86+
if any(not isinstance(column, (int, float)) for column in row):
87+
raise ValueError("solve_simultaneous() requires lists of integers")
88+
if len(equations) == 1:
89+
return [equations[0][-1] / equations[0][0]]
90+
data_set = equations.copy()
91+
if any(0 in row for row in data_set):
92+
temp_data = data_set.copy()
93+
full_row = []
94+
for row_index, row in enumerate(temp_data):
95+
if 0 not in row:
96+
full_row = data_set.pop(row_index)
97+
break
98+
if not full_row:
99+
raise ValueError("solve_simultaneous() requires at least 1 full equation")
100+
data_set.insert(0, full_row)
101+
useable_form = data_set.copy()
102+
simplified = simplify(useable_form)
103+
simplified = simplified[::-1]
104+
solutions: list = []
105+
for row in simplified:
106+
current_solution = row[-1]
107+
if not solutions:
108+
if row[-2] == 0:
109+
solutions.append(0)
110+
continue
111+
solutions.append(current_solution / row[-2])
112+
continue
113+
temp_row = row.copy()[: len(row) - 1 :]
114+
while temp_row[0] == 0:
115+
temp_row.pop(0)
116+
if len(temp_row) == 0:
117+
solutions.append(0)
118+
continue
119+
temp_row = temp_row[1::]
120+
temp_row = temp_row[::-1]
121+
for column_index, column in enumerate(temp_row):
122+
current_solution -= column * solutions[column_index]
123+
solutions.append(current_solution)
124+
final = []
125+
for item in solutions:
126+
final.append(float(round(item, 5)))
127+
return final[::-1]
128+
129+
130+
if __name__ == "__main__":
131+
import doctest
132+
133+
doctest.testmod()
134+
eq = [
135+
[2, 1, 1, 1, 1, 4],
136+
[1, 2, 1, 1, 1, 5],
137+
[1, 1, 2, 1, 1, 6],
138+
[1, 1, 1, 2, 1, 7],
139+
[1, 1, 1, 1, 2, 8],
140+
]
141+
print(solve_simultaneous(eq))
142+
print(solve_simultaneous([[4, 2]]))

0 commit comments

Comments
 (0)