Skip to main content

Linear Algebra

Matrix multiplication​

Use Matft.matmul or the operator *&.

If the dimension of the input is 3 or more, it is treated as a stack of matrices residing in the last two indexes and broadcast accordingly (see numpy.matmul).

let a = Matft.arange(start: 1, to: 5, by: 1, shape: [2,2])
let b = Matft.arange(start: 5, to: 9, by: 1, shape: [2,2])
print(Matft.matmul(a, b))
print(a*&b)
/*
mfarray =
[[ 19, 22],
[ 43, 50]], type=Int, shape=[2, 2]
mfarray =
[[ 19, 22],
[ 43, 50]], type=Int, shape=[2, 2]
*/

Simultaneous equations​

Solve them by Matft.linalg.solve. The result's mftype is converted to Float or Double.

let coef = MfArray([[3,2],[1,2]])
let b = MfArray([7,1])
let ans = try! Matft.linalg.solve(coef, b: b)
print(ans)
/*
mfarray =
[ 3.0, -1.0000002], type=Float, shape=[2]
*/

The shape of the result is aligned to b's one; b of shape [2, 1] returns the result of shape [2, 1].

Inverse​

let a = MfArray([[1,3,2],[-1,0,1],[2,3,0]])
let ainv = try! Matft.linalg.inv(a)
print(ainv)
print(a*&ainv)
/*
mfarray =
[[ 1.0, -2.0, -1.0],
[ -0.6666666, 1.3333334, 1.0],
[ 1.0, -1.0, -1.0]], type=Float, shape=[3, 3]
mfarray =
[[ 1.0000001, 0.0, 0.0],
[ 0.0, 1.0, 0.0],
[ 1.1920929e-07, 1.1920929e-07, 1.0]], type=Float, shape=[3, 3]
*/

If the inverse matrix does not exist, MfError.LinAlgError.factorizationError or MfError.LinAlgError.singularMatrix is thrown.

Eigenvalues and eigenvectors​

Matft.linalg.eigen returns the tuple (valRe, valIm, lvecRe, lvecIm, rvecRe, rvecIm), where val is the eigenvalues, lvec is the left eigenvectors, rvec is the right eigenvectors, and Re / Im are the real / imaginary parts.

let a = MfArray([[1, -1], [1, 1]])
let ret = try! Matft.linalg.eigen(a)

print(ret.valRe)
print(ret.valIm)
print(ret.lvecRe)
print(ret.lvecIm)
print(ret.rvecRe)
print(ret.rvecIm)
/*
mfarray =
[ 1.0, 1.0], type=Float, shape=[2]
mfarray =
[ 1.0, -1.0], type=Float, shape=[2]
mfarray =
[[ -0.70710677, -0.70710677],
[ 0.0, 0.0]], type=Float, shape=[2, 2]
mfarray =
[[ 0.0, -0.0],
[ 0.70710677, -0.70710677]], type=Float, shape=[2, 2]
mfarray =
[[ 0.70710677, 0.70710677],
[ 0.0, 0.0]], type=Float, shape=[2, 2]
mfarray =
[[ 0.0, -0.0],
[ -0.70710677, 0.70710677]], type=Float, shape=[2, 2]
*/

Singular value decomposition​

Matft.linalg.svd returns the tuple (v, s, rt) (see numpy.linalg.svd).

let a = MfArray([[1, 2],
[3, 4]])
let ret = try! Matft.linalg.svd(a)

print(ret.v)
print(ret.s)
print(ret.rt)
print((ret.v *& Matft.diag(v: ret.s) *& ret.rt).nearest())
/*
mfarray =
[[ -0.40455368, -0.91451436],
[ -0.9145144, 0.4045536]], type=Float, shape=[2, 2]
mfarray =
[ 5.4649854, 0.36596614], type=Float, shape=[2]
mfarray =
[[ -0.5760485, -0.81741554],
[ 0.81741554, -0.5760485]], type=Float, shape=[2, 2]
mfarray =
[[ 1.0, 2.0],
[ 3.0, 4.0]], type=Float, shape=[2, 2]
*/

Polar decomposition​

Matft.linalg.polar_right returns (u, p), where u is an orthonormal matrix and p is a positive definite matrix. Matft.linalg.polar_left returns (p, l), where l is an orthonormal matrix and p is a positive definite matrix.

let a = MfArray([[0.5, 1, 2],
[1.5, 3, 4],
[2, 3.5, 1]])
let retR = try! Matft.linalg.polar_right(a)

print(retR.u)
print(retR.p)
/*
mfarray =
[[ 0.7279401870626366, -0.4224602202449294, 0.5400281903473371],
[ -0.28527166525638337, 0.529599993193229, 0.7988391103417394],
[ 0.6234766724273361, 0.7355618325608915, -0.26500118757960134]], type=Double, shape=[3, 3]
mfarray =
[[ 1.1830159405014165, 2.054293544789163, 0.9382703855270752],
[ 2.054293544789163, 3.7408061732978783, 2.009041364843949],
[ 0.938270385527075, 2.0090413648439487, 4.01041163448203]], type=Double, shape=[3, 3]
*/

See NumPy Mapping › Linear Algebra for all functions (det, pinv, lstsq, matrix_rank, norms, …).