UNPKG

hdsp2

Version:

High-Dimensional Space Projections

254 lines 9.54 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SparseMDSSGD = void 0; var Edge_1 = __importDefault(require("./Edge")); var fibonacci_heap_1 = require("@tyriar/fibonacci-heap"); var SparseTerm_1 = __importDefault(require("./SparseTerm")); var Utils_1 = require("./Utils"); var SparseMDSSGD = (function () { function SparseMDSSGD() { } SparseMDSSGD.project = function (n, m, I, J, V, D, p, seed, t_max, eps) { console.debug("Building weighted graph..."); var graph = SparseMDSSGD.buildGraphWeighted(n, m, I, J, V); console.debug("Sampling pivots..."); var closest_pivots = SparseMDSSGD.maxmin_random_sp_weighted(graph, p, 0, seed); console.debug("Configuring terms..."); var terms = SparseMDSSGD.MSSP_weighted(graph, closest_pivots); console.debug("Configuring schedule..."); var etas = SparseMDSSGD.schedule(terms, t_max, eps); console.debug("Initializing layout..."); var X = Utils_1.Utils.random2D(n, D); console.debug("Computing layout..."); SparseMDSSGD.sgd(X, D, terms, etas, seed); return X; }; SparseMDSSGD.sgd = function (X, D, terms, etas, seed) { for (var i_eta = 0; i_eta < etas.length; i_eta++) { var eta = etas[i_eta]; SparseMDSSGD.fisheryates_shuffle(terms); var n_terms = terms.length; for (var i_term = 0; i_term < n_terms; i_term++) { var t = terms[i_term]; var i = t.i; var j = t.j; var d_ij = t.d; var mu_i = eta * t.w_ij; if (mu_i > 1) { mu_i = 1; } var mu_j = eta * t.w_ji; if (mu_j > 1) { mu_j = 1; } var dx = X[i][0] - X[j][0]; var dy = X[i][1] - X[j][1]; var dz = X[i][2] - X[j][2]; var mag = Math.sqrt(dx * dx + dy * dy + dz * dz); var r = (mag - d_ij) / (2 * mag); var r_x = r * dx; var r_y = r * dy; var r_z = r * dz; X[i][0] -= mu_i * r_x; X[i][1] -= mu_i * r_y; X[i][2] -= mu_i * r_z; X[j][0] += mu_j * r_x; X[j][1] += mu_j * r_y; X[j][2] += mu_j * r_z; } } }; SparseMDSSGD.fisheryates_shuffle = function (terms) { var n = terms.length; for (var i = n - 1; i >= 1; i--) { var j = SparseMDSSGD.random_int(0, i); var temp = terms[i]; terms[i] = terms[j]; terms[j] = temp; } }; SparseMDSSGD.random_int = function (min, max) { return Math.floor(Math.random() * (max - min + 1) + min); }; SparseMDSSGD.schedule = function (terms, t_max, eps) { var w_min = Number.MAX_VALUE; var w_max = Number.MIN_VALUE; for (var i = 0; i < terms.length; i++) { var term = terms[i]; if (term.w_ij < w_min && term.w_ij !== 0) { w_min = term.w_ij; } if (term.w_ji < w_min && term.w_ji !== 0) { w_min = term.w_ji; } if (term.w_ij > w_max) { w_max = term.w_ij; } if (term.w_ji > w_max) { w_max = term.w_ji; } } var eta_max = 1.0 / w_min; var eta_min = eps / w_max; var lambda = Math.log(eta_max / eta_min) / (t_max - 1); var etas = new Array(); for (var t = 0; t < t_max; t++) { etas.push(eta_max * Math.exp(-lambda * t)); } console.debug("Etas: " + etas); return etas; }; SparseMDSSGD.MSSP_weighted = function (graph, closest_pivots) { var n = graph.length; var regions = new Map(); var termsDict = new Map(); for (var i = 0; i < n; i++) { if (!regions.has(closest_pivots[i])) { regions.set(closest_pivots[i], new Set()); } regions.get(closest_pivots[i]).add(i); } for (var i = 0; i < n; i++) { for (var i_edge = 0; i_edge < graph[i].length; i_edge++) { var e = graph[i][i_edge]; var j = e.target; var d_ij = e.weight; if (i < j) { if (!termsDict.has(i)) { termsDict.set(i, new Map()); } if (!termsDict.get(i).has(j)) { termsDict.get(i).set(j, new SparseTerm_1.default(i, j, d_ij)); } else { termsDict.get(i).get(j).d = d_ij; } if (d_ij === 5000) { termsDict.get(i).get(j).w_ij = termsDict.get(i).get(j).w_ji = 5000; } else { termsDict.get(i).get(j).w_ij = termsDict.get(i).get(j).w_ji = 1 / (d_ij * d_ij); } } } } var terms = new Array(); termsDict.forEach(function (i_terms) { i_terms.forEach(function (term) { terms.push(term); }); }); return terms; }; SparseMDSSGD.maxmin_random_sp_weighted = function (graph, n_pivots, p0, seed) { var n = graph.length; var mins = new Array(n).fill(Number.MAX_VALUE); var argmins = new Array(n).fill(-1); mins[p0] = 0; argmins[p0] = p0; SparseMDSSGD.maxmin_bfs_weighted(graph, p0, mins, argmins); for (var i = 0; i < n; i++) { if (argmins[i] === -1) { throw new Error("graph has multiple connected components"); } } for (var i = 1; i < n_pivots; i++) { var min_total = 0; for (var j = 0; j < n; j++) { min_total += mins[j]; } var sample = Math.random() * min_total; var cumul = 0; var argmax = -1; for (var j = 0; j < n; j++) { cumul += mins[j]; if (cumul >= sample) { argmax = j; break; } } if (argmax === -1) { throw new Error("weighted pivot sampling failed"); } mins[argmax] = 0; argmins[argmax] = argmax; SparseMDSSGD.maxmin_bfs_weighted(graph, argmax, mins, argmins); } return argmins; }; SparseMDSSGD.maxmin_bfs_weighted = function (graph, p, mins, argmins) { var n = graph.length; var visited = new Array(n).fill(false); var d = new Array(n).fill(Number.MAX_VALUE); var pq = new fibonacci_heap_1.FibonacciHeap(function (a, b) { return a.key.weight > b.key.weight ? 1 : a.key.weight < b.key.weight ? -1 : 0; }); d[p] = 0; pq.insert(new Edge_1.default(p, 0)); while (!pq.isEmpty()) { var current = pq.findMinimum().key.target; var d_pi = pq.findMinimum().key.weight; pq.extractMinimum(); if (!visited[current]) { visited[current] = true; if (d_pi < mins[current]) { mins[current] = d_pi; argmins[current] = p; } for (var i_edge = 0; i_edge < graph[current].length; i_edge++) { var e = graph[current][i_edge]; var next = e.target; var weight = e.weight; if (d_pi + weight < d[next]) { d[next] = d_pi + weight; pq.insert(new Edge_1.default(next, d[next])); } } } } }; SparseMDSSGD.buildGraphWeighted = function (n, m, I, J, V) { var undirected = new Array(n); var graph = new Array(n); for (var ij = 0; ij < m; ij++) { var i = I[ij], j = J[ij]; if (i >= n || j >= n) { throw new Error("i or j bigger than n"); } var v = V[ij]; if (v <= 0) { throw new Error("edge length less than or equal to 0"); } if (!undirected[i]) { undirected[i] = new Map(); } if (!undirected[j]) { undirected[j] = new Map(); } if (!graph[i]) { graph[i] = new Array(); } if (!graph[j]) { graph[j] = new Array(); } if (i !== j && !undirected[j].has(i)) { undirected[i].set(j, v); undirected[j].set(i, v); graph[i].push(new Edge_1.default(j, v)); graph[j].push(new Edge_1.default(i, v)); } else { if (undirected[j].get(i) !== v) { throw new Error("graph edge lengths not symmetric"); } } } return graph; }; return SparseMDSSGD; }()); exports.SparseMDSSGD = SparseMDSSGD; //# sourceMappingURL=SparseMDSSGD.js.map