sylvester
Advanced tools
Comparing version 0.0.15 to 0.0.16
@@ -36,2 +36,3 @@ // Copyright (c) 2011, Chris Umbel, James Coglan | ||
function svdJs() { | ||
@@ -45,34 +46,34 @@ var A = this; | ||
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 qr = S.transpose().qrJs(); | ||
S = qr.R; | ||
V = V.x(qr.Q); | ||
qr = S.transpose().qrJs(); | ||
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]); | ||
} | ||
} | ||
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]); | ||
} | ||
} | ||
} | ||
@@ -83,2 +84,47 @@ | ||
function svdPack() { | ||
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() | ||
}; | ||
} | ||
function qrJs() { | ||
var m = this.rows(); | ||
var n = this.cols(); | ||
var Q = Matrix.I(m); | ||
var A = this; | ||
for(var k = 1; k < Math.min(m, n); k++) { | ||
var ak = A.slice(k, 0, k, k).col(1); | ||
var oneZero = [1]; | ||
while(oneZero.length <= m - k) | ||
oneZero.push(0); | ||
oneZero = $V(oneZero); | ||
var vk = ak.add(oneZero.x(ak.norm() * Math.sign(ak.e(1)))); | ||
var Vk = $M(vk); | ||
var Hk = Matrix.I(m - k + 1).subtract(Vk.x(2).x(Vk.transpose()).div(Vk.transpose().x(Vk).e(1, 1))); | ||
var Qk = identSize(Hk, m, n, k); | ||
A = Qk.x(A); | ||
// slow way to compute Q | ||
Q = Q.x(Qk); | ||
} | ||
return {Q: Q, R: A}; | ||
} | ||
function qrPack() { | ||
var qr = lapack.qr(this.elements); | ||
return { | ||
Q: $M(qr.Q), | ||
R: $M(qr.R) | ||
}; | ||
} | ||
function Matrix() {} | ||
@@ -119,28 +165,2 @@ Matrix.prototype = { | ||
qr: function() { | ||
var m = this.rows(); | ||
var n = this.cols(); | ||
var Q = Matrix.I(m); | ||
var A = this; | ||
for(var k = 1; k < Math.min(m, n); k++) { | ||
var ak = A.slice(k, 0, k, k).col(1); | ||
var oneZero = [1]; | ||
while(oneZero.length <= m - k) | ||
oneZero.push(0); | ||
oneZero = $V(oneZero); | ||
var vk = ak.add(oneZero.x(ak.norm() * Math.sign(ak.e(1)))); | ||
var Vk = $M(vk); | ||
var Hk = Matrix.I(m - k + 1).subtract(Vk.x(2).x(Vk.transpose()).div(Vk.transpose().x(Vk).e(1, 1))); | ||
var Qk = identSize(Hk, m, n, k); | ||
A = Qk.x(A); | ||
Q = Q.x(Qk); | ||
} | ||
return {Q: Q, R: A}; | ||
}, | ||
slice: function(startRow, endRow, startCol, endCol) { | ||
@@ -709,3 +729,8 @@ var x = []; | ||
return $V(mins); | ||
} | ||
}, | ||
svdJs: svdJs, | ||
svdPack: svdPack, | ||
qrJs: qrJs, | ||
qrPack: qrPack | ||
}; | ||
@@ -722,13 +747,7 @@ | ||
if(lapack = getLapack()) { | ||
Matrix.prototype.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() | ||
}; | ||
}; | ||
Matrix.prototype.svd = svdPack; | ||
Matrix.prototype.qr = qrPack; | ||
} else { | ||
Matrix.prototype.svd = svdJs; | ||
Matrix.prototype.qr = qrJs; | ||
} | ||
@@ -735,0 +754,0 @@ |
{ | ||
"name": "sylvester", | ||
"description": "node.js implementation of James Coglan's \"Sylvester\" matrix math library.", | ||
"version": "0.0.15", | ||
"version": "0.0.16", | ||
"engines": { | ||
@@ -6,0 +6,0 @@ "node": ">=0.2.6" |
@@ -7,3 +7,2 @@ | ||
describe('matrix', function() { | ||
/* | ||
describe('PCA', function() { | ||
@@ -35,3 +34,2 @@ it('should PCA', function() { | ||
}); | ||
*/ | ||
@@ -85,36 +83,53 @@ it('shoud triu', function () { | ||
it('should svd in JS', function() { | ||
var A2 = $M([ | ||
[ 1, -1, 2, 2], | ||
[-1, 2, 1, -1], | ||
[ 2, 1, 3, 2], | ||
[ 2, -1, 2, 1] | ||
]); | ||
var ASVD = $M([ | ||
[ 1, -1, 2, 2], | ||
[-1, 2, 1, -1], | ||
[ 2, 1, 3, 2], | ||
[ 2, -1, 2, 1] | ||
]); | ||
it('should svd', function() { | ||
var svd = ASVD.svdJs(); | ||
expect(svd.U.eql(U)).toBeTruthy(); | ||
expect(svd.S.eql(S)).toBeTruthy(); | ||
expect(svd.V.eql(V)).toBeTruthy(); | ||
}); | ||
var svd = A2.svd(); | ||
//expect(svd.U.eql(U)).toBeTruthy(); | ||
//expect(svd.S.eql(S)).toBeTruthy(); | ||
//expect(svd.V.eql(V)).toBeTruthy(); | ||
it('should have matching svds for js and lapack', function() { | ||
var svdJs = ASVD.svdJs(); | ||
var svdPack = ASVD.svdPack(); | ||
expect(svdJs.U.eql(svdPack.U)).toBeTruthy(); | ||
expect(svdJs.S.eql(svdPack.S)).toBeTruthy(); | ||
expect(svdJs.V.eql(svdPack.V)).toBeTruthy(); | ||
}); | ||
it('should qr', function() { | ||
var A2 = $M([ | ||
[1, -1, 2, 2], | ||
[-1, 2, 1, -1], | ||
[2, 1, 3, 2], | ||
[2, -1, 2, 1] | ||
]); | ||
var QRin = $M([ | ||
[1, -1, 2, 2], | ||
[-1, 2, 1, -1], | ||
[2, 1, 3, 2], | ||
[2, -1, 2, 1] | ||
]); | ||
var qr = A2.qr(); | ||
expect(qr.Q.eql($M([[-0.316227766016838, 0.28342171556262064, 0.8226876614429064, -0.3779644730092273], | ||
[0.31622776601683794, -0.6883098806520787, 0.5323273103454103, 0.3779644730092272], | ||
[-0.6324555320336759, -0.6478210641431328, -0.19357356739833098, -0.37796447300922714], | ||
[-0.6324555320336759, 0.16195526603578317, 0.048393391849582745, 0.7559289460184544]]))).toBeTruthy(); | ||
expect(qr.R.eql($M([[-3.1622776601683795, 0.9486832980505139, -3.478505426185217, -2.8460498941515415], | ||
[1.91055907392895e-17, -2.4698178070456938, -1.7410191098846692, 0.1214664495268375], | ||
[-2.254600901479451e-16, 2.0686390257580927e-16, 1.6937687147353957, 0.7742942695933234], | ||
[3.446764628337833e-17, 8.098938594673387e-17, 2.220446049250313e-16, -1.1338934190276815]]))).toBeTruthy(); | ||
var Qout = $M([[-0.316227766016838, 0.28342171556262064, 0.8226876614429064, -0.3779644730092273], | ||
[0.31622776601683794, -0.6883098806520787, 0.5323273103454103, 0.3779644730092272], | ||
[-0.6324555320336759, -0.6478210641431328, -0.19357356739833098, -0.37796447300922714], | ||
[-0.6324555320336759, 0.16195526603578317, 0.048393391849582745, 0.7559289460184544]]); | ||
var Rout = $M([[-3.1622776601683795, 0.9486832980505139, -3.478505426185217, -2.8460498941515415], | ||
[1.91055907392895e-17, -2.4698178070456938, -1.7410191098846692, 0.1214664495268375], | ||
[-2.254600901479451e-16, 2.0686390257580927e-16, 1.6937687147353957, 0.7742942695933234], | ||
[3.446764628337833e-17, 8.098938594673387e-17, 2.220446049250313e-16, -1.1338934190276815]]); | ||
it('should qr from javascript', function() { | ||
var qr = QRin.qrJs(); | ||
expect(qr.Q.eql(Qout)).toBeTruthy(); | ||
expect(qr.R.eql(Rout)).toBeTruthy(); | ||
}); | ||
it('should qr from lapack', function() { | ||
var qr = QRin.qrPack(); | ||
expect(qr.Q.eql(Qout)).toBeTruthy(); | ||
expect(qr.R.eql(Rout)).toBeTruthy(); | ||
}); | ||
it('should create a 1\'s matrix', function() { | ||
@@ -121,0 +136,0 @@ var Ones = Matrix.One(2, 3); |
95069
2433