sylvester
Advanced tools
Comparing version 0.0.12 to 0.0.13
@@ -36,2 +36,47 @@ // Copyright (c) 2011, Chris Umbel, James Coglan | ||
function svdJs() { | ||
var A = this; | ||
var V = Matrix.I(A.rows()); | ||
var S = A.transpose(); | ||
var U = Matrix.I(A.cols()); | ||
var err = Number.MAX_VALUE; | ||
var i = 0; | ||
var maxLoop = 100; | ||
while(err > 2.2737e-13 && i < maxLoop) { | ||
var qr = S.transpose().qr(); | ||
S = qr.R; | ||
V = V.x(qr.Q); | ||
qr = S.transpose().qr(); | ||
U = U.x(qr.Q); | ||
S = qr.R; | ||
var e = S.triu(1).unroll().norm(); | ||
var f = S.diagonal().norm(); | ||
if(f == 0) | ||
f = 1; | ||
err = e / f; | ||
i++; | ||
} | ||
var ss = S.diagonal(); | ||
var s = []; | ||
for(var i = 1; i <= ss.cols(); i++) { | ||
var ssn = ss.e(i); | ||
s.push(Math.abs(ssn)); | ||
if(ssn < 0) { | ||
for(var j = 0; j < U.rows(); j++) { | ||
V.elements[j][i - 1] = -(V.elements[j][i - 1]); | ||
} | ||
} | ||
} | ||
return {U: U, S: $V(s).toDiagonalMatrix(), V: V}; | ||
} | ||
function Matrix() {} | ||
@@ -60,47 +105,2 @@ Matrix.prototype = { | ||
svd: function() { | ||
var A = this; | ||
var U = Matrix.I(A.rows()); | ||
var S = A.transpose(); | ||
var V = Matrix.I(A.cols()); | ||
var err = Number.MAX_VALUE; | ||
var i = 0; | ||
var maxLoop = 100; | ||
while(err > 2.2737e-13 && i < maxLoop) { | ||
var qr = S.transpose().qr(); | ||
S = qr.R; | ||
U = U.x(qr.Q); | ||
qr = S.transpose().qr(); | ||
V = V.x(qr.Q); | ||
S = qr.R; | ||
var e = S.triu(1).unroll().norm(); | ||
var f = S.diagonal().norm(); | ||
if(f == 0) | ||
f = 1; | ||
err = e / f; | ||
i++; | ||
} | ||
var ss = S.diagonal(); | ||
var s = []; | ||
for(var i = 1; i <= ss.cols(); i++) { | ||
var ssn = ss.e(i); | ||
s.push(Math.abs(ssn)); | ||
if(ssn < 0) { | ||
for(var j = 0; j < U.rows(); j++) { | ||
U.elements[j][i - 1] = -(U.elements[j][i - 1]); | ||
} | ||
} | ||
} | ||
return {U: U, S: $V(s).toDiagonalMatrix(), V: V}; | ||
}, | ||
unroll: function() { | ||
@@ -711,5 +711,22 @@ var v = []; | ||
// Constructor function | ||
Matrix.create = function(elements) { | ||
var M = new Matrix(); | ||
return M.setElements(elements); | ||
Matrix.create = function(elements, useLapack) { | ||
var M = new Matrix().setElements(elements); | ||
if(useLapack) { | ||
var lapack = require('lapack'); | ||
M.svd = function() { | ||
var result = lapack.sgesvd('A', 'A', this.elements); | ||
return { | ||
U: $M(result.U), | ||
S: $M(result.S).column(1).toDiagonalMatrix(), | ||
V: $M(result.VT).transpose() | ||
}; | ||
}; | ||
} else { | ||
M.svd = svdJs; | ||
} | ||
return M; | ||
}; | ||
@@ -716,0 +733,0 @@ |
{ | ||
"name": "sylvester", | ||
"description": "node.js implementation of James Coglan's \"Sylvester\" matrix math library.", | ||
"version": "0.0.12", | ||
"version": "0.0.13", | ||
"engines": { | ||
@@ -6,0 +6,0 @@ "node": ">=0.2.6" |
@@ -67,3 +67,17 @@ | ||
it('should svd', function() { | ||
var U = $M([[-0.5110308651281587, 0.2132007163556105, 0.7071067811881557, 0.4397646068404634], | ||
[0.08729449334404742, -0.8528028654224428, 1.882731224298497e-12, 0.514885369921382], | ||
[-0.6856198518162525, -0.42640143271122105, -2.157344709257849e-12, -0.5900061329997158], | ||
[-0.5110308651281581, 0.21320071635561055, -0.7071067811849397, 0.4397646068456342]]); | ||
var S = $M([[5.85410196624969, 0, 0, 0], | ||
[0, 2.999999999999999, 0, 0], | ||
[0, 0, 1.0000000000000002, 0], | ||
[0, 0, 0, 0.8541019662496846]]); | ||
var V = $M([[-0.5110308651281575, 0.21320071635561047, -0.7071067811884307, -0.43976460684002194], | ||
[0.08729449334404744, -0.8528028654224414, -2.2043789591597237e-12, -0.5148853699213815], | ||
[-0.6856198518162527, -0.42640143271122066, 2.525858488366184e-12, 0.590006132999716], | ||
[-0.5110308651281579, 0.21320071635561044, 0.7071067811846652, -0.4397646068460757], | ||
]); | ||
it('should svd in JS', function() { | ||
var A2 = $M([ | ||
@@ -74,21 +88,34 @@ [ 1, -1, 2, 2], | ||
[ 2, -1, 2, 1] | ||
]); | ||
], false); | ||
var svd = A2.svd(); | ||
expect(svd.U.eql($M([[-0.5110308651281575, 0.21320071635561047, -0.7071067811884307, -0.43976460684002194], | ||
[0.08729449334404744, -0.8528028654224414, -2.2043789591597237e-12, -0.5148853699213815], | ||
[-0.6856198518162527, -0.42640143271122066, 2.525858488366184e-12, 0.590006132999716], | ||
[-0.5110308651281579, 0.21320071635561044, 0.7071067811846652, -0.4397646068460757], | ||
]))).toBeTruthy(); | ||
expect(svd.S.eql($M([[5.85410196624969, 0, 0, 0], | ||
[0, 2.999999999999999, 0, 0], | ||
[0, 0, 1.0000000000000002, 0], | ||
[0, 0, 0, 0.8541019662496846]]))).toBeTruthy(); | ||
expect(svd.V.eql($M([[-0.5110308651281587, 0.2132007163556105, 0.7071067811881557, 0.4397646068404634], | ||
[0.08729449334404742, -0.8528028654224428, 1.882731224298497e-12, 0.514885369921382], | ||
[-0.6856198518162525, -0.42640143271122105, -2.157344709257849e-12, -0.5900061329997158], | ||
[-0.5110308651281581, 0.21320071635561055, -0.7071067811849397, 0.4397646068456342]]))).toBeTruthy(); | ||
expect(svd.U.eql(U)).toBeTruthy(); | ||
expect(svd.S.eql(S)).toBeTruthy(); | ||
expect(svd.V.eql(V)).toBeTruthy(); | ||
}); | ||
it('should svd in lapack', function() { | ||
var lapack; | ||
try{ | ||
lapack = require('lapack'); | ||
} catch(e) {} | ||
// this is so incredibly optional i'll only bother testing if it's around. | ||
// will likely break it out into seperate spec folder later once i get an understanding | ||
// of the impact of LAPACK on this project. | ||
if(lapack) { | ||
var A2 = $M([ | ||
[ 1, -1, 2, 2], | ||
[-1, 2, 1, -1], | ||
[ 2, 1, 3, 2], | ||
[ 2, -1, 2, 1] | ||
], true); | ||
var svd = A2.svd(); | ||
expect(svd.U.eql(U)).toBeTruthy(); | ||
expect(svd.S.eql(S)).toBeTruthy(); | ||
expect(svd.V.eql(V)).toBeTruthy(); | ||
} | ||
}); | ||
@@ -95,0 +122,0 @@ |
Sorry, the diff of this file is not supported yet
2420
204
94509