matrixlib-js
Version:
MatrixLib.js is a JavaScript simple matrix calculation library.
840 lines (769 loc) • 24.5 kB
JavaScript
/**
* # matrixLib-multiThread.js - v0.3.1
*
* Copyright (c) 2018 Kohei Katada.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
module.exports = (op) => {
'use strict';
// blob取得用
window.URL = window.URL || window.webkitURL;
/*
# util
*/
const util = {
/**
* # 引数がnullかundefinedではない事を確認する関数
* @param x
* @returns {boolean}
*/
existy(x) {
return x != null;
},
/**
* # 0と''もtrueとみなす真偽値を返す
* @param x
* @returns {boolean|*}
*/
truthy(x) {
return (x !== false) && util.existy(x);
},
/**
* # 数値かどうかの真偽値を返す
* @param num
* @returns {boolean}
*/
isNumber(num) {
return typeof num === 'number' && isFinite(num);
},
/**
* # 配列かどうかの真偽値を返す
* @param arr
* @returns {boolean}
*/
isArray(arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
},
/**
* # 関数かどうかの真偽値を返す
* @param fn
* @returns {boolean}
*/
isFunction(fn, notArrow) {
return Object.prototype.toString.call(fn) === '[object Function]' && (!notArrow || 'prototype' in fn);
},
/**
* # 正規乱数生成
* @param m
* @param s
* @returns {*}
*/
rnorm(m, s) {
const a = 1 - Math.random();
const b = 1 - Math.random();
const c = Math.sqrt(-2 * Math.log(a));
if(0.5 - Math.random() > 0) {
return c * Math.sin(Math.PI * 2 * b) * s + m;
}else{
return c * Math.cos(Math.PI * 2 * b) * s + m;
}
}
};
/*
# math
*/
const math = {
/*
# math.util
*/
util: {
/**
* # n次元配列の形状を返す
* @param arr
* @returns {[*,*]}
*/
shape(arr) {
let row, col;
if (!util.isArray(arr)) {
throw new Error(arr + 'がスカラー値なのでshape()は使えません.');
} else if (util.isArray(arr[0])) {
row = arr.length;
col = arr[0].length;
} else if (util.isArray(arr)) {
row = arr.length;
col = 0;
} else {
throw new Error(arr + 'が2次元以上の配列なのでshape()は使えません.');
}
return [row, col];
}
},
/*
# math.arr
*/
arr: {
/*
# math.arr.util
*/
util: {
/**
* # 1次元配列生成
* @param x {Number}
* @param v {*} # 配列の各要素を初期化する値(関数だった場合は関数の戻り値で初期化)
* @returns {Array}
*/
create(x, v) {
let r = [];
for (let i=0,l=x; i<l; i+=1) {
r[i] = util.isFunction(v) ? v() : v;
}
return r;
},
/**
* # step単位の、minSizeからmaxSizeまでの数の1次元配列を生成
* @param minSize
* @param maxSize
* @param step
* @param callback # 出来上がった配列に適用可能な関数
* @returns {Array}
*/
arange(minSize, maxSize, step, callback) {
// 初期化
let arr = [];
// step引数がないのに、maxSize引数がある場合
if (!step && !!maxSize) {
throw new Error('第三引数のステップ数が指定されていないため計算できません.');
}
// 引数がminSizeだけの場合
if (!step && !maxSize && !!minSize) {
// 引数がminSizeだけで、負の値だった場合
if (minSize < 0) {
throw new Error('負の値を指定するときは第二引数に範囲の最大値、第三引数にステップ数を指定してください.');
}
// 引数がminSizeだけで、正の値だった場合
for (let i=0,l=minSize; i<l; i+=1) {
arr[i] = i;
}
}
// 引数が全てある場合
if (!!step) {
if (maxSize <= minSize) {
throw new Error('第二引数の値は第一引数の値より大きい値を指定してください.');
}
let len = maxSize - minSize;
for (let i=0,l=len/step; i<l; i+=1) {
arr[i] = minSize + (step*i);
}
}
// コールバック関数がある場合
if (!!callback) {
for (let i=0,l=arr.length; i<l; i+=1) {
arr[i] = callback(arr[i]);
}
return arr;
}
return arr;
}
}
},
/*
# math.matrix
*/
matrix: {
/*
# math.matrix.util
*/
util: {
/**
* # 行列を生成
* @param x {Array|Number}
* @param y {Number}
* @param v {*} # 行列の各要素を初期化する値(関数だった場合は関数の戻り値で初期化)
* @returns {*}
*/
create(x, y, v) {
let r1;
if (util.isArray(x)) {
if (!util.isArray(x[0])) {
r1 = [x];
} else {
r1 = x;
}
}
let r2 = [];
for (let i=0,l=x; i<l; i+=1) {
r2[i] = (() => {
return math.arr.util.create(y, v);
})();
}
let r;
if (!!r1) {
r = r1;
} else {
r = r2;
}
return r;
},
/**
* # 行列の列を行に変換
* @param matrix
* @returns {Array}
*/
colToRow(matrix) {
if (math.util.shape(matrix)[1] === 0) {
return matrix;
}
let r = [];
for (let i=0,l=matrix[0].length; i<l; i+=1) {
r[i] = [];
for (let j=0,m=matrix.length; j<m; j+=1) {
r[i][j] = matrix[j][i];
}
}
return r;
}
}
},
/**
* # n次元配列同士の足し算
* @param x
* @param y
* @returns {Array}
*/
plus(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.plus(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の引き算 (x - y)
* @param x
* @param y
* @returns {Array}
*/
minus(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.minus(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の掛け算
* @param x
* @param y
* @returns {Array}
*/
multi(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.multi(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の割り算 (x / y)
* @param x
* @param y
* @returns {Array}
*/
div(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.div(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の大なり (x > y)
* @param x
* @param y
* @returns {Array}
*/
more(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.more(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の小なり (x < y)
* @param x
* @param y
* @returns {Array}
*/
less(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.less(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の大なりイコール (x >= y)
* @param x
* @param y
* @returns {Array}
*/
moreEq(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.moreEq(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の小なりイコール (x <= y)
* @param x
* @param y
* @returns {Array}
*/
lessEq(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.lessEq(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の同値演算 (x === y)
* @param x
* @param y
* @returns {Array}
*/
equal(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.equal(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # n次元配列同士の非同値演算 (x !== y)
* @param x
* @param y
* @returns {Array}
*/
notEqual(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.notEqual(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* n次元配列の総和を求める
* @param x
* @param axis
* @returns {*}
*/
sum(x, axis) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var axis = e.data[1];
self.postMessage(mt.math.sum(x, axis));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, axis, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 配列中の最大値のインデックスを取得
* @param x
* @param axis
* @returns {Number|number}
*/
maxIdx(x, axis) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var axis = e.data[1];
self.postMessage(mt.math.maxIdx(x, axis));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, axis, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 2つの配列の同じインデックスの要素の値が同じだった場合に、そのカウント数を取得する
* @param x
* @param y
* @returns {number}
*/
matchCount(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.matchCount(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 真偽値を数値1か0に変換する
* @param x
* @returns {Promise<any>}
*/
boolToInt(x) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
self.postMessage(mt.math.boolToInt(x));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 真偽値を任意の値に変換する
* @param x
* @callback
* @returns {Promise<any>}
*/
valToAnyVal(x, callback) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var callback = e.data[1];
self.postMessage(mt.math.valToAnyVal(x, eval('('+callback+')')));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, callback.toString(), op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 累乗する
* @param x
* @param n
* @returns {*}
*/
pow(x, n) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var n = e.data[1];
self.postMessage(mt.math.pow(x, n));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, n, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # Ex を返す.(自然対数の底であるネイピア数(オイラー数))
* @param x
* @returns {*}
*/
exp(x) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
self.postMessage(mt.math.exp(x));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 自然対数 (底は e) を返す.
* @param x
* @returns {*}
*/
log(x) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
self.postMessage(mt.math.log(x));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 一番大きい数値を返す
* @param x
* @param axis
* @returns {number}
*/
max(x, axis) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var axis = e.data[1];
self.postMessage(mt.math.max(x, axis));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, axis, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 大きい方の値を返す
* @param x
* @param y
* @returns {Promise<any>}
*/
maximum(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.maximum(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 多次元配列を1次元配列にする
* @param x
* @returns {Array}
*/
flatten(x) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
self.postMessage(mt.math.flatten(x));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
/**
* # 行列の内積を計算
* @param x
* @param y
* @returns {Promise<any>}
*/
dot(x, y) {
return new Promise((resolve, reject) => {
const s = `onmessage = function (e) {
importScripts(e.data[e.data.length-1]);
var mt = matrixlibJs();
var x = e.data[0];
var y = e.data[1];
self.postMessage(mt.math.dot(x, y));
self.close();
};`;
const worker = new Worker(window.URL.createObjectURL(new Blob([s], {type: 'application/javascript'})));
worker.postMessage([x, y, op.libUrl]);
worker.onmessage = (e) => {
resolve(e.data);
window.URL.revokeObjectURL(worker);
};
});
},
};
// api
return {
util: util,
math: math
};
};