gaussian-elimination-co
Version:
A library implementing Gauissian Elmination in typescript
189 lines • 5.08 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RowSide = exports.Row = exports.Tableau = void 0;
/**
* Returns a new array containing the indices where the predicate is true.
*
* @param array The target array
* @param predicate The filter function
*/
function findAllIndices(array, predicate) {
return array.map((value, index) => predicate(value, index, array) ? index : undefined)
.filter(((value) => value !== undefined));
}
// Credit: https://stackoverflow.com/a/37580979
function* permute(permutation) {
yield permutation.slice();
const length = permutation.length;
let c = new Array(length).fill(0);
let i = 1;
while (i < length) {
if (c[i] < i) {
let k = i % 2 && c[i];
let p = permutation[i];
permutation[i] = permutation[k];
permutation[k] = p;
++c[i];
i = 1;
yield permutation.slice();
}
else {
c[i] = 0;
++i;
}
}
}
class Tableau {
rows;
constructor(rows) {
this.rows = rows;
if (this.height <= 1) {
throw "Invalid row count";
}
if (this.lhsWidth !== this.height) {
throw "Row LHS width must equal amount of rows to make a square matrix";
}
this.orderRows();
}
/**
* Constructs a tableau from nested arrays
*
* @param input
*/
static from(input) {
return new Tableau(input.map(([lhs, rhs]) => new Row(new RowSide(lhs), new RowSide(rhs))));
}
/**
* Solves the set of equations
*/
solve() {
this.gauss();
this.checkValidity();
this.jordan();
return this.getLHS();
}
/**
* Gets the left-hand side of the tableau
*/
getLHS() {
return this.rows.map((row) => row.rhs.values);
}
/**
* Gets the first elements of the left-hand side of the tableau.
*/
getLHSFirsts() {
return this.rows.map((row) => row.rhs.values[0]);
}
/**
* Prints out the Tableau
*/
inspect() {
console.log(this.rows.map((row) => [row.lhs.values, row.rhs.values]));
}
gauss() {
for (let i = 0; i < this.height; ++i) {
this.rows[i].divideBy(this.lhsGet(i, i));
for (let j = this.height - 1; j > i; --j) {
this.rows[j].subtractMultiple(this.rows[i], this.lhsGet(j, i));
if (this.lhsGet(j, j) === 0) {
this.orderRows();
}
}
}
}
checkValidity() {
for (let i = 0; i < this.height; ++i) {
if (this.lhsGet(i, i) === 0) {
throw "LHS is singular and unsolvable";
}
}
}
jordan() {
for (let i = this.height - 1; i >= 0; --i) {
for (let j = 0; j < i; ++j) {
this.rows[j].subtractMultiple(this.rows[i], this.lhsGet(j, i));
}
}
}
lhsGet(x, y) {
return this.rows[x].lhs.values[y];
}
lhsSet(x, y, value) {
this.rows[x].lhs.values[y] = value;
}
/**
* The LHS matrix needs to have the y=-x entries be non-zero
* @private
*/
orderRows() {
for (let permutation of permute(this.rows)) {
let validPermutation = true;
for (let i = 0; i < this.height; ++i) {
if (!permutation[i].validIndices.includes(i)) {
validPermutation = false;
}
}
if (validPermutation) {
this.rows = permutation;
return;
}
}
throw "Unable to order LHS to solve system";
}
get lhsWidth() {
return this.rows[0].lhsWidth;
}
get rhsWidth() {
return this.rows[0].rhsWidth;
}
get height() {
return this.rows.length;
}
}
exports.Tableau = Tableau;
/**
* Is used to build the rows of a Tableau
*/
class Row {
lhs;
rhs;
constructor(lhs, rhs) {
this.lhs = lhs;
this.rhs = rhs;
}
subtractMultiple(row, multiple) {
this.lhs.subtractMultiple(row.lhs, multiple);
this.rhs.subtractMultiple(row.rhs, multiple);
}
divideBy(multiple) {
this.lhs.divideBy(multiple);
this.rhs.divideBy(multiple);
}
get lhsWidth() {
return this.lhs.values.length;
}
get rhsWidth() {
return this.rhs.values.length;
}
get validIndices() {
return findAllIndices(this.lhs.values, (value) => value !== 0);
}
}
exports.Row = Row;
/**
* Is used to build a Row
*/
class RowSide {
values;
constructor(values) {
this.values = values;
}
subtractMultiple(rhs, multiple) {
this.values = this.values.map((value, index) => value - rhs.values[index] * multiple);
}
divideBy(multiple) {
this.values = this.values.map((value) => value / multiple);
}
}
exports.RowSide = RowSide;
//# sourceMappingURL=main.js.map