Skip to content

Commit 41d488f

Browse files
committed
v0.3.4 Use The Gaussian-Jordan Algorithm, rebuild whole balancer by Chemical Equation Balancing. G.R. Blakley. Stable now.
1 parent 6c5f873 commit 41d488f

File tree

7 files changed

+227
-168
lines changed

7 files changed

+227
-168
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "lib_xch"
3-
version = "0.3.3"
3+
version = "0.3.4"
44
authors = ["LEXUGE <LEXUGEyky@outlook.com>"]
55
description = "Crate xch-ceb's official lib"
66
license = "GPL-3.0"

src/balancer_mod/gauss_eliminate.rs

+195
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// Copyright 2017-2018 LEXUGE
2+
//
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU General Public License
14+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
// Overall: This is the source code of the AlphaForce Balancer.
17+
18+
use handler::{ErrorCases, ResultHandler};
19+
use handler::ErrorCases::Unsolvable;
20+
use handler::WarnCases::{FreeVariablesDetected, NoWarn};
21+
use super::frac_util::Frac;
22+
23+
pub struct GaussianElimination {
24+
matrix_a: Vec<Vec<Frac>>, // A n*n matrix.
25+
matrix_b: Vec<Frac>, // A n*1 matrix.
26+
n: usize,
27+
m: usize,
28+
}
29+
30+
struct Pivots {
31+
col: Vec<usize>,
32+
row: Vec<usize>,
33+
}
34+
35+
impl GaussianElimination {
36+
pub fn new(matrix_a: Vec<Vec<Frac>>, matrix_b: Vec<Frac>, n: usize, m: usize) -> Self {
37+
// Create a GaussianElimination Solution.
38+
Self {
39+
matrix_a: matrix_a,
40+
matrix_b: matrix_b,
41+
n: n,
42+
m: m,
43+
}
44+
}
45+
46+
pub fn solve(&mut self) -> Result<ResultHandler<Vec<Frac>>, ErrorCases> {
47+
// The Gaussian-Jordan Algorithm
48+
for i in 0..self.n {
49+
let leftmosti = match self.get_leftmost_row(i) {
50+
Some(s) => s,
51+
None => continue,
52+
};
53+
self.matrix_a.swap(i, leftmosti);
54+
self.matrix_b.swap(i, leftmosti);
55+
let j = match self.get_pivot(i) {
56+
// if left most has no pivot, just continue.
57+
Some(s) => s,
58+
None => continue,
59+
};
60+
let maxi = self.get_max_abs_row(i, j)?;
61+
if self.matrix_a[maxi][j].numerator != 0 {
62+
self.matrix_a.swap(i, maxi);
63+
self.matrix_b.swap(i, maxi); // swap row i and maxi in matrix_a and matrix_b
64+
{
65+
let tmp = self.matrix_a[i][j];
66+
self.divide_row(i, tmp)?;
67+
}
68+
for u in i + 1..self.n {
69+
let v = self.mul_row(i, self.matrix_a[u][j])?; // v has n+1 elements
70+
for (k, item) in v.iter().enumerate().take(self.m) {
71+
self.matrix_a[u][k] = self.matrix_a[u][k].sub(*item)?; // A_{u}=A_{u}-A_{u}{j}*A_{i}
72+
}
73+
self.matrix_b[u] = self.matrix_b[u].sub(v[self.m])?;
74+
}
75+
}
76+
} // REF
77+
78+
for i in (0..self.n).rev() {
79+
let j = match self.get_pivot(i) {
80+
Some(s) => s,
81+
None => continue,
82+
};
83+
for u in (0..i).rev() {
84+
// j above i
85+
let v = self.mul_row(i, self.matrix_a[u][j])?; // v has n+1 elements
86+
for (k, item) in v.iter().enumerate().take(self.m) {
87+
self.matrix_a[u][k] = self.matrix_a[u][k].sub(*item)?; // A_{u}=A_{u}-A_{u}{j}*A_{i}
88+
}
89+
self.matrix_b[u] = self.matrix_b[u].sub(v[self.m])?;
90+
}
91+
} // RREF
92+
let mut ans: Vec<Frac> = vec![Frac::new(0, 1); self.m];
93+
let pivots = self.check()?;
94+
let mut free_variable = false;
95+
for i in (0..self.m).rev() {
96+
if pivots.col.contains(&i) {
97+
let mut sum = Frac::new(0, 1);
98+
for (k, item) in ans.iter().enumerate().take(self.m).skip(i + 1) {
99+
sum = sum.add(self.matrix_a[pivots.row[i]][k].mul(*item)?)?;
100+
}
101+
ans[i] = self.matrix_b[pivots.row[i]]
102+
.sub(sum)?
103+
.div(self.matrix_a[pivots.row[i]][i])?;
104+
} else {
105+
free_variable = true;
106+
ans[i] = Frac::new(1, 1); // set all free variables = 1/1.
107+
}
108+
}
109+
Ok(ResultHandler {
110+
warn_message: if free_variable {
111+
FreeVariablesDetected
112+
} else {
113+
NoWarn
114+
},
115+
result: ans,
116+
}) // x_{n} to x_{1}
117+
}
118+
119+
fn check(&self) -> Result<Pivots, ErrorCases> {
120+
let mut col: Vec<usize> = Vec::new();
121+
let mut row: Vec<usize> = Vec::new();
122+
for i in 0..self.n {
123+
if self.get_pivot(i).is_some() {
124+
col.push(self.get_pivot(i).unwrap());
125+
row.push(i);
126+
}
127+
if self.matrix_a[i] == vec![Frac::new(0, 1); self.n + 1]
128+
&& self.matrix_b[i] != Frac::new(0, 1)
129+
{
130+
return Err(Unsolvable);
131+
}
132+
}
133+
Ok(Pivots { col, row })
134+
}
135+
136+
fn get_pivot(&self, row: usize) -> Option<usize> {
137+
for column in 0..self.m {
138+
if self.matrix_a[row][column] != Frac::new(0, 1) {
139+
return Some(column);
140+
}
141+
}
142+
None
143+
}
144+
145+
fn get_leftmost_row(&self, row: usize) -> Option<usize> {
146+
let mut fake_zero = false;
147+
let mut leftmost = row;
148+
let mut min_left: usize = match self.get_pivot(row) {
149+
Some(s) => s,
150+
None => {
151+
fake_zero = true;
152+
0
153+
}
154+
};
155+
for i in row + 1..self.n {
156+
let current_pivot = match self.get_pivot(i) {
157+
Some(s) => s,
158+
None => continue,
159+
};
160+
if (current_pivot < min_left) | (fake_zero) {
161+
leftmost = i;
162+
min_left = current_pivot;
163+
fake_zero = false;
164+
}
165+
}
166+
Some(leftmost)
167+
}
168+
169+
fn mul_row(&self, row: usize, multiplicator: Frac) -> Result<Vec<Frac>, ErrorCases> {
170+
let mut v: Vec<Frac> = Vec::new();
171+
for column in 0..self.m {
172+
v.push(self.matrix_a[row][column].mul(multiplicator)?);
173+
}
174+
v.push(self.matrix_b[row].mul(multiplicator)?);
175+
Ok(v)
176+
}
177+
178+
fn divide_row(&mut self, row: usize, divisor: Frac) -> Result<bool, ErrorCases> {
179+
for column in 0..self.m {
180+
self.matrix_a[row][column] = self.matrix_a[row][column].div(divisor)?;
181+
}
182+
self.matrix_b[row] = self.matrix_b[row].div(divisor)?;
183+
Ok(true)
184+
}
185+
186+
fn get_max_abs_row(&self, row: usize, column: usize) -> Result<usize, ErrorCases> {
187+
let mut maxi = row;
188+
for k in row + 1..self.n {
189+
if self.matrix_a[k][column].abs()? > self.matrix_a[maxi][column].abs()? {
190+
maxi = k;
191+
}
192+
}
193+
Ok(maxi)
194+
}
195+
}

src/balancer_mod/guass_eliminate.rs

-111
This file was deleted.

0 commit comments

Comments
 (0)