Skip to content

Commit

Permalink
Use Buffer instead of FFI.Pointer as recommended by the FFI 1.x.x API
Browse files Browse the repository at this point in the history
- Use Buffer instead of FFI.Pointer
- Use read*/write* methods of Buffer instead of put* and get*
- Replace seeking in Buffers by calculating offsets
  • Loading branch information
addaleax committed Mar 20, 2015
1 parent 8115e26 commit 5ef1f8b
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 54 deletions.
20 changes: 8 additions & 12 deletions lib/node-lapack/fortranArray.js
Expand Up @@ -23,9 +23,8 @@ THE SOFTWARE.
var FFI = require('ffi');

function fortranArrayToJSMatrix(fortranArray, m, n, elementSize) {
var op = elementSize == 8 ? 'getDouble' : 'getFloat';
var op = elementSize == 8 ? 'readDoubleLE' : 'readFloatLE';
var array = [];
var a;
var rowWidth = elementSize * n;
var columnOffset = m * elementSize;

Expand All @@ -34,8 +33,7 @@ function fortranArrayToJSMatrix(fortranArray, m, n, elementSize) {
var rowStart = i * elementSize;

for(var j = 0; j < n; j++) {
a = fortranArray.seek(columnOffset * j + rowStart);
row.push(a[op]());
row.push(fortranArray[op](columnOffset * j + rowStart));
}

array.push(row);
Expand All @@ -45,14 +43,13 @@ function fortranArrayToJSMatrix(fortranArray, m, n, elementSize) {
}

function jsMatrixToFortranArray(array, elementSize) {
var op = elementSize == 8 ? 'putDouble' : 'putFloat';
var op = elementSize == 8 ? 'writeDoubleLE' : 'writeFloatLE';
var m = array.length;
var n = array[0].length;
var fortranArrayStart = fortranArray = new FFI.Pointer(m * n * elementSize);
var fortranArrayStart = fortranArray = new Buffer(m * n * elementSize);
for(var j = 0; j < n; j++) {
for(var i = 0; i < m; i++) {
fortranArray[op](array[i][j]);
fortranArray = fortranArray.seek(elementSize);
for(var i = 0; i < m; i++) {
fortranArray[op](array[i][j], elementSize * (j * m + i));
}
}

Expand All @@ -62,9 +59,8 @@ function jsMatrixToFortranArray(array, elementSize) {
function fortranArrayToJSArray(fortranArray, n, op, elementSize) {
var array = [];

for(var i = 0; i < n; i++) {
array.push(fortranArray[op]());
fortranArray = fortranArray.seek(elementSize);
for(var i = 0; i < n; i++) {
array.push(fortranArray[op](i * elementSize));
}

return array;
Expand Down
84 changes: 42 additions & 42 deletions lib/node-lapack/lapack.js
Expand Up @@ -72,14 +72,14 @@ function eye(m) {
function matrixOp(matrix, elementSize, callback) {
var m = matrix.length;
var n = matrix[0].length;
var f_m = new FFI.Pointer(FORTRAN_INT);
var f_n = new FFI.Pointer(FORTRAN_INT);
var f_m = new Buffer(FORTRAN_INT);
var f_n = new Buffer(FORTRAN_INT);
var f_a = fortranArray.jsMatrixToFortranArray(matrix, elementSize);
var f_lda = new FFI.Pointer(FORTRAN_INT);
var f_lda = new Buffer(FORTRAN_INT);

f_m.putInt32(m);
f_n.putInt32(n);
f_lda.putInt32(Math.max(1, m));
f_m.writeInt32LE(m, 0);
f_n.writeInt32LE(n, 0);
f_lda.writeInt32LE(Math.max(1, m), 0);

callback(m, n, f_m, f_n, f_a, f_lda);
}
Expand All @@ -95,16 +95,16 @@ function zeroBottomLeft(matrix) {
}

function sgesv(a, b) {
var f_info = new FFI.Pointer(FORTRAN_INT);
var f_info = new Buffer(FORTRAN_INT);
var result = {};

matrixOp(a, FORTRAN_FLOAT, function(am, an, af_m, af_n, f_a) {
var f_ipiv = new FFI.Pointer(am * FORTRAN_INT);
var f_ipiv = new Buffer(am * FORTRAN_INT);

matrixOp(b, FORTRAN_FLOAT, function(bm, bn, bf_m, bf_n, f_b) {
LAPACK.sgesv_(af_m, bf_n, f_a, af_n, f_ipiv, f_b, bf_m, f_info);
result.X = fortranArray.fortranArrayToJSMatrix(f_b, bm, bn, FORTRAN_FLOAT);
result.P = ipivToP(bm, fortranArray.fortranArrayToJSArray(f_ipiv, bm, 'getInt', FORTRAN_FLOAT));
result.P = ipivToP(bm, fortranArray.fortranArrayToJSArray(f_ipiv, bm, 'readInt32LE', FORTRAN_FLOAT));
});
});

Expand All @@ -115,8 +115,8 @@ function qr(matrix) {
var result;

sgeqrf(matrix, function(qr, m, n, f_m, f_n, f_a, f_lda, f_tau, f_work, f_lwork, f_info) {
var f_k = new FFI.Pointer(FORTRAN_INT);
f_k.putInt32(Math.min(m, n));
var f_k = new Buffer(FORTRAN_INT);
f_k.writeInt32LE(Math.min(m, n), 0);
LAPACK.sorgqr_(f_m, f_n, f_k, f_a, f_lda, f_tau, f_work, f_lwork, f_info);
qr.Q = fortranArray.fortranArrayToJSMatrix(f_a, m, n, FORTRAN_FLOAT);
qr.R = zeroBottomLeft(qr.R);
Expand All @@ -127,31 +127,31 @@ function qr(matrix) {
}

function sgeqrf(matrix, callback) {
return geqrf(matrix, 'getFloat', LAPACK.sgeqrf_, FORTRAN_FLOAT, callback);
return geqrf(matrix, 'readFloatLE', LAPACK.sgeqrf_, FORTRAN_FLOAT, callback);
}

function dgeqrf(matrix, callback) {
return geqrf(matrix, 'getDouble', LAPACK.dgeqrf_, FORTRAN_DOUBLE, callback);
return geqrf(matrix, 'readDoubleLE', LAPACK.dgeqrf_, FORTRAN_DOUBLE, callback);
}

function geqrf(matrix, op, lapackFunc, elementSize, callback) {
var qr;

matrixOp(matrix, elementSize, function(m, n, f_m, f_n, f_a, f_lda) {
var f_tau = new FFI.Pointer(m * n * elementSize);
var f_info = new FFI.Pointer(FORTRAN_INT);
var f_lwork = new FFI.Pointer(FORTRAN_INT);
var f_tau = new Buffer(m * n * elementSize);
var f_info = new Buffer(FORTRAN_INT);
var f_lwork = new Buffer(FORTRAN_INT);
var f_work;
f_lwork.putInt32(-1);
f_lwork.writeInt32LE(-1, 0);

// get optimal size of workspace
f_work = new FFI.Pointer(FORTRAN_INT);
f_work = new Buffer(FORTRAN_DOUBLE);
lapackFunc(f_m, f_n, f_a, f_lda, f_tau, f_work, f_lwork, f_info);
lwork = f_work[op]();
lwork = f_work[op](0);

// allocate workspace
f_work = new FFI.Pointer(lwork * elementSize);
f_lwork.putInt32(lwork);
f_work = new Buffer(lwork * elementSize);
f_lwork.writeInt32LE(lwork, 0);

// perform QR decomp
lapackFunc(f_m, f_n, f_a, f_lda, f_tau, f_work, f_lwork, f_info);
Expand Down Expand Up @@ -239,46 +239,46 @@ function getrf(matrix, lapackFunc, elementSize) {
var result = {};

matrixOp(matrix, elementSize, function(m, n, f_m, f_n, f_a, f_lda) {
var f_ipiv = new FFI.Pointer(Math.min(m, n) * FORTRAN_INT);
var f_info = new FFI.Pointer(FORTRAN_INT);
var f_ipiv = new Buffer(Math.min(m, n) * FORTRAN_INT);
var f_info = new Buffer(FORTRAN_INT);
lapackFunc(f_m, f_n, f_a, f_m, f_ipiv, f_info);
result.LU = fortranArray.fortranArrayToJSMatrix(f_a, m, n, elementSize);
result.IPIV = fortranArray.fortranArrayToJSArray(f_ipiv, Math.min(m, n), 'getInt', elementSize);
result.IPIV = fortranArray.fortranArrayToJSArray(f_ipiv, Math.min(m, n), 'readInt32LE', elementSize);
});

return result;
}

function sgesvd(jobu, jobvt, matrix) {
var f_jobu = new FFI.Pointer(FORTRAN_CHAR);
var f_jobvt = new FFI.Pointer(FORTRAN_CHAR);
f_jobu.putChar(jobu.charCodeAt(0));
f_jobvt.putChar(jobvt.charCodeAt(0));
var f_jobu = new Buffer(FORTRAN_CHAR);
var f_jobvt = new Buffer(FORTRAN_CHAR);
f_jobu.writeUInt8(jobu.charCodeAt(0), 0);
f_jobvt.writeUInt8(jobvt.charCodeAt(0), 0);
var svd;

matrixOp(matrix, FORTRAN_FLOAT, function(m, n, f_m, f_n, f_a, f_lda) {
var f_s = new FFI.Pointer(Math.pow(Math.min(m, n), 2) * FORTRAN_FLOAT);
var f_u = new FFI.Pointer(Math.pow(m, 2) * FORTRAN_FLOAT);
var f_ldu = new FFI.Pointer(FORTRAN_INT);
f_ldu.putInt32(m);
var f_s = new Buffer(Math.pow(Math.min(m, n), 2) * FORTRAN_FLOAT);
var f_u = new Buffer(Math.pow(m, 2) * FORTRAN_FLOAT);
var f_ldu = new Buffer(FORTRAN_INT);
f_ldu.writeInt32LE(m, 0);

// TODO: punting on dims for now. revisit with http://www.netlib.org/lapack/single/sgesvd.f
var f_vt = new FFI.Pointer(Math.pow(n, 2) * FORTRAN_FLOAT);
var f_ldvt = new FFI.Pointer(FORTRAN_INT);
f_ldvt.putInt32(n);
var f_vt = new Buffer(Math.pow(n, 2) * FORTRAN_FLOAT);
var f_ldvt = new Buffer(FORTRAN_INT);
f_ldvt.writeInt32LE(n, 0);

var lwork = -1;
var f_work = new FFI.Pointer(FORTRAN_FLOAT);
var f_lwork = new FFI.Pointer(FORTRAN_INT);
f_lwork.putInt32(lwork);
var f_info = new FFI.Pointer(FORTRAN_INT);
var f_work = new Buffer(FORTRAN_FLOAT);
var f_lwork = new Buffer(FORTRAN_INT);
f_lwork.writeInt32LE(lwork, 0);
var f_info = new Buffer(FORTRAN_INT);

LAPACK.sgesvd_(f_jobu, f_jobvt, f_m, f_n, f_a, f_lda, f_s, f_u, f_ldu, f_vt, f_ldvt,
f_work, f_lwork, f_info);

lwork = f_work.getFloat();
f_work = new FFI.Pointer(lwork * FORTRAN_FLOAT);
f_lwork.putInt32(lwork);
lwork = f_work.readFloatLE(0);
f_work = new Buffer(lwork * FORTRAN_FLOAT);
f_lwork.writeInt32LE(lwork, 0);

LAPACK.sgesvd_(f_jobu, f_jobvt, f_m, f_n, f_a, f_lda, f_s, f_u, f_ldu, f_vt, f_ldvt,
f_work, f_lwork, f_info);
Expand Down

0 comments on commit 5ef1f8b

Please sign in to comment.