UNPKG

matrixlib-js

Version:

MatrixLib.js is a JavaScript simple matrix calculation library.

840 lines (769 loc) 24.5 kB
/** * # 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 }; };