@bluemath/linalg
Version:
Bluemath Linear Algebra library
392 lines (363 loc) • 12.2 kB
text/typescript
/*
Copyright (C) 2017 Jayesh Salvi, Blue Math Software Inc.
This file is part of bluemath.
bluemath is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
bluemath is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with bluemath. If not, see <http://www.gnu.org/licenses/>.
*/
import {NDArray} from '@bluemath/common'
import * as linalg from '../src'
export default function testLAPACK() {
QUnit.module('LAPACK', () => {
QUnit.module('BLAS Level 1', () => {
QUnit.module('dot', () => {
QUnit.test('sdot', assert => {
let sx = new NDArray([1,2,3,4]);
let sy = new NDArray([2,3,4,5]);
assert.equal(linalg.lapack.dot(sx.data,sy.data), 40);
});
QUnit.test('ddot', assert => {
let dx = new NDArray([1,2,3,4],{datatype:'f64'});
let dy = new NDArray([2,3,4,5],{datatype:'f64'});
assert.equal(linalg.lapack.dot(dx.data,dy.data), 40);
});
});
});
QUnit.module('BLAS Level 2', () => {
QUnit.module('gemv', () => {
QUnit.test('sgemv', assert => {
let A = new NDArray([
[2,3,4,5],
[1,0,7,5]
])
let x = new NDArray([2,2,2,2]);
let y = new NDArray([3,3]);
linalg.lapack.gemv(2,A.data,A.shape[0],A.shape[1],x.data,y.data,5);
assert.deepEqual(y.toArray(), [71,67]);
});
QUnit.test('dgemv', assert => {
let A = new NDArray([
[2,3,4,5],
[1,0,7,5]
], {datatype:'f64'})
let x = new NDArray([2,2,2,2], {datatype:'f64'});
let y = new NDArray([1,1], {datatype:'f64'});
linalg.lapack.gemv(2,A.data,A.shape[0],A.shape[1],x.data,y.data,5);
assert.deepEqual(y.toArray(), [61,57]);
});
});
});
QUnit.module('BLAS Level 3', () => {
QUnit.module('gemm', () => {
QUnit.test('sgemm', assert => {
let A = new NDArray([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
]);
let B = new NDArray([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
]);
let C = new NDArray([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
]);
linalg.lapack.gemm(A.data,B.data,C.data,4,4,4,1.5,2.5);
assert.deepEqual(C.toArray(), [
[8.5,8.5,8.5,8.5],
[8.5,8.5,8.5,8.5],
[8.5,8.5,8.5,8.5],
[8.5,8.5,8.5,8.5]
]);
});
QUnit.test('dgemm', assert => {
let A = new NDArray([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
], {datatype:'f64'});
let B = new NDArray([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
], {datatype:'f64'});
let C = new NDArray([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
], {datatype:'f64'});
linalg.lapack.gemm(A.data,B.data,C.data,4,4,4,1.5,3.5);
assert.deepEqual(C.toArray(), [
[9.5,9.5,9.5,9.5],
[9.5,9.5,9.5,9.5],
[9.5,9.5,9.5,9.5],
[9.5,9.5,9.5,9.5]
]);
});
});
});
QUnit.module('gesv', () => {
QUnit.test('sgesv - no permutation', assert => {
let A = new NDArray([
[11,-3,0],
[-3,6,-1],
[0,-1,3]
]);
let x = new NDArray([30,5,-25]);
let ipiv = linalg.lapack.gesv(A.data,x.data,A.shape[0],1);
assert.deepEqual(x.toArray(), [3,1,-8]);
assert.deepEqual(Array.prototype.slice.call(ipiv), [1,2,3]);
});
QUnit.test('sgesv - permutation', assert => {
let A = new NDArray([
[-3,6,-1],
[11,-3,0],
[0,-1,3]
]);
let x = new NDArray([30,5,-25]); // TODO: why this doesn't have to change?
let ipiv = linalg.lapack.gesv(A.data,x.data,A.shape[0],1);
assert.deepEqual(x.toArray(), [1,3,-8]);
assert.deepEqual(Array.prototype.slice.call(ipiv), [2,2,3]);
});
QUnit.test('dgesv - no permutation', assert => {
let A = new NDArray([
[11,-3,0],
[-3,6,-1],
[0,-1,3]
], {datatype:'f64'});
let x = new NDArray([30,5,-25], {datatype:'f64'});
let ipiv = linalg.lapack.gesv(A.data,x.data,A.shape[0],1);
assert.deepEqual(x.toArray(), [3,1,-8]);
assert.deepEqual(Array.prototype.slice.call(ipiv), [1,2,3]);
});
QUnit.test('dgesv - permutation', assert => {
let A = new NDArray([
[-3,6,-1],
[11,-3,0],
[0,-1,3]
], {datatype:'f64'});
let x = new NDArray([30,5,-25], {datatype:'f64'}); // TODO: why this doesn't have to change?
let ipiv = linalg.lapack.gesv(A.data,x.data,A.shape[0],1);
assert.deepEqual(x.toArray(), [1,3,-8]);
assert.deepEqual(Array.prototype.slice.call(ipiv), [2,2,3]);
});
});
// TODO
QUnit.module('gesdd', () => {
QUnit.test('dgesdd', assert => {
let A = new NDArray([
[-3,6,-1],
[11,-3,0],
[0,-1,3]
], {datatype:'f64'});
A.swapOrder();
let U = new NDArray({shape:[3,3]});
let VT = new NDArray({shape:[3,3]});
let S = new NDArray({shape:[3]});
linalg.lapack.gesdd(A.data, 3, 3,U.data,S.data,VT.data,'A');
U.swapOrder();
VT.swapOrder();
// Results generated from numpy
assert.ok(U.isEqual(new NDArray([
[-0.42847299, -0.81649658, 0.386968],
[0.90241006, -0.40824829, 0.1378021],
[0.04546408, 0.40824829, 0.91173809]
])));
assert.ok(S.isEqual(new NDArray([
12.4244289, 5.0, 2.5755711
])));
assert.ok(VT.isEqual(new NDArray([
[0.90241006, -0.42847299, 0.04546408],
[-0.40824829, -0.81649658, 0.40824829],
[0.1378021, 0.386968, 0.91173809]
])));
});
QUnit.test('sgesdd', assert => {
let A = new NDArray([
[-3,6,-1],
[11,-3,0],
[0,-1,3]
], {datatype:'f32'});
A.swapOrder();
let U = new NDArray({shape:[3,3]});
let VT = new NDArray({shape:[3,3]});
let S = new NDArray({shape:[3]});
linalg.lapack.gesdd(A.data, 3, 3,U.data,S.data,VT.data,'A');
U.swapOrder();
VT.swapOrder();
// Results generated from numpy
assert.ok(U.isEqual(new NDArray([
[-0.42847299, -0.81649658, 0.386968],
[0.90241006, -0.40824829, 0.1378021],
[0.04546408, 0.40824829, 0.91173809]
])));
assert.ok(S.isEqual(new NDArray([
12.4244289, 5.0, 2.5755711
])));
assert.ok(VT.isEqual(new NDArray([
[0.90241006, -0.42847299, 0.04546408],
[-0.40824829, -0.81649658, 0.40824829],
[0.1378021, 0.386968, 0.91173809]
])));
});
});
QUnit.module('gelsd', () => {
QUnit.test('dgelsd', assert => {
let Y = new NDArray([-1,0.2,0.9,2.1]);
let A = new NDArray([
[0,1], [1,1], [2,1], [3,1]
]);
let S = new NDArray({shape:[2]});
linalg.lapack.gelsd(A.data,4,2,1,-1,Y.data,S.data);
/*
Test output computed from numpy.linalg.lapack_lite.dgelsd execution
with same input data
In [20]: A = np.array([[0,1],[1,1],[2,1],[3,1]],np.double)
In [21]: B = np.array([-1,0.2,0.9,2.1],np.double)
In [22]: np.linalg.lapack_lite.dgelsd(4,2,1,A,4,B,4,np.zeros(2),-1,0,work,802,np.zeros(20,np.int32),0)
*/
assert.ok(A.isEqual(new NDArray([
[-1.73205081, 0.],
[0.57735027, 0.57735027],
[-2.88675135, 2.5819889],
[-0.04056742, 0.41363159]
])));
assert.ok(Y.isEqual(new NDArray([
1.65, -0.35, 0.4356074, 1.35655674
])));
});
});
QUnit.module('getrf', () => {
QUnit.test('dgetrf', assert => { // TODO
let A = new NDArray([
[3,6,2],
[1,7,6],
[9,3,2]
],{datatype:'f64'});
let ipiv = new NDArray({shape:[3],datatype:'i32'});
A.swapOrder();
linalg.lapack.getrf(A.data,3,3,ipiv.data);
A.swapOrder();
let customLU = new NDArray([
[3,6,2],
[1,7,6],
[9,3,2]
],{datatype:'f64'});
linalg.lu_custom(customLU);
assert.ok(A.isEqual(customLU,1e-4));
});
});
QUnit.module('geev', () => {
QUnit.test('dgeev 3x3', assert => {
/*
let A = new NDArray([
[3,6,2],
[1,7,6],
[9,3,2]
],{datatype:'f64'});
*/
let A = new NDArray([
[1,0,0],
[0,2,0],
[0,0,3]
],{datatype:'f64'});
A.swapOrder();
let [WR,WI,VL,VR] = linalg.lapack.geev(A.data,3,true,true);
assert.ok(WR[0] === 1 && WR[1] === 2 && WR[2] === 3);
assert.ok(WI[0] === 0 && WI[1] === 0 && WI[2] === 0);
let vl = new NDArray(VL,{shape:[3,3]})
let vr = new NDArray(VR,{shape:[3,3]})
vl.swapOrder();
vr.swapOrder();
assert.ok(vl.isEqual(new NDArray([
[1,0,0],
[0,1,0],
[0,0,1]
])));
assert.ok(vr.isEqual(new NDArray([
[1,0,0],
[0,1,0],
[0,0,1]
])));
});
QUnit.test('dgeev 2x2', assert => {
let A = new NDArray([
[3,1],
[0,2],
],{datatype:'f64'});
A.swapOrder();
let [WR,WI,VL,VR] = linalg.lapack.geev(A.data,2,true,true);
let vl = new NDArray(VL,{shape:[2,2]})
let vr = new NDArray(VR,{shape:[2,2]})
vl.swapOrder();
vr.swapOrder();
assert.equal(WR[0],3);
assert.equal(WR[1],2);
assert.equal(WI[0],0);
assert.equal(WI[1],0);
//assert.ok(vl.isEqual(new NDArray([[0.7071,0.0000],[0.7071,1.0000]]),1e-4))
// As returned by numpy (it only returns right eigen vectors)
assert.ok(vr.isEqual(new NDArray([[1.0000,-0.7071,],[0.0000,0.7071]]),1e-4))
});
});
QUnit.module('geqrf-orgqr', () => {
QUnit.test('dgeqrf-dorgqr', assert => {
let A = new NDArray([
[3, 6, 2],
[1, 7, 6],
[9, 3, 2]
]);
let tau = new NDArray({shape:[3],datatype:'f64'});
linalg.lapack.geqrf(A.data,3,3,tau.data);
assert.ok(A.isEqual(new NDArray([
[-7.,0.6,0.2],
[-8.14285714,-4.43777845,0.7008373],
[-7.,3.38006959,5.79440502]
])));
assert.ok(tau.isEqual(new NDArray([
1.42857143,1.34122607,0.
])));
linalg.lapack.orgqr(A.data,3,3,3,tau.data);
assert.ok(A.isEqual(new NDArray([
[-0.42857143,-0.85714286,-0.28571429],
[0.56104557,-0.00459873,-0.82777215],
[0.70820506,-0.51505822,0.48286708]
])));
});
});
QUnit.module('potrf', () => {
QUnit.test('dpotrf', assert => {
// From wikipedia
let A = new NDArray([
[4,12,-16],
[12,37,-43],
[-16,-43,98]
]);
linalg.lapack.potrf(A.data, 3);
//TODO: this only passes if internally 'L' is specified for UPLO
assert.equal(A.get(0,0), 2);
assert.equal(A.get(0,1), 6);
assert.equal(A.get(0,2), -8);
assert.equal(A.get(1,1), 1);
assert.equal(A.get(1,2), 5);
assert.equal(A.get(2,2), 3);
});
});
});
}