@kkitahara/linear-algebra
v2.1.3
Published
ECMAScript modules for exactly manipulating vectors and matrices of which elements are real or complex numbers of the form (p / q)sqrt(b).
Downloads
5
Maintainers
Readme
LinearAlgebra
ECMAScript modules for exactly manipulating vectors and matrices of which elements are real or complex numbers of the form (p / q)sqrt(b), where p is an integer, q is a positive (non-zero) integer, and b is a positive, square-free integer.
Installation
npm install @kkitahara/linear-algebra @kkitahara/complex-algebra @kkitahara/real-algebra
Examples
Complex linear algebra
import { ExactRealAlgebra as RealAlgebra } from '@kkitahara/real-algebra'
import { ComplexAlgebra } from '@kkitahara/complex-algebra'
import { LinearAlgebra } from '@kkitahara/linear-algebra'
let r = new RealAlgebra()
let c = new ComplexAlgebra(r)
let l = new LinearAlgebra(c)
let m1, m2, m3
Generate a new matrix (since v2.0.0)
m1 = l.$(1, 0, 0, 1)
m1.toString() // '(1, 0, 0, 1)'
m1 = l.$(r.$(1, 2, 5), c.$(0, 1), c.$(0, -1), 1)
m1.toString() // '((1 / 2)sqrt(5), i(1), i(-1), 1)'
// Some Array methods can be used
m1 = l.$(r.$(1, 2, 5), c.$(0, 1), c.$(0, -1), 1)
m1.push(c.$(3))
m1.toString() // '((1 / 2)sqrt(5), i(1), i(-1), 1, 3)'
Set and get the dimension
m1 = l.$(1, 0, 0, 1)
// 2 x 2 matix
m1.setDim(2, 2)
// number of rows
m1.getDim()[0] // 2
// number of columns
m1.getDim()[1] // 2
// elements are stored in row-major order
m1.toString() // '(1, 0,\n 0, 1)'
// 1 x 4 matix
m1.setDim(1, 4)
m1.getDim()[0] // 1
m1.getDim()[1] // 4
m1.toString() // '(1, 0, 0, 1)'
// 4 x 1 matix
m1.setDim(4, 1)
m1.getDim()[0] // 4
m1.getDim()[1] // 1
m1.toString() // '(1,\n 0,\n 0,\n 1)'
// 3 x 1 matix (inconsistent dimension)
m1.setDim(3, 1)
// throws an Error when getDim is called
m1.getDim() // Error
// 2 x 0 (0 means auto)
m1.setDim(2, 0)
m1.getDim()[0] // 2
m1.getDim()[1] // 2
// 0 x 1 (0 means auto)
m1.setDim(0, 1)
m1.getDim()[0] // 4
m1.getDim()[1] // 1
// 0 x 0 (this is an adaptive matrix, since v2.0.0)
m1.setDim(0, 0)
m1.isAdaptive() // true
m1.getDim() // Error
// matrices are adaptive by default
m1 = l.$(1, 0, 0, 1)
m1.isAdaptive() // true
:warning: matrix elements are stored in row-major order.
Copy (generate a new object)
m1 = l.$(1, 0, 0, 1).setDim(2, 2)
m2 = l.copy(m1)
m2.toString() // '(1, 0,\n 0, 1)'
m2.getDim()[0] // 2
m2.getDim()[1] // 2
Equality
m1 = l.$(1, 0, 0, 1).setDim(2, 2)
m2 = l.$(1, 0, 0, 1).setDim(2, 2)
m3 = l.$(1, 0, 0, -1).setDim(2, 2)
l.eq(m1, m2) // true
l.eq(m1, m3) // false
// matrices of different dimension are considered to be not equal
m1 = l.$(1, 0, 0, 1).setDim(2, 2)
m2 = l.$(1, 0, 0, 1).setDim(1, 4)
l.eq(m1, m2) // false
// here, `m1` is adaptive
m1 = l.$(1, 0, 0, 1)
m2 = l.$(1, 0, 0, 1).setDim(1, 4)
m3 = l.$(1, 0, 0, 1).setDim(4, 1)
l.eq(m1, m2) // true
l.eq(m1, m3) // true
l.eq(m2, m3) // false
Inequality
m1 = l.$(1, 0, 0, 1).setDim(2, 2)
m2 = l.$(1, 0, 0, 1).setDim(2, 2)
m3 = l.$(1, 0, 0, -1).setDim(2, 2)
l.ne(m1, m2) // false
l.ne(m1, m3) // true
// matrices of different dimension are considered to be not equal
m1 = l.$(1, 0, 0, 1).setDim(2, 2)
m2 = l.$(1, 0, 0, 1).setDim(1, 4)
l.ne(m1, m2) // true
// here, `m1` is adaptive
m1 = l.$(1, 0, 0, 1)
m2 = l.$(1, 0, 0, 1).setDim(1, 4)
m3 = l.$(1, 0, 0, 1).setDim(4, 1)
l.ne(m1, m2) // false
l.ne(m1, m3) // false
l.ne(m2, m3) // true
isZero
m1 = l.$(1, 0, 0, 1).setDim(2, 2)
m2 = l.$(0, 0, 0, 0).setDim(2, 2)
l.isZero(m1) // false
l.isZero(m2) // true
isInteger (since v1.1.0)
m1 = l.$(1, r.$(4, 2), -3, 4).setDim(2, 2)
m2 = l.$(1, r.$(1, 2), -3, 4).setDim(2, 2)
l.isInteger(m1) // true
l.isInteger(m2) // false
Element-wise addition
m1 = l.$(1, 2, 3, 4)
m2 = l.$(1, 3, 1, 3)
// new object is generated
m3 = l.add(m1, m2)
m3.toString() // '(2, 5, 4, 7)'
In-place element-wise addition
m1 = l.$(1, 2, 3, 4)
m2 = l.$(1, 3, 1, 3)
// new object is not generated
m1 = l.iadd(m1, m2)
m1.toString() // '(2, 5, 4, 7)'
Element-wise subtraction
m1 = l.$(1, 2, 3, 4)
m2 = l.$(1, 3, 1, 3)
// new object is generated
m3 = l.sub(m1, m2)
m3.toString() // '(0, -1, 2, 1)'
In-place element-wise subtraction
m1 = l.$(1, 2, 3, 4)
m2 = l.$(1, 3, 1, 3)
// new object is not generated
m1 = l.isub(m1, m2)
m1.toString() // '(0, -1, 2, 1)'
Element-wise multiplication
m1 = l.$(1, 2, 3, 4)
m2 = l.$(1, 3, 1, 3)
// new object is generated
m3 = l.mul(m1, m2)
m3.toString() // '(1, 6, 3, 12)'
In-place element-wise multiplication
m1 = l.$(1, 2, 3, 4)
m2 = l.$(1, 3, 1, 3)
// new object is not generated
m1 = l.imul(m1, m2)
m1.toString() // '(1, 6, 3, 12)'
Element-wise division
m1 = l.$(1, 2, 3, 4)
m2 = l.$(1, 3, 1, 3)
// new object is generated
m3 = l.div(m1, m2)
m3.toString() // '(1, 2 / 3, 3, 4 / 3)'
In-place element-wise division
m1 = l.$(1, 2, 3, 4)
m2 = l.$(1, 3, 1, 3)
// new object is not generated
m1 = l.idiv(m1, m2)
m1.toString() // '(1, 2 / 3, 3, 4 / 3)'
Scalar multiplication
m1 = l.$(1, 2, 3, 4)
// new object is generated
m2 = l.smul(m1, r.$(1, 2))
m2.toString() // '(1 / 2, 1, 3 / 2, 2)'
In-place scalar multiplication
m1 = l.$(1, 2, 3, 4)
// new object is not generated
m1 = l.ismul(m1, r.$(1, 2))
m1.toString() // '(1 / 2, 1, 3 / 2, 2)'
Scalar multiplication by -1
m1 = l.$(1, 2, 3, 4)
// new object is generated
m2 = l.neg(m1)
m2.toString() // '(-1, -2, -3, -4)'
In-place scalar multiplication by -1
m1 = l.$(1, 2, 3, 4)
// new object is not generated
m1 = l.ineg(m1)
m1.toString() // '(-1, -2, -3, -4)'
Scalar division (since v2.0.0)
m1 = l.$(1, 2, 3, 4)
// new object is generated
m2 = l.sdiv(m1, 2)
m2.toString() // '(1 / 2, 1, 3 / 2, 2)'
In-place scalar division (since v2.0.0)
m1 = l.$(1, 2, 3, 4)
// new object is not generated
m1 = l.isdiv(m1, 2)
m1.toString() // '(1 / 2, 1, 3 / 2, 2)'
Complex conjugate
m1 = l.$(1, c.$(0, 2), 3, c.$(0, 4))
// new object is generated
m2 = l.cjg(m1)
m2.toString() // '(1, i(-2), 3, i(-4))'
In-place evaluation of the complex conjugate
m1 = l.$(1, c.$(0, 2), 3, c.$(0, 4))
// new object is not generated
m1 = l.icjg(m1)
m1.toString() // '(1, i(-2), 3, i(-4))'
Transpose
m1 = l.$(1, 2, 3, 4).setDim(2, 2)
// new object is generated
m2 = l.transpose(m1)
m2.toString() // '(1, 3,\n 2, 4)'
In-place evaluation of the transpose
m1 = l.$(1, 2, 3, 4).setDim(2, 2)
// new object is not generated
m1 = l.itranspose(m1)
m1.toString() // '(1, 3,\n 2, 4)'
Conjugate transpose (Hermitian transpose)
m1 = l.$(1, c.$(0, 2), 3, c.$(0, 4)).setDim(2, 2)
// new object is generated
m2 = l.cjgTranspose(m1)
m2.toString() // '(1, 3,\n i(-2), i(-4))'
In-place evaluation of the conjugate transpose
m1 = l.$(1, c.$(0, 2), 3, c.$(0, 4)).setDim(2, 2)
// new object is not generated
m1 = l.icjgTranspose(m1)
m1.toString() // '(1, 3,\n i(-2), i(-4))'
Dot product
m1 = l.$(1, c.$(0, 2))
m2 = l.$(c.$(0, 3), 2)
l.dot(m1, m2).toString() // 'i(-1)'
Square of the absolute value (Frobenius norm)
m1 = l.$(1, c.$(0, 2))
let a = l.abs2(m1)
a.toString() // '5'
// return value is not a complex number (but a real number)
a.re // undefined
a.im // undefined
Matrix multiplication
m1 = l.$(1, 2, 3, 4).setDim(2, 2)
m2 = l.$(1, 3, 1, 3).setDim(2, 2)
m3 = l.mmul(m1, m2)
m3.toString() // '(3, 9,\n 7, 21)'
LU-factorisation
m1 = l.$(1, 2, 3, 4).setDim(2, 2)
// new object is generated
m2 = l.lup(m1)
In-place LU-factorisation
m1 = l.$(1, 2, 3, 4).setDim(2, 2)
// new object is not generated
m1 = l.ilup(m1)
Solving a linear equation
m1 = l.$(1, 2, 3, 4).setDim(2, 2)
m2 = l.$(1, 2, 3, 4).setDim(2, 2)
// m1 m3 = m2, new object is generated
m3 = l.solve(l.lup(m1), m2)
m3.toString() // '(1, 0,\n 0, 1)'
// m3 m1 = m2, new object is generated
m3 = l.solve(m2, l.lup(m1))
m3.toString() // '(1, 0,\n 0, 1)'
Solving a linear equation in-place
m1 = l.$(1, 2, 3, 4).setDim(2, 2)
m2 = l.$(1, 2, 3, 4).setDim(2, 2)
// m1 m3 = m2, new object is not generated
m2 = l.isolve(l.lup(m1), m2)
m2.toString() // '(1, 0,\n 0, 1)'
m2 = l.$(1, 2, 3, 4).setDim(2, 2)
// m3 m1 = m2, new object is not generated
m2 = l.isolve(m2, l.lup(m1))
m2.toString() // '(1, 0,\n 0, 1)'
Determinant
m1 = l.$(1, 2, 3, 4).setDim(2, 2)
m2 = l.lup(m1)
// det method supports only LU-factorised matrices
let det = l.det(m2)
det.toString() // '-2'
JSON (stringify and parse)
m1 = l.$(1, r.$(2, 3, 5), 3, c.$(0, r.$(4, 5, 3))).setDim(2, 2)
let str = JSON.stringify(m1)
m2 = JSON.parse(str, l.reviver)
l.eq(m1, m2) // true
Real linear algebra
If complex numbers are not necessary, you can use RealAlgebra instead of ComplexAlgebra.
import { ExactRealAlgebra as RealAlgebra } from '@kkitahara/real-algebra'
import { LinearAlgebra } from '@kkitahara/linear-algebra'
let r = new RealAlgebra()
let l = new LinearAlgebra(r)
Numerical real/complex linear algebra
You can work with built-in numbers if you use
import { RealAlgebra } from '@kkitahara/real-algebra'
instead of ExactRealAlgebra. See the documents of @kkitahara/real-algebra for more details.
ESDoc documents
For more examples, see ESDoc documents:
cd node_modules/@kkitahara/linear-algebra
npm install --only=dev
npm run doc
and open doc/index.html
in your browser.
LICENSE
© 2019 Koichi Kitahara
Apache 2.0