UNPKG

gaussian-elimination-co

Version:

A library implementing Gauissian Elmination in typescript

189 lines 5.08 kB
"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