UNPKG

maia-hash

Version:

Hashing and fingerprinting functions supporting various applications by Music Artificial Intelligence Algorithms, Inc.

1,184 lines (1,086 loc) 46.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // Imports var fs = require("fs"); var path = require("path"); var mu = require("maia-util"); // import PointSet from './PointSet' var HasherNoConcat = function () { function HasherNoConcat(_mapPath) { _classCallCheck(this, HasherNoConcat); if (_mapPath !== undefined) { this.map = require(_mapPath); } else { this.map = {}; } } _createClass(HasherNoConcat, [{ key: "contains", value: function contains(aKey) { return this.map[aKey]; } // The expected format is with ontime in the first dimension and pitch in the // second dimension of pts. It is assumed that pts is sorted // lexicographically. }, { key: "create_hash_entries", value: function create_hash_entries(pts, fnam) { var mode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "duples"; var insertMode = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "increment and file with fnams"; var tMin = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0.1; var tMax = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 10; var pMin = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 1; var pMax = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 12; var folder = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : __dirname; var npts = pts.length; // console.log("npts:", npts) var nh = 0; switch (mode) { case "duples": for (var i = 0; i < npts - 1; i++) { var v0 = pts[i]; var j = i + 1; while (j < npts) { var v1 = pts[j]; var td = v1[0] - v0[0]; var apd = Math.abs(v1[1] - v0[1]); // console.log("i:", i, "j:", j) // Decide whether to make a hash entry. if (td > tMin && td < tMax && apd >= pMin && apd <= pMax) { // Make a hash entry, something like "±pdtd" var he = this.create_hash_entry([v1[1] - v0[1], td], mode, v0[0], fnam, tMin, tMax); this.insert(he); nh++; } // End whether to make a hash entry. if (td >= tMax) { j = npts - 1; } j++; } // End while. } // for (let i = 0; break; case "triples": for (var _i = 0; _i < npts - 2; _i++) { var _v = pts[_i]; var _j = _i + 1; while (_j < npts - 1) { var _v2 = pts[_j]; var td1 = Math.round(100000 * (_v2[0] - _v[0])) / 100000; var apd1 = Math.abs(_v2[1] - _v[1]); // console.log("i:", i, "j:", j) // Decide whether to proceed to v1 and v2. if (td1 > tMin && td1 < tMax && apd1 >= pMin && apd1 <= pMax) { var k = _j + 1; while (k < npts) { var v2 = pts[k]; var td2 = Math.round(100000 * (v2[0] - _v2[0])) / 100000; var apd2 = Math.abs(v2[1] - _v2[1]); // console.log("j:", j, "k:", k) // Decide whether to make a hash entry. if (td2 > tMin && td2 < tMax && apd2 >= pMin && apd2 <= pMax) { // Make a hash entry, something like "±pd1±pd2tdr" var _he = this.create_hash_entry([_v2[1] - _v[1], v2[1] - _v2[1], td2 / td1], mode, _v[0], fnam, tMin, tMax); this.insert(_he, insertMode, folder, [_i, _j, k]); nh++; } // End whether to make a hash entry. if (td2 >= tMax) { k = npts - 1; } k++; } // End k while. } if (td1 >= tMax) { _j = npts - 2; } _j++; } // End j while. } // for (let i = 0; break; default: console.log("Should not get to default in create_hash_entries() switch."); } return nh; } }, { key: "create_hash_entry", value: function create_hash_entry(vals, mode, ctime, fnam, tMin, tMax) { var str = "", isInteger = void 0; switch (mode) { case "duples": // Sense-check pitch difference. var apd = Math.abs(vals[0]); if (apd >= 100 || Math.round(vals[0]) !== vals[0]) { console.log("Unexpected pitch difference:", vals[0]); console.log("Returning."); return; } if (vals[0] >= 0) { str += "+"; } else { str += "-"; } if (apd < 10) { str += "0"; } str += apd; // Sense-check time difference. isInteger = Math.round(vals[1]) === vals[1]; if (vals[1] >= tMax || vals[1] < tMin) { console.log("Unexpected time difference:", vals[1]); console.log("Returning."); return; } // Round time difference to 1 d.p. and append to str. str += Math.round(10 * vals[1]) / 10; if (isInteger) { str += ".0"; } break; case "triples": // Sense-check pitch difference. vals.slice(0, 2).forEach(function (v, idx) { var apd = Math.abs(v); if (apd >= 100 || Math.round(v) !== v) { console.log("Unexpected pitch difference:", v, idx); console.log("Returning."); return; } if (v >= 0) { str += "+"; } else { str += "-"; } if (apd < 10) { str += "0"; } str += apd; }); // Sense-check time difference ratio. if (vals[2] >= tMax / tMin || vals[2] < tMin / tMax) { console.log("Unexpected time difference:", vals[2]); console.log("Returning."); return; } // If ratio less than 1, invert and give it a negative sign so that such // values are as accurately represented as positive values. // console.log("vals[2] before inversion:", vals[2]) var sign = "+"; if (vals[2] < 1) { vals[2] = 1 / vals[2]; sign = "-"; } // console.log("vals[2] after inversion:", vals[2]) str += sign; // Round time difference ratio to 1 d.p. and append to str. var dp1 = Math.round(10 * vals[2]) / 10; isInteger = Math.round(dp1) === dp1; // console.log("isInteger:", isInteger) str += dp1; if (isInteger) { str += ".0"; } // console.log("str:", str) break; default: console.log("Should not get to default in create_hash_entry() switch."); } return { "hash": str, "ctimes": [ctime], "fnams": [fnam] }; } // Obsolete }, { key: "get_piece_names", value: function get_piece_names(countBins, binSize) { var topN = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 100; var out = []; countBins.forEach(function (value, key) { var pieceHist = countBins.get(key); pieceHist.forEach(function (setSize, idx) { out.push({ "pieceId": key, "index": idx, "setSize": setSize }); }); }); // "out" contains the index of bin, // and it is sorted based on the corresponding number of hash entries contained in "hist". out.sort(function (a, b) { return b.setSize - a.setSize; }); out = out.slice(0, topN); return out.map(function (entry) { return { "winningPiece": entry.pieceId, "edge": entry.index * binSize, "count": entry.setSize }; }); } }, { key: "insert", value: function insert(hashEntry) { var method = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "hash and lookup"; var dir = arguments[2]; var tripleIdx = arguments[3]; var key = hashEntry.hash; var lookup = this.contains(key); switch (method) { case "hash and lookup": if (lookup !== undefined) { // Extend ctimes and fnams arrays. lookup.ctimes.push(hashEntry.ctimes[0]); lookup.fnams.push(hashEntry.fnams[0]); } else { delete hashEntry.hash; this.map[key] = hashEntry; } break; case "increment and file with fnams": if (lookup !== undefined) { this.map[key].increment++; } else { this.map[key] = { "increment": 1, "log": fs.openSync(path.join(dir, key + ".json"), "a") }; } fs.writeSync(this.map[key].log, JSON.stringify([Math.round(100 * hashEntry.ctimes[0]) / 100, hashEntry.fnams[0]]) + ","); break; case "increment and file with fnams and tripleIdx": // save triples of points for visualising if (lookup !== undefined) { this.map[key].increment++; } else { this.map[key] = { "increment": 1, "log": fs.openSync(path.join(dir, key + ".json"), "a") }; } fs.writeSync(this.map[key].log, JSON.stringify([Math.round(100 * hashEntry.ctimes[0]) / 100, hashEntry.fnams[0], tripleIdx]) + ","); break; case "increment and file": if (lookup !== undefined) { this.map[key].increment++; } else { this.map[key] = { "increment": 1, "log": fs.openSync(path.join(dir, key + ".json"), "a" // {"flags": "a"} ) }; } var content = JSON.stringify(Math.round(100 * hashEntry.ctimes[0]) / 100) + ","; // 82.3MB // const content = JSON.stringify(Math.round(10 * hashEntry.ctimes[0]) / 10) + "," // 72.MB // const content = JSON.stringify(hashEntry.ctimes[0]) + "," // 162.9MB fs.writeSync(this.map[key].log, content); // this.map[key].log.write(content) // fs.writeFileSync( // path.join(dir, key + ".json"), // JSON.stringify( // [ // Math.round(10*hashEntry.ctimes[0])/10, // hashEntry.fnams[0] // ] // ) // + ",", // { "flag": "a" } // ) break; default: console.log("Should not get to default in insert()!"); } } // The expected format is with time in the first dimension and pitch in the // second dimension of pts. It is assumed that pts is sorted // lexicographically. // maxOntimes: the max ontime of each piece of music in a dataset. }, { key: "match_hash_entries", value: function match_hash_entries(pts) { var mode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "duples"; var tMin = arguments[2]; var tMax = arguments[3]; var pMin = arguments[4]; var pMax = arguments[5]; var maxOntimes = arguments[6]; var binSize = arguments[7]; var _this = this; var folder = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : __dirname; var topN = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 100; var uninh = new Set(); // const bins = Math.ceil(maxOntimes[maxOntimes.length - 1] / binSize); var countBins = new Map(); // let countBin = new Array(bins).fill(0).map(() => { // return new Set() // }) pts = pts.slice(0, 80); var npts = pts.length; var nh = 0; var queLookupHashPointIdx = new Map(); // save matched query triples according to each countBin index. // Collect the topN matches. Will keep this sorted descending by setSize // property. var out = []; var jdx = 0; // Increment to populate out and throw away any unused entries. switch (mode) { case "duples": for (var i = 0; i < npts - 1; i++) { var v0 = pts[i]; var j = i + 1; while (j < npts) { var v1 = pts[j]; var td = Math.round(100000 * (v1[0] - v0[0])) / 100000; var apd = Math.abs(v1[1] - v0[1]); // console.log("i:", i, "j:", j) // Decide whether to make a hash entry. if (td > tMin && td < tMax && apd >= pMin && apd <= pMax) { (function () { // Make a hash entry, something like "±pdtd" var he = _this.create_hash_entry([v1[1] - v0[1], td], mode, v0[0]); // console.log("he:", he) // Is there a match? var lookup = _this.contains(he.hash); if (lookup !== undefined) { // There's a match! lookup.ctimes.forEach(function (ctime) { tInDset.push(ctime); tInQuery.push(he.ctimes[0]); }); } nh++; })(); } // End whether to make a hash entry. if (td >= tMax) { j = npts - 1; } j++; } // End while. } // for (let i = 0; return { "nosHashes": nh, "uninosHashes": uninh.size, "countBins": countBins.map(function (value) { return value.size; }) //break };case "triples": loop1: for (var _i2 = 0; _i2 < npts - 2; _i2++) { var _v3 = pts[_i2]; var _j2 = _i2 + 1; while (_j2 < npts - 1) { var _v4 = pts[_j2]; var td1 = Math.round(100000 * (_v4[0] - _v3[0])) / 100000; var apd1 = Math.abs(_v4[1] - _v3[1]); // console.log("i:", i, "j:", j) // Decide whether to proceed to v1 and v2. if (td1 > tMin && td1 < tMax && apd1 >= pMin && apd1 <= pMax) { var k = _j2 + 1; while (k < npts) { var v2 = pts[k]; var td2 = Math.round(100000 * (v2[0] - _v4[0])) / 100000; var apd2 = Math.abs(v2[1] - _v4[1]); // console.log("j:", j, "k:", k) // Decide whether to make a hash entry. if (td2 > tMin && td2 < tMax && apd2 >= pMin && apd2 <= pMax) { var _ret2 = function () { var he = _this.create_hash_entry([_v4[1] - _v3[1], v2[1] - _v4[1], td2 / td1], mode, _v3[0]); if (fs.existsSync(path.join(folder, he.hash + ".json"))) { var lookupStr = fs.readFileSync(path.join(folder, he.hash + ".json"), "utf8").slice(0, -1); var lookup = JSON.parse("[" + lookupStr + "]"); lookup.forEach(function (item) { var tmp_fname = item[1]; var tmp_ontime = item[0]; // create a new countBin when a new music with quired hash appears. if (!countBins.has(tmp_fname)) { var bins = Math.ceil(maxOntimes[tmp_fname] / binSize); countBins.set(tmp_fname, new Array(bins).fill(0).map(function () { return new Set(); })); } // Important line, and where other transformation operations // could be supported in future. var dif = tmp_ontime - he.ctimes[0]; if (dif >= 0 && dif <= maxOntimes[tmp_fname]) { var index_now = Math.floor(dif / binSize); var setArray = countBins.get(tmp_fname); var target = setArray[index_now]; target.add(he.hash); } }); } uninh.add(he.hash); nh++; if (nh > 5000) { return "break|loop1"; } }(); if (_ret2 === "break|loop1") break loop1; } // End whether to make a hash entry. if (td2 >= tMax) { k = npts - 1; } k++; } // End k while. } if (td1 >= tMax) { _j2 = npts - 2; } _j2++; } // End j while. } // for (let i = 0; // Collect the topN matches. Will keep this sorted descending by setSize // property. var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { var _loop = function _loop() { var key = _step.value; var countBinsForPiece = countBins.get(key).map(function (value) { return value.size; }); countBinsForPiece.forEach(function (count, idx) { if (jdx === 0 || // Nothing in it. jdx < topN - 1 || // Still isn't full given value of topN. count > out[out.length - 1]["setSize"] // Bigger match than current minimum. ) { out[jdx] = { "winningPiece": key, "edge": idx * binSize, "setSize": count }; out.sort(function (a, b) { return b.setSize - a.setSize; }); if (jdx < topN - 1) { jdx++; } } }); }; for (var _iterator = countBins.keys()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { _loop(); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } break; case "tripleIdx": var _loop2 = function _loop2(_i3) { var v0 = pts[_i3]; var j = _i3 + 1; while (j < npts - 1) { var _v5 = pts[j]; var _td = Math.round(100000 * (_v5[0] - v0[0])) / 100000; var _apd = Math.abs(_v5[1] - v0[1]); // console.log("i:", i, "j:", j) // Decide whether to proceed to v1 and v2. if (_td > tMin && _td < tMax && _apd >= pMin && _apd <= pMax) { var _ret5 = function () { var k = j + 1; while (k < npts) { var _v6 = pts[k]; var _td2 = Math.round(100000 * (_v6[0] - _v5[0])) / 100000; var _apd2 = Math.abs(_v6[1] - _v5[1]); // console.log("j:", j, "k:", k) // Decide whether to make a hash entry. if (_td2 > tMin && _td2 < tMax && _apd2 >= pMin && _apd2 <= pMax) { var _ret6 = function () { var he = _this.create_hash_entry([_v5[1] - v0[1], _v6[1] - _v5[1], _td2 / _td], "triples", v0[0]); if (fs.existsSync(path.join(folder, he.hash + ".json"))) { var lookupStr = fs.readFileSync(path.join(folder, he.hash + ".json"), "utf8").slice(0, -1); var lookup = JSON.parse("[" + lookupStr + "]"); lookup.forEach(function (item) { var tmp_fname = item[1]; var tmp_ontime = item[0]; // create a new countBin when a new music with quired hash appears. if (!countBins.has(tmp_fname)) { var bins = Math.ceil(maxOntimes[tmp_fname] / binSize); countBins.set(tmp_fname, new Array(bins).fill(0).map(function () { return new Set(); })); queLookupHashPointIdx.set(tmp_fname, new Array(bins).fill(0).map(function () { return new Set(); })); // Initialising } // Important line, and where other transformation operations // could be supported in future. var dif = tmp_ontime - he.ctimes[0]; if (dif >= 0 && dif <= maxOntimes[tmp_fname]) { var index_now = Math.floor(dif / binSize); var setArray = countBins.get(tmp_fname); var target = setArray[index_now]; if (!target.has(he.hash)) { target.add(he.hash); var queArray = queLookupHashPointIdx.get(tmp_fname); var tarQueBin = queArray[index_now]; tarQueBin.add([[_i3, j, k], item[2]]); } } }); } uninh.add(he.hash); nh++; if (nh > 5000) { return { v: { v: "break|loop1" } }; } }(); if ((typeof _ret6 === "undefined" ? "undefined" : _typeof(_ret6)) === "object") return _ret6.v; } // End whether to make a hash entry. if (_td2 >= tMax) { k = npts - 1; } k++; } // End k while. }(); if ((typeof _ret5 === "undefined" ? "undefined" : _typeof(_ret5)) === "object") return _ret5.v; } if (_td >= tMax) { j = npts - 2; } j++; } // End j while. }; loop1: for (var _i3 = 0; _i3 < npts - 2; _i3++) { var _ret4 = _loop2(_i3); if (_ret4 === "break|loop1") break loop1; } // for (let i = 0; // Collect the topN matches. Will keep this sorted descending by setSize // property. var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { var _loop3 = function _loop3() { var key = _step2.value; var countBinsForPiece = countBins.get(key).map(function (value) { return value.size; }); countBinsForPiece.forEach(function (count, idx) { if (jdx === 0 || // Nothing in it. jdx < topN - 1 || // Still isn't full given value of topN. count > out[out.length - 1]["setSize"] // Bigger match than current minimum. ) { out[jdx] = { "winningPiece": key, "edge": idx * binSize, "setSize": count, "queLookupTriplets": Array.from(queLookupHashPointIdx.get(key)[idx]) }; out.sort(function (a, b) { return b.setSize - a.setSize; }); if (jdx < topN - 1) { jdx++; } } }); }; for (var _iterator2 = countBins.keys()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { _loop3(); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } break; default: console.log("Should not get to default in match_hash_entries() switch."); } return { "nosHashes": nh, "uninosHashes": uninh.size, "countBins": out }; } // Return the count of unique matched hashes. // A query and a lookup piece will be regarded as a matched pair if their fingerprinting score > a threshold. }, { key: "match_query_lookup_piece", value: function match_query_lookup_piece(lookupPts, lookupFname, queryPts) { var mode = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "triples"; var tMin = arguments[4]; var tMax = arguments[5]; var pMin = arguments[6]; var pMax = arguments[7]; var maxOntimes = arguments[8]; var _this2 = this; var binSize = arguments[9]; var topN = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : 100; var lookupHashes = {}; var uninh = new Set(); // const bins = Math.ceil(maxOntimes[maxOntimes.length - 1] / binSize); var countBins = new Map(); // let countBin = new Array(bins).fill(0).map(() => { // return new Set() // }) // let pts = queryPts.slice(0, 80) // const npts = pts.length var npts = queryPts.length; var nh = 0; // Collect the topN matches. Will keep this sorted descending by setSize // property. var out = []; var jdx = 0; // Increment to populate out and throw away any unused entries. switch (mode) { case "triples": // Building hash table for the lookup piece. for (var i = 0; i < lookupPts.length - 2; i++) { var v0 = lookupPts[i]; var j = i + 1; while (j < lookupPts.length - 1) { var v1 = lookupPts[j]; var td1 = Math.round(100000 * (v1[0] - v0[0])) / 100000; var apd1 = Math.abs(v1[1] - v0[1]); // console.log("i:", i, "j:", j) // Decide whether to proceed to v1 and v2. if (td1 > tMin && td1 < tMax && apd1 >= pMin && apd1 <= pMax) { var k = j + 1; while (k < lookupPts.length) { var v2 = lookupPts[k]; var td2 = Math.round(100000 * (v2[0] - v1[0])) / 100000; var apd2 = Math.abs(v2[1] - v1[1]); // console.log("j:", j, "k:", k) // Decide whether to make a hash entry. if (td2 > tMin && td2 < tMax && apd2 >= pMin && apd2 <= pMax) { var he = this.create_hash_entry([v1[1] - v0[1], v2[1] - v1[1], td2 / td1], mode, v0[0]); if (he.hash in lookupHashes === false) { lookupHashes[he.hash] = []; } lookupHashes[he.hash].push(he.ctimes[0]); } // End whether to make a hash entry. if (td2 >= tMax) { k = lookupPts.length - 1; } k++; } // End k while. } if (td1 >= tMax) { j = lookupPts.length - 2; } j++; } } // Finding matched hashes. loop1: for (var _i4 = 0; _i4 < npts - 2; _i4++) { var _v7 = queryPts[_i4]; var _j3 = _i4 + 1; while (_j3 < npts - 1) { var _v8 = queryPts[_j3]; var _td3 = Math.round(100000 * (_v8[0] - _v7[0])) / 100000; var _apd3 = Math.abs(_v8[1] - _v7[1]); // console.log("i:", i, "j:", j) // Decide whether to proceed to v1 and v2. if (_td3 > tMin && _td3 < tMax && _apd3 >= pMin && _apd3 <= pMax) { var _k = _j3 + 1; while (_k < npts) { var _v9 = queryPts[_k]; var _td4 = Math.round(100000 * (_v9[0] - _v8[0])) / 100000; var _apd4 = Math.abs(_v9[1] - _v8[1]); // console.log("j:", j, "k:", k) // Decide whether to make a hash entry. if (_td4 > tMin && _td4 < tMax && _apd4 >= pMin && _apd4 <= pMax) { var _ret8 = function () { var he = _this2.create_hash_entry([_v8[1] - _v7[1], _v9[1] - _v8[1], _td4 / _td3], mode, _v7[0]); if (he.hash in lookupHashes) { var lookup = lookupHashes[he.hash]; var tmp_fname = lookupFname; lookup.forEach(function (item) { var tmp_ontime = item; // create a new countBin when a new music with quired hash appears. if (!countBins.has(tmp_fname)) { var bins = Math.ceil(maxOntimes / binSize); countBins.set(tmp_fname, new Array(bins).fill(0).map(function () { return new Set(); })); } // Important line, and where other transformation operations // could be supported in future. var dif = tmp_ontime - he.ctimes[0]; if (dif >= 0 && dif <= maxOntimes) { var index_now = Math.floor(dif / binSize); var setArray = countBins.get(tmp_fname); var target = setArray[index_now]; target.add(he.hash); } }); } uninh.add(he.hash); nh++; if (nh > 5000) { return "break|loop1"; } }(); if (_ret8 === "break|loop1") break loop1; } // End whether to make a hash entry. if (_td4 >= tMax) { _k = npts - 1; } _k++; } // End k while. } if (_td3 >= tMax) { _j3 = npts - 2; } _j3++; } // End j while. } // for (let i = 0; // Collect the topN matches. Will keep this sorted descending by setSize // property. var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { var _loop4 = function _loop4() { var key = _step3.value; var countBinsForPiece = countBins.get(key).map(function (value) { return value.size; }); countBinsForPiece.forEach(function (count, idx) { if (jdx === 0 || // Nothing in it. jdx < topN - 1 || // Still isn't full given value of topN. count > out[out.length - 1]["setSize"] // Bigger match than current minimum. ) { out[jdx] = { "winningPiece": key, "edge": idx * binSize, "setSize": count }; out.sort(function (a, b) { return b.setSize - a.setSize; }); if (jdx < topN - 1) { jdx++; } } }); }; for (var _iterator3 = countBins.keys()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { _loop4(); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } break; default: console.log("Should not get to default in match_hash_entries() switch."); } return { "nosHashes": nh, "uninosHashes": uninh.size, "countBins": out }; } // Checking if a query matches a lookup piece by taking pre-processed hashes as input. }, { key: "match_precomputed_hashes", value: function match_precomputed_hashes(input_lookupHashes, input_queryHashes, maxOntimes, binSize, lookupFname) { var topN = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 100; var mode = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : "triples"; var lookupHashes = input_lookupHashes; var queryFull = input_queryHashes; var queryHashes = Object.keys(input_queryHashes); var uninh = new Set(); // const bins = Math.ceil(maxOntimes[maxOntimes.length - 1] / binSize); var countBins = new Map(); // let countBin = new Array(bins).fill(0).map(() => { // return new Set() // }) // let pts = queryPts.slice(0, 80) // const npts = pts.length var nh = 0; // Collect the topN matches. Will keep this sorted descending by setSize // property. var out = []; var jdx = 0; // Increment to populate out and throw away any unused entries. switch (mode) { case "triples": var _loop5 = function _loop5(i) { if (queryHashes[i] in lookupHashes) { var lookup = lookupHashes[queryHashes[i]].ctimes; var tmp_fname = lookupFname; lookup.forEach(function (item) { var tmp_ontime = item; // create a new countBin when a new music with quired hash appears. if (!countBins.has(tmp_fname)) { var bins = Math.ceil(maxOntimes / binSize); countBins.set(tmp_fname, new Array(bins).fill(0).map(function () { return new Set(); })); } // Important line, and where other transformation operations // could be supported in future. // Loop over ctimes in the query. var query_ctimes = queryFull[queryHashes[i]].ctimes; for (var idx_q_ctimes = 0; idx_q_ctimes < query_ctimes.length; idx_q_ctimes++) { var dif = tmp_ontime - query_ctimes[idx_q_ctimes]; if (dif >= 0 && dif <= maxOntimes) { var index_now = Math.floor(dif / binSize); var setArray = countBins.get(tmp_fname); var target = setArray[index_now]; target.add(queryHashes[i]); } } }); } uninh.add(queryHashes[i]); nh++; if (nh > 5000) { return "break|loop1"; } }; // Finding matched hashes. loop1: for (var i = 0; i < queryHashes.length; i++) { var _ret10 = _loop5(i); if (_ret10 === "break|loop1") break loop1; } // Collect the topN matches. Will keep this sorted descending by setSize // property. var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { var _loop6 = function _loop6() { var key = _step4.value; var countBinsForPiece = countBins.get(key).map(function (value) { return value.size; }); countBinsForPiece.forEach(function (count, idx) { if (jdx === 0 || // Nothing in it. jdx < topN - 1 || // Still isn't full given value of topN. count > out[out.length - 1]["setSize"] // Bigger match than current minimum. ) { out[jdx] = { "winningPiece": key, "edge": idx * binSize, "setSize": count }; out.sort(function (a, b) { return b.setSize - a.setSize; }); if (jdx < topN - 1) { jdx++; } } }); }; for (var _iterator4 = countBins.keys()[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { _loop6(); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } break; default: console.log("Should not get to default in match_hash_entries() switch."); } return { "nosHashes": nh, "uninosHashes": uninh.size, "countBins": out }; } // Checking if a query matches a lookup piece by taking pre-processed lookup hashes as input, while process hashes for query online. }, { key: "match_precomputed_lookup_hashes", value: function match_precomputed_lookup_hashes(input_lookupHashes, queryPts, maxOntimes, binSize, lookupFname, tMin, tMax, pMin, pMax) { var _this3 = this; var topN = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 100; var mode = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : "triples"; var lookupHashes = input_lookupHashes; var uninh = new Set(); // const bins = Math.ceil(maxOntimes[maxOntimes.length - 1] / binSize); var countBins = new Map(); // let countBin = new Array(bins).fill(0).map(() => { // return new Set() // }) // let pts = queryPts.slice(0, 80) // const npts = pts.length var npts = queryPts.length; var nh = 0; // Collect the topN matches. Will keep this sorted descending by setSize // property. var out = []; var jdx = 0; // Increment to populate out and throw away any unused entries. switch (mode) { case "triples": // Finding matched hashes. // Finding matched hashes. loop1: for (var i = 0; i < npts - 2; i++) { var v0 = queryPts[i]; var j = i + 1; while (j < npts - 1) { var v1 = queryPts[j]; var td1 = Math.round(100000 * (v1[0] - v0[0])) / 100000; var apd1 = Math.abs(v1[1] - v0[1]); // console.log("i:", i, "j:", j) // Decide whether to proceed to v1 and v2. if (td1 > tMin && td1 < tMax && apd1 >= pMin && apd1 <= pMax) { var k = j + 1; while (k < npts) { var v2 = queryPts[k]; var td2 = Math.round(100000 * (v2[0] - v1[0])) / 100000; var apd2 = Math.abs(v2[1] - v1[1]); // console.log("j:", j, "k:", k) // Decide whether to make a hash entry. if (td2 > tMin && td2 < tMax && apd2 >= pMin && apd2 <= pMax) { var _ret12 = function () { var he = _this3.create_hash_entry([v1[1] - v0[1], v2[1] - v1[1], td2 / td1], mode, v0[0]); if (he.hash in lookupHashes) { var lookup = lookupHashes[he.hash].ctimes; var tmp_fname = lookupFname; lookup.forEach(function (item) { var tmp_ontime = item; // create a new countBin when a new music with quired hash appears. if (!countBins.has(tmp_fname)) { var bins = Math.ceil(maxOntimes / binSize); countBins.set(tmp_fname, new Array(bins).fill(0).map(function () { return new Set(); })); } // Important line, and where other transformation operations // could be supported in future. var dif = tmp_ontime - he.ctimes[0]; if (dif >= 0 && dif <= maxOntimes) { var index_now = Math.floor(dif / binSize); var setArray = countBins.get(tmp_fname); var target = setArray[index_now]; target.add(he.hash); } }); } uninh.add(he.hash); nh++; if (nh > 5000) { return "break|loop1"; } }(); if (_ret12 === "break|loop1") break loop1; } // End whether to make a hash entry. if (td2 >= tMax) { k = npts - 1; } k++; } // End k while. } if (td1 >= tMax) { j = npts - 2; } j++; } // End j while. } // for (let i = 0; // Collect the topN matches. Will keep this sorted descending by setSize // property. var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { var _loop7 = function _loop7() { var key = _step5.value; var countBinsForPiece = countBins.get(key).map(function (value) { return value.size; }); countBinsForPiece.forEach(function (count, idx) { if (jdx === 0 || // Nothing in it. jdx < topN - 1 || // Still isn't full given value of topN. count > out[out.length - 1]["setSize"] // Bigger match than current minimum. ) { out[jdx] = { "winningPiece": key, "edge": idx * binSize, "setSize": count }; out.sort(function (a, b) { return b.setSize - a.setSize; }); if (jdx < topN - 1) { jdx++; } } }); }; for (var _iterator5 = countBins.keys()[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { _loop7(); } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } break; default: console.log("Should not get to default in match_hash_entries() switch."); } return { "nosHashes": nh, "uninosHashes": uninh.size, "countBins": out }; } }]); return HasherNoConcat; }(); exports.default = HasherNoConcat;