UNPKG

open-data

Version:

A package filled with data structures, sort algorithms, selections, and more to come

188 lines (185 loc) 4.37 kB
const s = require('./structures'); let cluster; try { cluster = require('cluster'); } catch (e) { console.log('Non-fatal error', e); } let os; try { os = require('os'); } catch (e) { console.log('Non-fatal error', e); } const identity=i=>i; class Matrix { constructor (identifier=identity) { this.size = 0; this.storage = []; this.swapSpace = []; this.identifier= identifier; } set (x, y, value) { this.storage[y] = this.storage[y] || []; if (this.storage[y][x] === undefined) this.size++; this.storage[y][x] = value; this.swapSpace[x] = this.swapSpace[x] || []; this.swapSpace[x][y] = value; } clone () { let clone = new Matrix(this.identifier); clone.size = this.size; clone.storage = this.storage; clone.swapSpace = this.swapSpace; return clone; } get (x, y) { return this.storage[y] ? this.storage[y][x] : undefined; } row (y) { return this.storage[y] || []; } setRow (y, arr) { arr.forEach((value, x) => { this.set(x, y, value); }); } setCol (x, arr) { return this.setColumn(x, arr); } setColumn (x, arr) { arr.forEach((value, y) => { this.set(x, y, value); }); } column (x) { return this.swapSpace[x] || []; } forEach (cb) { this.storage.forEach((row, y) => { row.forEach((value, x) => { cb(value, x, y); }); }); } forEachRow (cb) { this.storage.forEach((row, y) => { cb(row, y); }); } forEachCol (cb) { this.swapSpace.forEach((col, x) => { cb(col, x); }); } map (cb) { let clone = this.clone(); clone.swapSpace.map((column, x) => { return column.map((value, y) => { return cb(value, x, y); }); }); clone.storage.map((row, y) => { return row.map((value, x) => { return cb(value, x, y); }); }); return clone; } pow(n) { if (pow > 0) { let current = this.clone(); for (let i = 0; i < n; i++) { current = current.multiply(this.clone()); } return current; } } transpose() { let result = new Matrix(this.identifier); this.forEach((value, x, y) => { result.set(y,x, value); }); return result; } add (m) { let result = new Matrix(this.identifier); this.forEach((value, x, y) => { result.set(x,y, value + (m.get(x, y) || 0)); }); m.forEach((value, x, y) => { result.set(x,y, value + (this.get(x,y) || 0)); }); return result; } multiply (m) { if (typeof m === 'number') { let result = this.clone(); result.map(x => x * m); } else if (m.constructor !== Matrix) { throw new Error('TypeError: must be a matrix or a number'); } else { let result = new Matrix(this.identifier); this.forEachRow((row, y) => { let newRow = []; m.forEachCol((col, x) => { let v = 0; row.forEach((e, i) => v += e * col[i]); newRow.push(v); }); result.setRow(y, newRow); }); return result; } } clusterMult (m, cb) { if (cluster === undefined || os === undefined) { throw new Error('cluster not defined in this environment'); } if (m.constructor !== Matrix) { throw new Error('TypeError: matrix multiplication must be of type matrix.'); } if (cluster.isMaster) { let result = new Matrix(this.identifier); let workers = []; let incoming = new s.Queue(); this.forEachRow((row, y) => { incoming.enqueue({row, y}); }); //worker.send master --> worker //process.on('message') worker --> master; const constructWorker = (i) => { let worker = cluster.fork(); worker.on('online', ()=>{ let r = incoming.dequeue(); let row = r.row; let newRow = []; m.forEachCol((col, x) => { let v = 0; row.forEach((e, i) => v += e * col[i]); newRow.push(v); }); result.setRow(r.y, newRow); worker.kill(0); }); worker.on('exit', ()=>{ if (incoming.length > 0) { workers[i] = constructWorker(i); } else { workers.forEach(w => w.kill(0)); cb(result); } }); return worker; } for (let i = 0; i < Math.min(incoming.length, os.cpus().length); i ++) { let w = constructWorker(i); workers.push(w); } }; } toString () { return this.storage.map(row => row.toString()).join('\n'); } } module.exports = Matrix;