Skip to content

Instantly share code, notes, and snippets.

@WoolDoughnut310
Created July 26, 2022 16:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WoolDoughnut310/8b5e017c15396a1169f14a0c872177c3 to your computer and use it in GitHub Desktop.
Save WoolDoughnut310/8b5e017c15396a1169f14a0c872177c3 to your computer and use it in GitHub Desktop.
const getElements = (compounds) => {
let elements = [];
for (let compound of compounds) {
for (let element of Object.keys(compound)) {
if (!elements.includes(element)) elements.push(element);
}
}
elements.sort();
return elements;
}
const constructElementMatrix = (elements, reactants, products) => {
let matrix = [];
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
for (let j = 0; j < reactants.length; j++) {
const reactant = reactants[j];
if (matrix[i] === undefined) matrix[i] = [];
matrix[i][j] = new Fraction(reactant[element] ?? 0);
}
for (let j = 0; j < products.length; j++) {
const product = products[j];
matrix[i][j + reactants.length] = new Fraction(
-(product[element] ?? 0)
);
}
}
return matrix;
}
const forwardElimination = (matrix) => {
// Number of rows
let n = matrix.length;
// Number of columns
let m = matrix[0].length;
for (let i = 0; i < n; i++) {
// Identifying maximum value and position for a pivot
let iMax = i;
let vMax = matrix[iMax][i];
for (let j = i + 1; j < n; j++) {
if (matrix[j][i].abs() > vMax) {
vMax = matrix[j][i];
iMax = j;
}
}
if (iMax !== i) {
// Swap the current row with the maximum value's row
for (let k = 0; k < m; k++) {
let temp = matrix[i][k];
matrix[i][k] = matrix[iMax][k];
matrix[iMax][k] = temp;
}
}
for (let j = i + 1; j < n; j++) {
const ratio = matrix[j][i].div(matrix[i][i]);
let empty = true;
for (let k = 0; k < m; k++) {
matrix[j][k] = matrix[j][k].sub(ratio.mul(matrix[i][k]));
if (!matrix[j][k].equals(0)) empty = false;
}
// Delete empty rows to avoid later zero division
if (empty) {
n--;
delete matrix[j];
}
}
}
return matrix;
}
const backSubstitution = (matrix) => {
let solution = new Array(n).fill(new Fraction(0));
// Applying back substitution
solution[n - 1] = matrix[n - 1][m - 1].div(matrix[n - 1][m - 2]);
for (let i = n - 2; i >= 0; i--) {
solution[i] = matrix[i][n];
for (let j = i + 1; j < m; j++) {
solution[i] = solution[i].sub(matrix[i][j].mul(solution[j]));
}
solution[i] = solution[i].div(matrix[i][i]);
}
solution.push(new Fraction(1));
for (let i = 0; i < solution.length; i++) {
solution[i] = solution[i].abs();
if (!solution[i].equals(parseFloat(solution[i].toString()) | 0)) {
let scale = solution[i].inverse().lcm(1);
for (let j = 0; j < solution.length; j++) {
solution[j] = solution[j].mul(scale).abs();
}
}
}
}
const balanceEquation = (
reactants,
products
) => {
let elements = getElements(reactants);
let matrix = constructElementMatrix(elements, reactants, products);
forwardElimination(matrix);
let solution = backSubstitution(matrix);
// Converting Fraction objects back to numbers
solution = solution.map(Number);
return [
solution.slice(0, reactants.length),
solution.slice(reactants.length),
];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment