From 5b75f5b588097bac6b3cc22d23b874adfc52ad12 Mon Sep 17 00:00:00 2001 From: brian Date: Fri, 16 Mar 2018 10:16:45 +0700 Subject: [PATCH] Remove stress function import in hybrid object --- src/neighbourSampling.js | 410 +++++++++++++++++++-------------------- 1 file changed, 204 insertions(+), 206 deletions(-) diff --git a/src/neighbourSampling.js b/src/neighbourSampling.js index 186a2f7..9914cc2 100644 --- a/src/neighbourSampling.js +++ b/src/neighbourSampling.js @@ -1,206 +1,204 @@ -import constant from "./constant"; -import jiggle from "./jiggle"; -import {getStress} from "./stress"; - -/** - * An implementation of Chalmers' 1996 Neighbour and Sampling algorithm. - * It uses random sampling to find the most suited neighbours from the - * data set. - */ - -function sortDistances(a, b) { - return b[1] - a[1]; -} - -export default function () { - var neighbours = [], - distance = constant(300), - nodes, - neighbourSize = 10, - sampleSize = 10, - stableVelocity = 0, - stableVeloHandler = null, - dataSizeFactor, - latestVelocityDiff = 0; - - /** - * Apply spring forces at each simulation iteration. - * @param {number} alpha - multiplier for amount of force applied - */ - function force(alpha) { - let n = nodes.length; - // Cache old velocity for comparison later - if (stableVeloHandler!==null && stableVelocity>=0) { - for (let i = n-1, node; i>=0; i--) { - node = nodes[i]; - node.oldvx = node.vx; - node.oldvy = node.vy; - } - } - - for (let i = n-1, node, samples; i>=0; i--) { - node = nodes[i]; - samples = createRandomSamples(i); - - for (let [neighbourID, highDDist] of neighbours[i]) { - setVelocity(node, nodes[neighbourID], highDDist, alpha); - } - - for (let [sampleID, highDDist] of samples) { - setVelocity(node, nodes[sampleID], highDDist, alpha); - } - - neighbours[i] = findNewNeighbours(neighbours[i], samples); - } - - // Calculate velocity changes, aka force applied. - if (stableVeloHandler!==null && stableVelocity>=0) { - let velocityDiff = 0; - for (let i = n-1, node; i>=0; i--) { - node = nodes[i]; - velocityDiff += Math.abs(Math.hypot(node.vx-node.oldvx, node.vy-node.oldvy)); - } - velocityDiff /= n; - latestVelocityDiff = velocityDiff; - - if(velocityDiff=0; i--) { - let neighbs = pickRandomNodesFor(i, [i], neighbourSize); - // Sort the neighbour set by the distances. - neighbours[i] = new Map(neighbs.sort(sortDistances)); - } - - initDataSizeFactor(); - } - - function initDataSizeFactor(){ - dataSizeFactor = 0.5/(neighbourSize+sampleSize); - } - - /** - * Generates an array of array[index, high-d distance to the node of index] - * where all indices are different and the size is as specified unless - * impossible (may be due to too large size requested) - * @param {number} index - index of a node to calculate distance against - * @param {array} exclude - indices of the nodes to ignore. - * @param {number} size - max number of elements in the map to return. - * @return {array} - */ - function pickRandomNodesFor(index, exclude, size) { - let randElements = []; - let max = nodes.length; - - for (let i = 0; i < size; i++) { - // Stop when no new elements can be found. - if (randElements.length + exclude.length >= nodes.length) { - break; - } - - let rand = Math.floor((Math.random() * max)); - // Re-random until suitable value is found. - while (randElements.includes(rand) || exclude.includes(rand)) { - rand = Math.floor((Math.random() * max)); - } - randElements.push(rand); - } - for(let i=randElements.length-1, rand; i>=0; i--){ - rand = randElements[i]; - randElements[i] = [rand, distance(nodes[index], nodes[rand])]; - } - return randElements; - } - - /** - * Generates a map {index: high-dimensional distance to the node of index} - * to be used as samples set for the node of the specified index. - * @param {number} index - index of the node to generate sample for - * @return {map} - */ - function createRandomSamples(index) { - // Ignore the current neighbours of the node and itself. - let exclude = [index]; - exclude = exclude.concat(Array.from(neighbours[index].keys())); - return new Map(pickRandomNodesFor(index, exclude, sampleSize)); - } - - /** - * Compares the elements from sample set to the neighbour set and replaces the - * elements in the neighbour set if any better neighbours are found. - * @param {map} neighbours - map of neighbours - * @param {map} samples - map of samples - * @return {map} - new map of neighbours - */ - function findNewNeighbours(neighbours, samples) { - let combined = [...neighbours.entries()].concat([...samples.entries()]); - combined = combined.sort(sortDistances); - return new Map(combined.slice(0, neighbourSize)); - } - - - // API for initializing the algorithm and setting parameters - force.initialize = function (_) { - nodes = _; - initialize(); - }; - - force.neighbourSize = function (_) { - return arguments.length ? (neighbourSize = +_, initialize(), force) : neighbourSize; - }; - - force.neighbours = function () { - return neighbours; - }; - - force.sampleSize = function (_) { - return arguments.length ? (sampleSize = +_, initDataSizeFactor(), force) : sampleSize; - }; - - force.distance = function (_) { - return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), force) : distance; - }; - - force.latestAccel = function () { - return latestVelocityDiff; - }; - - force.onStableVelo = function (_) { - return arguments.length ? (stableVeloHandler = _, force) : stableVeloHandler; - }; - - force.stableVelocity = function (_) { - return arguments.length ? (stableVelocity = _, force) : stableVelocity; - }; - return force; -} +import constant from "./constant"; +import jiggle from "./jiggle"; +/** + * An implementation of Chalmers' 1996 Neighbour and Sampling algorithm. + * It uses random sampling to find the most suited neighbours from the + * data set. + */ + +function sortDistances(a, b) { + return b[1] - a[1]; +} + +export default function () { + var neighbours = [], + distance = constant(300), + nodes, + neighbourSize = 10, + sampleSize = 10, + stableVelocity = 0, + stableVeloHandler = null, + dataSizeFactor, + latestVelocityDiff = 0; + + /** + * Apply spring forces at each simulation iteration. + * @param {number} alpha - multiplier for amount of force applied + */ + function force(alpha) { + let n = nodes.length; + // Cache old velocity for comparison later + if (stableVeloHandler!==null && stableVelocity>=0) { + for (let i = n-1, node; i>=0; i--) { + node = nodes[i]; + node.oldvx = node.vx; + node.oldvy = node.vy; + } + } + + for (let i = n-1, node, samples; i>=0; i--) { + node = nodes[i]; + samples = createRandomSamples(i); + + for (let [neighbourID, highDDist] of neighbours[i]) { + setVelocity(node, nodes[neighbourID], highDDist, alpha); + } + + for (let [sampleID, highDDist] of samples) { + setVelocity(node, nodes[sampleID], highDDist, alpha); + } + + neighbours[i] = findNewNeighbours(neighbours[i], samples); + } + + // Calculate velocity changes, aka force applied. + if (stableVeloHandler!==null && stableVelocity>=0) { + let velocityDiff = 0; + for (let i = n-1, node; i>=0; i--) { + node = nodes[i]; + velocityDiff += Math.abs(Math.hypot(node.vx-node.oldvx, node.vy-node.oldvy)); + } + velocityDiff /= n; + latestVelocityDiff = velocityDiff; + + if(velocityDiff=0; i--) { + let neighbs = pickRandomNodesFor(i, [i], neighbourSize); + // Sort the neighbour set by the distances. + neighbours[i] = new Map(neighbs.sort(sortDistances)); + } + + initDataSizeFactor(); + } + + function initDataSizeFactor(){ + dataSizeFactor = 0.5/(neighbourSize+sampleSize); + } + + /** + * Generates an array of array[index, high-d distance to the node of index] + * where all indices are different and the size is as specified unless + * impossible (may be due to too large size requested) + * @param {number} index - index of a node to calculate distance against + * @param {array} exclude - indices of the nodes to ignore. + * @param {number} size - max number of elements in the map to return. + * @return {array} + */ + function pickRandomNodesFor(index, exclude, size) { + let randElements = []; + let max = nodes.length; + + for (let i = 0; i < size; i++) { + // Stop when no new elements can be found. + if (randElements.length + exclude.length >= nodes.length) { + break; + } + + let rand = Math.floor((Math.random() * max)); + // Re-random until suitable value is found. + while (randElements.includes(rand) || exclude.includes(rand)) { + rand = Math.floor((Math.random() * max)); + } + randElements.push(rand); + } + for(let i=randElements.length-1, rand; i>=0; i--){ + rand = randElements[i]; + randElements[i] = [rand, distance(nodes[index], nodes[rand])]; + } + return randElements; + } + + /** + * Generates a map {index: high-dimensional distance to the node of index} + * to be used as samples set for the node of the specified index. + * @param {number} index - index of the node to generate sample for + * @return {map} + */ + function createRandomSamples(index) { + // Ignore the current neighbours of the node and itself. + let exclude = [index]; + exclude = exclude.concat(Array.from(neighbours[index].keys())); + return new Map(pickRandomNodesFor(index, exclude, sampleSize)); + } + + /** + * Compares the elements from sample set to the neighbour set and replaces the + * elements in the neighbour set if any better neighbours are found. + * @param {map} neighbours - map of neighbours + * @param {map} samples - map of samples + * @return {map} - new map of neighbours + */ + function findNewNeighbours(neighbours, samples) { + let combined = [...neighbours.entries()].concat([...samples.entries()]); + combined = combined.sort(sortDistances); + return new Map(combined.slice(0, neighbourSize)); + } + + + // API for initializing the algorithm and setting parameters + force.initialize = function (_) { + nodes = _; + initialize(); + }; + + force.neighbourSize = function (_) { + return arguments.length ? (neighbourSize = +_, initialize(), force) : neighbourSize; + }; + + force.neighbours = function () { + return neighbours; + }; + + force.sampleSize = function (_) { + return arguments.length ? (sampleSize = +_, initDataSizeFactor(), force) : sampleSize; + }; + + force.distance = function (_) { + return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), force) : distance; + }; + + force.latestAccel = function () { + return latestVelocityDiff; + }; + + force.onStableVelo = function (_) { + return arguments.length ? (stableVeloHandler = _, force) : stableVeloHandler; + }; + + force.stableVelocity = function (_) { + return arguments.length ? (stableVelocity = _, force) : stableVelocity; + }; + return force; +}