UNPKG

maia-util

Version:

Utility math and music functions supporting various applications by Music Artificial Intelligence Algorithms, Inc.

185 lines (167 loc) 5.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = siar; var _intersection_hash = require("./intersection_hash"); var _intersection_hash2 = _interopRequireDefault(_intersection_hash); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // const child_process = require('child_process') // const numchild = require('os').cpus().length // console.log("numchild:", numchild) // const myD = [ // [1, 1, 4], [1, 3, 5], [2, 1, 1], [2, 2, 6], [2, 3, 2], [3, 2, 3], // [6, 1, 4], [6, 3, 5], [7, 1, 1], [7, 2, 6], [7, 3, 2], [8, 2, 3], // [11, -1, 4], [11, 0, 1], [11, 0, 9], [11, 1, 5] // ] // const myD = [[0, 64], [1+1/3, 62], [1+2/3, 68], [3, 66]] // // siar(myD, 2) // export default function siar(D) { var r = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; // Tom Collins 31/01/2022. // In // D Array mandatory // r Integer optional // Out Array // This function calculates the structure induction algorithm over r // superdiagonals (SIAR, Collins, 2011). // It is assumed that the point set D is in lexicograhic order. // The implementation utilises a hash table, and is accurate to within 1e-5. var n = D.length; // Checking for input errors with regards to r. if (Math.floor(r) !== r || r <= 0) { console.log("r should be a positive integer. Returning."); return; } if (r >= n) { console.log("r should be less than D.length, and ideally small. Setting r = 1."); r = 1; } // Hash to store the difference vectors and associated indices. var V = {}; var _loop = function _loop(i) { var _loop2 = function _loop2(j) { // console.log("j:", j, "j - i - 1:", j - i - 1) var hash = D[j].map(function (djk, k) { // Calculate difference rounded to 5 d.p. and convert to string. return (Math.round(100000 * (djk - D[j - i - 1][k])) / 100000).toString(); }).toString(); if (V[hash] === undefined) { V[hash] = [j - i - 1]; } else { V[hash].push(j - i - 1); } }; for (var j = i + 1; j < n; j++) { _loop2(j); } }; for (var i = 0; i < r; i++) { _loop(i); } // console.log("V:", V) // Run SIA on a value of V if it contains more than one datapoint, recording // the results in one hash table L. var L = {}; var ndim = D[0].length; Object.keys(V).forEach(function (k) { if (V[k].length > 1) { var sidx = void 0; if (r === 1) { // Indices will be in ascending order. sidx = V[k]; } else { // Should sort the indices, because they won't necessarily be in ascending order. sidx = V[k].sort(); } sidx.forEach(function (i) { sidx.forEach(function (j) { if (j > i) { var hash = []; for (var dim = 0; dim < ndim; dim++) { hash[dim] = Math.round(100000 * (D[j][dim] - D[i][dim])) / 100000; } var hashAsStr = hash.join(","); // console.log("hash", hash_x, hash_y) if (L[hashAsStr] === undefined) { L[hashAsStr] = { "cnt": 1, "hash": hash }; } else { L[hashAsStr].cnt++; } } }); }); } }); // console.log("L:", L) var lByFreq = Object.keys(L).sort(function (a, b) { return L[b].cnt - L[a].cnt; }); // console.log("lByFreq:", lByFreq) // Hash D. var Dh = void 0; Dh = {}; D.map(function (d, idx) { var hash = d.map(function (val) { // Calculate difference rounded to 5 d.p. and convert to string. return (Math.round(100000 * val) / 100000).toString(); }).toString(); if (Dh[hash] === undefined) { Dh[hash] = idx; } else { console.log("Error: non-unique entry in D!"); return; } }); // console.log("Dh:", Dh) // This is the bit that could be parallelised. var outputMTP = []; lByFreq.forEach(function (vecAsStr) { // Object.keys(L).forEach(function(vecAsStr){ var vec = L[vecAsStr].hash; var Dmv = D.map(function (d) { return d.map(function (dk, k) { return dk - vec[k]; }); }); // console.log("Dmv:", Dmv) outputMTP.push({ "vector": vec, "MTP": (0, _intersection_hash2.default)(Dmv, Dh) }); }); return outputMTP; } // Here is some code for parallelising Node. // From https://stackoverflow.com/questions/20004935/best-way-to-execute-parallel-processing-in-node-js // const child_process = require('child_process') // const numchild = require('os').cpus().length // console.log("numchild:", numchild) // var done = 0; // // for (var i = 0; i < numchild; i++){ // var child = child_process.fork('./child'); // child.send((i + 1) * 1000); // child.on('message', function(message) { // console.log('[parent] received message from child:', message); // done++; // if (done === numchild) { // console.log('[parent] received all results'); // ... // } // }); // } // // // child.js // process.on('message', function(message) { // console.log('[child] received message from server:', message); // setTimeout(function() { // process.send({ // child : process.pid, // result : message + 1 // }); // process.disconnect(); // }, (0.5 + Math.random()) * 5000); // });