UNPKG

@bluemath/linalg

Version:
392 lines (363 loc) 12.2 kB
/* 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); }); }); }); }