Skip to content

Matrices and systems ​

Matrix holds fractions, PolyMatrix holds polynoms, and LinearSystem solves systems of linear equations.

js
import {Matrix, PolyMatrix, LinearSystem} from 'pimath'

Matrix ​

Build a matrix ​

js
new Matrix([[1, 2], [3, 4]]).display // ((1,2),(3,4))
new Matrix('((1,2),(3,4))').display // ((1,2),(3,4))
new Matrix(2, 3).display // ((0,0,0),(0,0,0))
new Matrix(2).display // ((0,0),(0,0))
Matrix.fromVectors(new Vector(1, 2), new Vector(3, 4)).display // ((1,3),(2,4))

Rows of different lengths throw a DimensionError. Each vector given to fromVectors is a column.

js
new Matrix([[1, 2], [3]]) // throws DimensionError

Indices are zero-based.

js
const M = new Matrix([[1, 2], [3, 4]])

M.dimension // { rows: 2, cols: 2 }
M.values[1][0].display // 3
M.rows.length // 2
M.cols[1].map(f => f.display) // [ '2', '4' ]
M.aij(0, 1).display // 2
M.aij(5, 5) // null
M.setValue(0, 0, 9).display // ((9,2),(3,4))

values, rows and cols give copies. setValue throws an IndexError outside of the matrix.

Operations ​

Operations modify the matrix and return it. A dimension mismatch throws a DimensionError.

js
new Matrix([[1, 2], [3, 4]]).add(new Matrix([[1, 1], [1, 1]])).display // ((2,3),(4,5))
new Matrix([[1, 2], [3, 4]]).subtract(new Matrix([[1, 1], [1, 1]])).display // ((0,1),(2,3))
new Matrix([[1, 2], [3, 4]]).multiply(2).display // ((2,4),(6,8))
new Matrix([[1, 2], [3, 4]]).multiply(new Matrix([[0, 1], [1, 0]])).display // ((2,1),(4,3))
new Matrix([[1, 2], [3, 4]]).pow(2).display // ((7,10),(15,22))
new Matrix([[1, 2], [3, 4]]).opposite().display // ((-1,-2),(-3,-4))
new Matrix([[1, 2], [3, 4]]).transpose().display // ((1,3),(2,4))
new Matrix([[1, 2], [3, 4]]).inverse().display // ((-2,1),(3/2,-1/2))

transpose, rowEchelonForm and reducedRowEchelonForm return a new matrix. inverse throws a MathError when the matrix is not invertible, so test it first.

js
new Matrix([[1, 2], [3, 4]]).canBeInverted() // true
new Matrix([[1, 2], [2, 4]]).canBeInverted() // false
new Matrix([[1, 2], [3, 4]]).canBeMultiplied(new Matrix(3, 1)) // false

Determinant, rank and reduction ​

js
const M = new Matrix([[1, 2], [3, 4]])

M.determinant().display // -2
M.cofactor(0, 0).display // 4
M.rank() // 2
M.isSquare() // true
new Matrix([[1, 2], [3, 4]]).reducedRowEchelonForm().display // ((1,0),(0,1))
new Matrix([[2, 4], [1, 3]]).rowEchelonForm().display // ((1,2),(0,1))

determinant throws a DimensionError for a matrix that is not square. cofactor(i, j) is the signed minor.

Display ​

js
const M = new Matrix([[1, 2], [3, 4]])

M.display // ((1,2),(3,4))
M.asBmatrix.display // [(1,2),(3,4)]
M.asVmatrix.display // |(1,2),(3,4)|

tex writes a pmatrix environment. The delimiter options asPmatrix (default), asBmatrix, asBraceMatrix, asVmatrix and asDoubleVmatrix are chainable and stay set.

js
M.tex
// \begin{pmatrix}
//     1 & 2\\
//     3 & 4\\
// \end{pmatrix}

withPartition(c) draws a vertical bar before column c, as in an augmented matrix. withDigits(n) shows decimals.

js
new Matrix([[1, 2, 3], [4, 5, 6]]).withPartition(2).display // ((1,2|3),(4,5|6))
new Matrix([[1, 2], [3, 4]]).multiply('1/3').withDigits(2).display // ((0.33,0.67),(1.00,1.33))

Compare and test ​

js
new Matrix([[1, 0], [0, 1]]).isOne() // true
new Matrix(2, 2).isZero() // true
new Matrix([[1, 2], [3, 4]]).isEqual(new Matrix([[1, 2], [3, 4]])) // true

Go through the entries ​

js
new Matrix([[1, 2], [3, 4]]).map(a => a.value) // [ [ 1, 2 ], [ 3, 4 ] ]
new Matrix([[1, 2], [3, 4]]).flat().map(a => a.display) // [ '1', '2', '3', '4' ]

forEach(callback) calls callback(entry, row, column) on the real entries, which can be modified.

PolyMatrix ​

A PolyMatrix is built like a Matrix and has the same methods, with polynomial entries.

js
const P = new PolyMatrix([['x', 1], [2, 'x+1']])

P.display // ((x,1),(2,x+1))
P.determinant().display // x^(2)+x-2
PolyMatrix.fromValues([[2, 1], [1, 2]]).characteristic_polynom('k').display // k^(2)-4k+3

characteristic_polynom(variable) is the polynom det(A - kI), where variable names the unknown (k by default). PolyMatrix.fromMatrix(M) converts a Matrix.

LinearSystem ​

A LinearSystem is built from equations written as strings, or from Equation objects.

js
const S = new LinearSystem('x+y=3', 'x-y=1')

S.display // {(x,+y,=,3),(x,-y,=,1):}
S.variables // [ 'x', 'y' ]
S.solve().map(s => s.display) // [ '2', '1' ]
S.isSolvable() // true

The solutions come in the order of variables. solve() uses Gauss-Jordan elimination.

  • A single solution gives one Solution per variable.
  • A system with no solution gives an empty array.
  • A system with infinitely many solutions gives one infinite Solution per variable.
js
new LinearSystem('x+y=3', 'x+y=5').solve().length // 0
new LinearSystem('x+y=3', '2x+2y=6').solve().map(s => s.value) // [ Infinity, Infinity ]
LinearSystem.solutionAsDisplay(new LinearSystem('x+y=3', 'x-y=1').solve()) // (2;1)

Build from numbers ​

js
new LinearSystem().fromComponents([[1, 1, 3], [1, -1, 1]], 'xy').display // {(x,+y,=,3),(x,-y,=,1):}

Each row holds the coefficients of the variables, then the constant of the right member. fromMatrix, fromVectors and fromEquations do the same from other inputs, and replace the equations of the system.

Work step by step ​

For a lesson on elimination, the system offers the elementary operations. They modify the system.

js
const S = new LinearSystem('x+y=3', 'x-y=1')

S.multiply(2, 0).display // {(2x,+2y,=,6),(x,-y,=,1):}
S.add(new Equation('x-y=1'), 0).display // {(3x,+y,=,7),(x,-y,=,1):}
S.subtract(new Equation('x-y=1'), 1).display // {(3x,+y,=,7),(,,=,0):}

mergeEquations({id, factor}, {id, factor}) returns the combination of two equations without changing the system, and solve_compute_factors(variable) suggests the factors that eliminate a variable. matrix gives the coefficients and the constants, and toAugmentedMatrix() the matrix [A|b].

js
const [A, b] = new LinearSystem('x+y=3', 'x-y=1').matrix

A.display // ((1,1),(1,-1))
b.display // ((3,1))

Members ​

Matrix ​

Constructors

  • new Matrix()
  • new Matrix(rows: number, cols?: number)
  • new Matrix(value: string)
  • new Matrix(values: InputAlgebra<Fraction>[][])

Static members

MemberDescription
fromString(value: string): MatrixBuild a matrix from its display string, such as "((1,2),(3,4))".
fromValues(values: InputAlgebra<Fraction>[][]): MatrixBuild a matrix from an array of rows. Throws: {DimensionError} if the rows do not all have the same length.
fromDimensions(rows: number, cols?: number): MatrixBuild a zero matrix. Without cols, the matrix is square.
fromVectors(...vectors: Vector[]): MatrixBuild a matrix whose columns are the given vectors. Throws: {DimensionError} if the vectors do not all have the same dimension.

Properties and getters

MemberDescription
tex: stringLaTeX output: a pmatrix environment by default, one row per line. With a partition (withPartition), an array with a vertical bar. An empty matrix gives an empty string.
display: stringText output such as ((1,2),(3,4)). The outer brackets follow the delimiter option, and a partition adds a |. This is the format read by parse.
asBmatrix: MatrixDelimiter option: square brackets. Chainable, persistent.
asBraceMatrix: MatrixDelimiter option: braces. Chainable, persistent.
cols: Fraction[][]The columns, as an array of arrays (copies of the values).
dimension: { rows: number; cols: number; }Number of rows and columns, as {rows, cols}.
asPmatrix: MatrixDelimiter option: round brackets (default). Chainable, persistent.
asVmatrix: MatrixDelimiter option: single vertical bars, as for a determinant. Chainable, persistent.
asDoubleVmatrix: MatrixDelimiter option: double vertical bars. Chainable, persistent.
rows: Fraction[][]The rows, as an array of arrays (copies of the values).
values: Fraction[][]The entries, as an array of rows (copies of the values).

Methods

MemberDescription
parse(value: string | Vector[] | InputAlgebra<Fraction>[][]): MatrixReplace the content with a display string ("((1,2),(3,4))"), an array of rows, or vectors (one per column). Throws: {DimensionError} if the rows (or the vectors) do not all have the same length.
copy(value: AbstractMatrix<Fraction>): MatrixCopy the values and the partition of another matrix into this one.
clone(): MatrixA full duplicate of the values and of the partition. The delimiter option (asBmatrix...) is not kept.
add(value: AbstractMatrix<Fraction>): MatrixAdd a matrix of the same dimensions, term by term. Throws: {DimensionError} if the dimensions differ.
aij(i: number, j: number): Fraction | nullReturns element at position (i, j), or null if the index is out of bounds.
canBeAdded(matrix: AbstractMatrix<Fraction>): booleanTrue when both matrices have the same dimensions.
canBeInverted(): booleanTrue when the matrix is square and its determinant is not zero.
canBeMultiplied(matrix: AbstractMatrix<Fraction>): booleanTrue when the number of columns of this matrix equals the number of rows of matrix.
cofactor(row: number, column: number): FractionThe cofactor of the entry at row, column: the determinant of the matrix without that row and column, times (-1)^(row+column).
determinant(): FractionDeterminant, by cofactor expansion along the first row. Throws: {DimensionError} if the matrix is not square.
flat(): Fraction[]All the values in a single array, row by row.
forEach(callback: (aij: Fraction, row: number, column: number) => void): voidCall callback(value, row, column) for each entry. The entries are the real objects: they can be modified.
inverse(): MatrixInverts this matrix in place. Throws: {MathError} if the matrix is not invertible (singular or non-square)
isEqual(value: AbstractMatrix<Fraction>): booleanTrue when both matrices have the same dimensions and equal entries.
isOne(): booleanTrue for an identity matrix.
isSquare(): booleanTrue when there are as many rows as columns.
isZero(): booleanTrue when every entry is zero.
isConsistent(): booleanReturns true if the augmented matrix [A|b] has a consistent system of equations. A row [0…0 | c≠0] after row reduction signals inconsistency. Always returns true when no partition has been set.
map<U>(callback: (aij: Fraction, row: number, column: number) => U): U[][]Build an array of rows from callback(value, row, column).
multiply(value: InputValue<Fraction> | AbstractMatrix<Fraction>): MatrixMultiply by a scalar (every entry), or by a matrix (this × value, which replaces the content). Throws: {DimensionError} if the dimensions are incompatible for a matrix product.
one(): MatrixSet the diagonal to one and every other entry to zero.
opposite(): MatrixChange the sign of every entry.
pow(value: number): MatrixRaise to a non-negative integer power. The power 0 gives the identity. Throws: {InvalidArgumentError} if value is negative or not an integer.; {DimensionError} if the matrix is not square and the power is 2 or more.
rank(): numberReturns the rank of this matrix — the number of non-zero rows after reduction to row echelon form.
reduce(): MatrixReduce every entry.
reducedRowEchelonForm(): MatrixReturns a new matrix in reduced row echelon form (Gauss-Jordan). Each pivot column has exactly one non-zero entry (value 1). Does not modify the receiver.
rowEchelonForm(): MatrixReturns a new matrix in row echelon form (forward Gauss elimination). The matrix is upper-triangular with each pivot normalised to 1. Does not modify the receiver.
setValue(row: number, column: number, value: InputValue<Fraction>): MatrixReplace the entry at row, column. Throws: {IndexError} if the position is outside of the matrix.
subtract(value: AbstractMatrix<Fraction>): MatrixSubtract a matrix of the same dimensions, term by term. Throws: {DimensionError} if the dimensions differ.
withDigits(digits: number | null): MatrixShow every numeric value as a decimal with digits digits after the point (exact values included: 3/2 becomes 1.50 with 2 digits).
transpose(): MatrixReturns a new matrix that is the transpose of this one. Does not modify the receiver.
withPartition(col: number): MatrixSets the column index that separates the coefficient columns from the augmented column(s) in display and tex output. A | separator is inserted before column col. The partition persists until overwritten. Throws: {IndexError} if col is not strictly between 0 and the column count
zero(): MatrixSet every entry to zero.

PolyMatrix ​

Constructors

  • new PolyMatrix()
  • new PolyMatrix(rows: number, cols?: number)
  • new PolyMatrix(value: string)
  • new PolyMatrix(values: InputAlgebra<Polynom>[][])

Static members

MemberDescription
fromString(value: string): PolyMatrixBuild a matrix from its display string, such as "((x,1),(2,x+1))".
fromValues(values: InputAlgebra<Polynom>[][]): PolyMatrixBuild a matrix from an array of rows. Throws: {DimensionError} if the rows do not all have the same length.
fromDimensions(rows: number, cols?: number): PolyMatrixBuild a zero matrix. Without cols, the matrix is square.
fromVectors(...vectors: Vector[]): PolyMatrixBuild a matrix whose columns are the given vectors. Throws: {DimensionError} if the vectors do not all have the same dimension.
fromMatrix(m: Matrix): PolyMatrixCreates a PolyMatrix from a Matrix by converting each Fraction entry to a constant Polynom.

Properties and getters

MemberDescription
tex: stringLaTeX output: a pmatrix environment by default, one row per line. With a partition (withPartition), an array with a vertical bar. An empty matrix gives an empty string.
display: stringText output such as ((1,2),(3,4)). The outer brackets follow the delimiter option, and a partition adds a |. This is the format read by parse.
asBmatrix: PolyMatrixDelimiter option: square brackets. Chainable, persistent.
asBraceMatrix: PolyMatrixDelimiter option: braces. Chainable, persistent.
cols: Polynom[][]The columns, as an array of arrays (copies of the values).
dimension: { rows: number; cols: number; }Number of rows and columns, as {rows, cols}.
asPmatrix: PolyMatrixDelimiter option: round brackets (default). Chainable, persistent.
asVmatrix: PolyMatrixDelimiter option: single vertical bars, as for a determinant. Chainable, persistent.
asDoubleVmatrix: PolyMatrixDelimiter option: double vertical bars. Chainable, persistent.
rows: Polynom[][]The rows, as an array of arrays (copies of the values).
values: Polynom[][]The entries, as an array of rows (copies of the values).

Methods

MemberDescription
characteristic_polynom(variable?: string): PolynomComputes the characteristic polynomial det(A − λI) of this matrix. Throws: {DimensionError} if the matrix is not square
parse(value: string | Vector[] | InputAlgebra<Polynom>[][]): PolyMatrixReplace the content with a display string ("((1,2),(3,4))"), an array of rows, or vectors (one per column). Throws: {DimensionError} if the rows (or the vectors) do not all have the same length.
copy(value: AbstractMatrix<Polynom>): PolyMatrixCopy the values and the partition of another matrix into this one.
clone(): PolyMatrixA full duplicate of the values and of the partition. The delimiter option (asBmatrix...) is not kept.
add(value: AbstractMatrix<Polynom>): PolyMatrixAdd a matrix of the same dimensions, term by term. Throws: {DimensionError} if the dimensions differ.
aij(i: number, j: number): Polynom | nullReturns element at position (i, j), or null if the index is out of bounds.
canBeAdded(matrix: AbstractMatrix<Polynom>): booleanTrue when both matrices have the same dimensions.
canBeInverted(): booleanTrue when the matrix is square and its determinant is not zero.
canBeMultiplied(matrix: AbstractMatrix<Polynom>): booleanTrue when the number of columns of this matrix equals the number of rows of matrix.
cofactor(row: number, column: number): PolynomThe cofactor of the entry at row, column: the determinant of the matrix without that row and column, times (-1)^(row+column).
determinant(): PolynomDeterminant, by cofactor expansion along the first row. Throws: {DimensionError} if the matrix is not square.
flat(): Polynom[]All the values in a single array, row by row.
forEach(callback: (aij: Polynom, row: number, column: number) => void): voidCall callback(value, row, column) for each entry. The entries are the real objects: they can be modified.
inverse(): PolyMatrixInverts this matrix in place. Throws: {MathError} if the matrix is not invertible (singular or non-square)
isEqual(value: AbstractMatrix<Polynom>): booleanTrue when both matrices have the same dimensions and equal entries.
isOne(): booleanTrue for an identity matrix.
isSquare(): booleanTrue when there are as many rows as columns.
isZero(): booleanTrue when every entry is zero.
isConsistent(): booleanReturns true if the augmented matrix [A|b] has a consistent system of equations. A row [0…0 | c≠0] after row reduction signals inconsistency. Always returns true when no partition has been set.
map<U>(callback: (aij: Polynom, row: number, column: number) => U): U[][]Build an array of rows from callback(value, row, column).
multiply(value: InputValue<Polynom> | AbstractMatrix<Polynom>): PolyMatrixMultiply by a scalar (every entry), or by a matrix (this × value, which replaces the content). Throws: {DimensionError} if the dimensions are incompatible for a matrix product.
one(): PolyMatrixSet the diagonal to one and every other entry to zero.
opposite(): PolyMatrixChange the sign of every entry.
pow(value: number): PolyMatrixRaise to a non-negative integer power. The power 0 gives the identity. Throws: {InvalidArgumentError} if value is negative or not an integer.; {DimensionError} if the matrix is not square and the power is 2 or more.
rank(): numberReturns the rank of this matrix — the number of non-zero rows after reduction to row echelon form.
reduce(): PolyMatrixReduce every entry.
reducedRowEchelonForm(): PolyMatrixReturns a new matrix in reduced row echelon form (Gauss-Jordan). Each pivot column has exactly one non-zero entry (value 1). Does not modify the receiver.
rowEchelonForm(): PolyMatrixReturns a new matrix in row echelon form (forward Gauss elimination). The matrix is upper-triangular with each pivot normalised to 1. Does not modify the receiver.
setValue(row: number, column: number, value: InputValue<Polynom>): PolyMatrixReplace the entry at row, column. Throws: {IndexError} if the position is outside of the matrix.
subtract(value: AbstractMatrix<Polynom>): PolyMatrixSubtract a matrix of the same dimensions, term by term. Throws: {DimensionError} if the dimensions differ.
withDigits(digits: number | null): PolyMatrixShow every numeric value as a decimal with digits digits after the point (exact values included: 3/2 becomes 1.50 with 2 digits).
transpose(): PolyMatrixReturns a new matrix that is the transpose of this one. Does not modify the receiver.
withPartition(col: number): PolyMatrixSets the column index that separates the coefficient columns from the augmented column(s) in display and tex output. A | separator is inserted before column col. The partition persists until overwritten. Throws: {IndexError} if col is not strictly between 0 and the column count
zero(): PolyMatrixSet every entry to zero.

LinearSystem ​

Constructors

  • new LinearSystem(...values: (string \| Equation)[])

Static members

MemberDescription
solutionAsDisplay(value: Solution[]): stringText form of a solution of a system: (2;1).
solutionAsTex(value: Solution[]): stringLaTeX form of a solution of a system: \left( 2 ; 1 \right).

Properties and getters

MemberDescription
tex: stringLaTeX rendering of the current state (terminal output, not chainable).
display: stringASCIIMath rendering of the current state (terminal output, not chainable).
equations: Equation[]The equations, as copies. Setting the property replaces them and updates the variables.
matrix: [Matrix, Vector]The system as [A, b]: the matrix of the coefficients and the vector of the constants.
variables: string[]The variables of the system, sorted. Setting the property accepts a string of letters or an array.

Methods

MemberDescription
parse(...inputs: (string | Equation)[]): LinearSystemReplace the equations with strings or equations. Throws: {ParseError} if a string has no equation sign.
fromEquations(...equations: Equation[]): LinearSystemReplace the equations. The variables are those found in them, in alphabetical order.
fromComponents(matrix: InputValue<Fraction>[][], variables?: string): LinearSystemReplace the equations from rows of numbers: the coefficients of the variables, then the constant of the right member. [[1, 1, 3], [1, -1, 1]] is x+y=3 and x-y=1. Throws: {DimensionError} if there is no row, or the rows have different lengths.
fromMatrix(value: Matrix, variables?: string): LinearSystemReplace the equations from a matrix, read as in fromComponents.
fromVectors(...vectors: Vector[]): LinearSystemReplace the equations from vectors: each vector is a column, the last one holds the constants.
copy(): LinearSystemCopy the mathematical state of another instance into this (display state is NOT transferred — the receiver keeps its own formatting). Entry point used when constructing/parsing from a same-type input. Distinct from clone. Classes without a real implementation throw NotImplementedError.
clone(): LinearSystemFull duplicate of this instance, including display state (selected form and options set via as*** / with***). Distinct from copy.
withDigits(digits: number | null): LinearSystemShow every numeric value as a decimal with digits digits after the point (exact values included: 3/2 becomes 1.50 with 2 digits).
add(value: InputValue<LinearSystem | Equation | Polynom>, index?: number): LinearSystemAdd a system to this one, equation by equation. With an equation, a polynom or a number, add it to the equation at position index. Throws: {DimensionError} if the systems do not have the same number of equations.; {IndexError} if index is missing or out of range.
buildTex(equations: Equation[], operators?: (string[])[]): stringBuilds the LaTeX \left\{...\right. representation from an explicit equation list. Called by tex with the reordered clone. Pass equations directly when generating a step-by-step derivation on a non-standard equation list.
degree(variable?: string): FractionHighest degree of the equations.
evaluate(): number | FractionNot implemented. Throws: {NotImplementedError} always.
hasVariable(variable: string): booleanTrue when the variable appears in the system.
isEqual(value: LinearSystem): booleanTrue when both systems have the same equations, in the same order.
isSolvable(): booleanTrue when the system has exactly one solution: it is consistent and its rank equals the number of variables.
toAugmentedMatrix(): MatrixBuilds the augmented matrix [A|b] for this system and marks the partition at the variable count, enabling isConsistent() and reducedRowEchelonForm() to interpret the coefficient vs. constant parts.
mergeEquations(equation1: { id: number; factor: InputValue<Fraction>; }, equation2: { id: number; factor: number; }): EquationA new equation: the first equation times its factor, plus the second equation times its factor. The system is not modified.
multiply(value: InputValue<Fraction> | InputValue<Fraction>[], index?: number): LinearSystemMultiply the equation at position index by a number, or every equation by the matching number of an array. Throws: {DimensionError} if the array does not have one value per equation.; {IndexError} if a single value is given without a valid index.
reduce(): LinearSystemReduce every equation.
reorder(): LinearSystemPut the variables on the left and the constant on the right in every equation.
solve(): Solution[]Solves the system by Gauss-Jordan elimination on the augmented matrix. - Unique solution: one Solution per variable, in variables order. - No solution: returns []. - Infinite solutions: one Solution per variable with .value === Infinity.
solve_compute_factors(variable: string): [{ id: number; factor: number; }, { id: number; factor: number; }][]For each pair of equations (i, j), computes LCM-based multipliers that eliminate variable by linear combination. The factors satisfy f_i·coeff_i + f_j·coeff_j = 0. Pairs are sorted by |f_i| + |f_j| (smallest multipliers first). Requires that all variable terms are on the left side of each equation.
subtract(value: InputValue<LinearSystem | Equation | Polynom>, index?: number): LinearSystemSubtract a system from this one, equation by equation. With an equation, a polynom or a number, subtract it from the equation at position index. Throws: {DimensionError} if the systems do not have the same number of equations.; {IndexError} if index is missing or out of range.

Released under the MIT License.