Revamp neighbor sampling, shredding unused features and correct calculations
This commit is contained in:
@@ -157,12 +157,6 @@
|
|||||||
<input type="range" min="1" max="100" value="3" step="1" oninput="d3.select('#hlsampleSizeSliderOutput').text(value); SAMPLE_SIZE=value;">
|
<input type="range" min="1" max="100" value="3" step="1" oninput="d3.select('#hlsampleSizeSliderOutput').text(value); SAMPLE_SIZE=value;">
|
||||||
</label>
|
</label>
|
||||||
<br/>
|
<br/>
|
||||||
<label title="DistanceRange">
|
|
||||||
Subset: Distance Range
|
|
||||||
<output id="hldistanceRangeSliderOutput">10</output><br/>
|
|
||||||
<input type="range" min="1" max="100" value="10" step="1" oninput="d3.select('#hldistanceRangeSliderOutput').text(value); SELECTED_DISTANCE=value;">
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
<label title="Number of iterations done at the end">
|
<label title="Number of iterations done at the end">
|
||||||
Full: Iterations
|
Full: Iterations
|
||||||
<output id="fullIterationsSliderOutput">20</output><br/>
|
<output id="fullIterationsSliderOutput">20</output><br/>
|
||||||
@@ -180,12 +174,6 @@
|
|||||||
<output id="hlFullsampleSizeSliderOutput">3</output><br/>
|
<output id="hlFullsampleSizeSliderOutput">3</output><br/>
|
||||||
<input type="range" min="1" max="100" value="3" step="1" oninput="d3.select('#hlFullsampleSizeSliderOutput').text(value); FULL_SAMPLE_SIZE=value;">
|
<input type="range" min="1" max="100" value="3" step="1" oninput="d3.select('#hlFullsampleSizeSliderOutput').text(value); FULL_SAMPLE_SIZE=value;">
|
||||||
</label>
|
</label>
|
||||||
<br/>
|
|
||||||
<label title="DistanceRange">
|
|
||||||
Full: Distance Range
|
|
||||||
<output id="hlFulldistanceRangeSliderOutput">10</output><br/>
|
|
||||||
<input type="range" min="1" max="100" value="10" step="1" oninput="d3.select('#hlFulldistanceRangeSliderOutput').text(value); FULL_SELECTED_DISTANCE=value;">
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input id="NSButton" type="radio" name="algorithm" onclick="d3.select('#startSimulation').on('click', startNeighbourSamplingSimulation)">Neighbour
|
<input id="NSButton" type="radio" name="algorithm" onclick="d3.select('#startSimulation').on('click', startNeighbourSamplingSimulation)">Neighbour
|
||||||
@@ -202,12 +190,6 @@
|
|||||||
<output id="sampleSizeSliderOutput">3</output><br/>
|
<output id="sampleSizeSliderOutput">3</output><br/>
|
||||||
<input type="range" min="1" max="100" value="3" step="1" oninput="d3.select('#sampleSizeSliderOutput').text(value); SAMPLE_SIZE=value;">
|
<input type="range" min="1" max="100" value="3" step="1" oninput="d3.select('#sampleSizeSliderOutput').text(value); SAMPLE_SIZE=value;">
|
||||||
</label>
|
</label>
|
||||||
<br/>
|
|
||||||
<label title="DistanceRange">
|
|
||||||
Distance Range
|
|
||||||
<output id="distanceRangeSliderOutput">10</output><br/>
|
|
||||||
<input type="range" min="1" max="100" value="10" step="1" oninput="d3.select('#distanceRangeSliderOutput').text(value); SELECTED_DISTANCE=value;">
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<input class="noParameters" type="radio" name="algorithm" onclick="d3.select('#startSimulation').on('click', startLinkSimulation); tweakedVerOfLink=false;">Link force in D3<br>
|
<input class="noParameters" type="radio" name="algorithm" onclick="d3.select('#startSimulation').on('click', startLinkSimulation); tweakedVerOfLink=false;">Link force in D3<br>
|
||||||
<input class="noParameters" type="radio" name="algorithm" onclick="d3.select('#startSimulation').on('click', startLinkSimulation); tweakedVerOfLink=true; ">Link force (tweaked)<br>
|
<input class="noParameters" type="radio" name="algorithm" onclick="d3.select('#startSimulation').on('click', startLinkSimulation); tweakedVerOfLink=true; ">Link force (tweaked)<br>
|
||||||
|
|||||||
@@ -57,10 +57,8 @@ var MULTIPLIER = 50,
|
|||||||
FULL_ITERATIONS = 20,
|
FULL_ITERATIONS = 20,
|
||||||
NODE_SIZE = 10,
|
NODE_SIZE = 10,
|
||||||
COLOR_ATTRIBUTE = "",
|
COLOR_ATTRIBUTE = "",
|
||||||
SELECTED_DISTANCE = 10,
|
|
||||||
FULL_NEIGHBOUR_SIZE = 6,
|
FULL_NEIGHBOUR_SIZE = 6,
|
||||||
FULL_SAMPLE_SIZE = 3,
|
FULL_SAMPLE_SIZE = 3;
|
||||||
FULL_SELECTED_DISTANCE = 10;
|
|
||||||
|
|
||||||
// Create a color scheme for a range of numbers.
|
// Create a color scheme for a range of numbers.
|
||||||
var color = d3.scaleOrdinal(d3.schemeCategory10);
|
var color = d3.scaleOrdinal(d3.schemeCategory10);
|
||||||
@@ -205,12 +203,12 @@ function ticked() {
|
|||||||
intercom.emit("passedData", simulation.force(forceName).distributionData());
|
intercom.emit("passedData", simulation.force(forceName).distributionData());
|
||||||
}
|
}
|
||||||
if(alreadyRanIterations == ITERATIONS) {
|
if(alreadyRanIterations == ITERATIONS) {
|
||||||
simulation.stop();
|
|
||||||
ended();
|
ended();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ended() {
|
function ended() {
|
||||||
|
simulation.stop();
|
||||||
console.log("ended");
|
console.log("ended");
|
||||||
if (rendering !== true) { // Never drawn anything before? Now it's time.
|
if (rendering !== true) { // Never drawn anything before? Now it's time.
|
||||||
node
|
node
|
||||||
|
|||||||
@@ -4,25 +4,24 @@
|
|||||||
function startNeighbourSamplingSimulation() {
|
function startNeighbourSamplingSimulation() {
|
||||||
console.log("startNeighbourSamplingSimulation");
|
console.log("startNeighbourSamplingSimulation");
|
||||||
//springForce = true;
|
//springForce = true;
|
||||||
|
alreadyRanIterations = 0;
|
||||||
simulation.stop();
|
simulation.stop();
|
||||||
p1 = performance.now();
|
p1 = performance.now();
|
||||||
|
|
||||||
simulation
|
let force = d3.forceNeighbourSamplingDistance()
|
||||||
.alphaDecay(1 - Math.pow(0.001, 1 / ITERATIONS))
|
|
||||||
.force(forceName, d3.forceNeighbourSamplingDistance()
|
|
||||||
// Set the parameters for the algorithm (optional).
|
|
||||||
.neighbourSize(NEIGHBOUR_SIZE)
|
.neighbourSize(NEIGHBOUR_SIZE)
|
||||||
.sampleSize(SAMPLE_SIZE)
|
.sampleSize(SAMPLE_SIZE)
|
||||||
// .freeness(0.5)
|
|
||||||
// The distance function that will be used to calculate distances
|
|
||||||
// between nodes.
|
|
||||||
.distance(function (s, t) {
|
.distance(function (s, t) {
|
||||||
return distanceFunction(s, t, props, norm);
|
return distanceFunction(s, t, props, norm);
|
||||||
})
|
})
|
||||||
.stableVelocity(0.004)
|
.stableVelocity(0.000001)
|
||||||
.stableVeloHandler( function(){simulation.stop(); ended();} )
|
.stableVeloHandler(ended);
|
||||||
);
|
|
||||||
|
simulation
|
||||||
|
.alphaDecay(0)
|
||||||
|
.alpha(1)
|
||||||
|
.force(forceName, force);
|
||||||
// Restart the simulation.
|
// Restart the simulation.
|
||||||
console.log(simulation.force(forceName).neighbourSize(), simulation.force(forceName).sampleSize());
|
console.log(simulation.force(forceName).neighbourSize(), simulation.force(forceName).sampleSize());
|
||||||
simulation.alpha(1).restart();
|
simulation.restart();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,240 +2,171 @@ import constant from "./constant";
|
|||||||
import jiggle from "./jiggle";
|
import jiggle from "./jiggle";
|
||||||
import {getStress} from "./stress";
|
import {getStress} from "./stress";
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the node id accessor to the specified i.
|
|
||||||
* @param {node} d - node.
|
|
||||||
* @param {accessor} i - id accessor.
|
|
||||||
* @return {accessor} - node id accessor.
|
|
||||||
*/
|
|
||||||
function index(d, i) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The implementation of Chalmers' 1996 Neighbour and Sampling algorithm.
|
* The implementation of Chalmers' 1996 Neighbour and Sampling algorithm.
|
||||||
* It uses random sampling to find the most suited neighbours from the
|
* It uses random sampling to find the most suited neighbours from the
|
||||||
* data set.
|
* data set.
|
||||||
* @return {force} calculated forces.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
function sortDistances(a, b) {
|
||||||
|
return b[1] - a[1];
|
||||||
|
}
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
var id = index,
|
var neighbours = [],
|
||||||
neighbours = [],
|
|
||||||
samples = new Array(),
|
|
||||||
distance = constant(300),
|
distance = constant(300),
|
||||||
nodes,
|
nodes,
|
||||||
neighbourSize = 6,
|
neighbourSize = 6,
|
||||||
sampleSize = 3,
|
sampleSize = 3,
|
||||||
//freeness = 0.85,
|
|
||||||
//springForce = 0.7,
|
|
||||||
//dampingFactor = 0.3,
|
|
||||||
velocity,
|
|
||||||
stableVelocity = 0,
|
stableVelocity = 0,
|
||||||
stableVeloHandler = null;
|
stableVeloHandler = null,
|
||||||
|
dataSizeFactor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the forces at each iteration between the node and the
|
* Apply spring forces at each iteration.
|
||||||
* objects in neighbour and sample sets.
|
* @param {number} alpha - multiplier for amount of force applied
|
||||||
* @param {number} alpha - controls the stopping of the
|
|
||||||
* particle simulations.
|
|
||||||
*/
|
*/
|
||||||
function force(alpha) {
|
function force(alpha) {
|
||||||
let velocityDiff = 0;
|
let n = nodes.length;
|
||||||
for (let node of nodes) {
|
// 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.oldvx = node.vx;
|
||||||
node.oldvy = node.vy;
|
node.oldvy = node.vy;
|
||||||
}
|
}
|
||||||
for (let i = 0, n = nodes.length; i < n; ++i) {
|
|
||||||
// Randomize the samples for every node.
|
|
||||||
samples[i] = randomizeSample(i);
|
|
||||||
// Calculate the forces between node and its neighbours.
|
|
||||||
for (let [keyN, valueN] of neighbours[i]) {
|
|
||||||
setVelocity(i, keyN, valueN, alpha);
|
|
||||||
}
|
}
|
||||||
// Calculate the forces between node and its sample set.
|
|
||||||
for (let [keyS, valueS] of samples[i]) {
|
for (let i = n-1, node, samples; i>=0; i--) {
|
||||||
setVelocity(i, keyS, valueS, alpha);
|
node = nodes[i];
|
||||||
|
samples = createRandomSamples(i);
|
||||||
|
|
||||||
|
for (let [neighbourID, highDDist] of neighbours[i]) {
|
||||||
|
setVelocity(node, nodes[neighbourID], highDDist, alpha);
|
||||||
}
|
}
|
||||||
// Check if there are a better neighbours in a sample array
|
|
||||||
// for each node.
|
for (let [sampleID, highDDist] of samples) {
|
||||||
findNewNeighbours(i);
|
setVelocity(node, nodes[sampleID], highDDist, alpha);
|
||||||
}
|
}
|
||||||
for (let node of nodes) {
|
// Replace neighbours with better ones found in the samples
|
||||||
velocityDiff += Math.abs(node.oldvx - node.vx) + Math.abs(node.oldvy - node.vy);
|
neighbours[i] = findNewNeighbours(neighbours[i], samples);
|
||||||
delete node.oldvx;
|
|
||||||
delete node.oldvy;
|
|
||||||
}
|
}
|
||||||
velocityDiff /= nodes.length*(neighbourSize+sampleSize);
|
|
||||||
// Now total velocity changes per link, alpha considered
|
// Calculate velocity changes, aka force applied.
|
||||||
// TODO per property too
|
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*(neighbourSize+sampleSize);
|
||||||
|
|
||||||
if(stableVeloHandler!==null && velocityDiff<stableVelocity){
|
if(stableVeloHandler!==null && velocityDiff<stableVelocity){
|
||||||
console.log("Neighbour sampling is now", velocityDiff, ", calling stableVeloHandler().")
|
console.log("Neighbour sampling is now", velocityDiff, ", calling stableVeloHandler().")
|
||||||
stableVeloHandler();
|
stableVeloHandler();
|
||||||
}
|
}
|
||||||
else console.log(velocityDiff);
|
else console.log(velocityDiff);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the velocities of the source and target nodes.
|
* Apply force to both source and target nodes.
|
||||||
* @param {number} sourceId - source node id.
|
* @param {number} source - source node object
|
||||||
* @param {number} targetId - target node id.
|
* @param {number} target - target node object
|
||||||
* @param {number} dist - high dimensional distance between
|
* @param {number} dist - high dimensional distance between the two nodes
|
||||||
* the two nodes.
|
* @param {number} alpha - multiplier for the amount of force applied
|
||||||
* @param {number} alpha - controls the speed of simulation.
|
|
||||||
*/
|
*/
|
||||||
function setVelocity(sourceId, targetId, dist, alpha) {
|
function setVelocity(source, target, dist, alpha) {
|
||||||
let source, target, x, y, l;
|
let x, y, l;
|
||||||
source = nodes[sourceId], target = nodes[targetId];
|
// jiggle so it wont divide / multiply by zero after this
|
||||||
// If x or y coordinates not defined, add some randomness.
|
|
||||||
x = target.x + target.vx - source.x - source.vx || jiggle();
|
x = target.x + target.vx - source.x - source.vx || jiggle();
|
||||||
y = target.y + target.vy - source.y - source.vy || jiggle();
|
y = target.y + target.vy - source.y - source.vy || jiggle();
|
||||||
l = Math.sqrt(x * x + y * y);
|
l = Math.sqrt(x * x + y * y);
|
||||||
l = (l - dist) / l * alpha;
|
l = (l - dist) / l * dataSizeFactor * alpha;
|
||||||
x *= l, y *= l;
|
x *= l, y *= l;
|
||||||
// Set the calculated velocites for both nodes.
|
// Set the calculated velocites for both nodes.
|
||||||
target.vx -= x*0.5;
|
target.vx -= x;
|
||||||
target.vy -= y*0.5;
|
target.vy -= y;
|
||||||
source.vx += x*0.5;
|
source.vx += x;
|
||||||
source.vy += y*0.5;
|
source.vy += y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the neighbour and sample set at the start.
|
|
||||||
*/
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
if (!nodes) return;
|
if (!nodes) return;
|
||||||
|
|
||||||
// Initialize for each node a neighbour and sample arrays
|
// Initialize for each node some random neighbours.
|
||||||
// with random values.
|
for (let i = nodes.length-1; i>=0; i--) {
|
||||||
for (let i = 0, n = nodes.length; i < n; ++i) {
|
let neighbs = pickRandomNodesFor(i, [i], neighbourSize);
|
||||||
let exclude = []; // Array that keeps the indices of nodes to ignore.
|
|
||||||
exclude.push(i);
|
|
||||||
|
|
||||||
let neighbs = createRandomNeighbours(i, exclude, n, neighbourSize);
|
|
||||||
// Sort the neighbour set by the distances.
|
// Sort the neighbour set by the distances.
|
||||||
neighbs = new Map([...neighbs.entries()].sort(sortDistances));
|
neighbours[i] = new Map(neighbs.sort(sortDistances));
|
||||||
neighbours[i] = neighbs;
|
|
||||||
|
|
||||||
//exclude.concat(neighbs);
|
|
||||||
//samples[i] = createRandomSample(i, exclude, n, sampleSize);
|
|
||||||
//Samples will be created at the start of each it anyway.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initDataSizeFactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initDataSizeFactor(){
|
||||||
|
dataSizeFactor = 0.5/(neighbourSize+sampleSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that compares to map elements by its values.
|
* Generates an array of array[index, high-d distance to the node of index]
|
||||||
* @param {object} a
|
* where all indices are different and the size is as specified unless
|
||||||
* @param {object} b
|
* impossible (may be due to too large size requested)
|
||||||
* @return {number} - 0, if values are equal, positive number if b > a,
|
* @param {number} index - index of a node to calculate distance against
|
||||||
* negative otherwise.
|
|
||||||
*/
|
|
||||||
function sortDistances(a, b) {
|
|
||||||
return b[1] - a[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an array of random integers, all different, with maximum
|
|
||||||
* value max and with size elements. No elements from exlucde should
|
|
||||||
* be included.
|
|
||||||
* @param {number} index - index of current node.
|
|
||||||
* @param {array} exclude - indices of the nodes to ignore.
|
* @param {array} exclude - indices of the nodes to ignore.
|
||||||
* @param {number} max - maximum value.
|
* @param {number} size - max number of elements in the map to return.
|
||||||
* @param {number} size - the number of elements in map to return.
|
* @return {array}
|
||||||
* @return {map} - a created map that contains random elements from
|
|
||||||
* data set.
|
|
||||||
*/
|
*/
|
||||||
function createRandomNeighbours(index, exclude, max, size) {
|
function pickRandomNodesFor(index, exclude, size) {
|
||||||
let randElements = new Map();
|
let randElements = [];
|
||||||
let triedElements = 0;
|
let max = nodes.length;
|
||||||
|
|
||||||
while ((randElements.size < size) && (randElements.size + exclude.length + triedElements < nodes.length)) {
|
for (let i = 0; i < size; i++) {
|
||||||
let rand = Math.floor((Math.random() * max));
|
|
||||||
// If the rand is already in random list or in exclude list
|
|
||||||
// ignore it and get a new value.
|
|
||||||
while (randElements.has(rand) || exclude.includes(rand)) {
|
|
||||||
rand = Math.floor((Math.random() * max));
|
|
||||||
}
|
|
||||||
let dist = +distance(nodes[index], nodes[rand]);
|
|
||||||
randElements.set(rand, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
return randElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function createRandomSample(index, exclude, max, size) {
|
|
||||||
let randElements = new Map();
|
|
||||||
|
|
||||||
for (let i = 0; i < size; ++i) {
|
|
||||||
// Stop when no new elements can be found.
|
// Stop when no new elements can be found.
|
||||||
if (randElements.size + exclude.length >= nodes.length) {
|
if (randElements.length + exclude.length >= nodes.length) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rand = Math.floor((Math.random() * max));
|
let rand = Math.floor((Math.random() * max));
|
||||||
// If the rand is already in random list or in exclude list
|
// Re-random until suitable value is found.
|
||||||
// ignore it and get a new value.
|
while (randElements.includes(rand) || exclude.includes(rand)) {
|
||||||
while (randElements.has(rand) || exclude.includes(rand)) {
|
|
||||||
rand = Math.floor((Math.random() * max));
|
rand = Math.floor((Math.random() * max));
|
||||||
}
|
}
|
||||||
randElements.set(rand, +distance(nodes[index], nodes[rand]));
|
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;
|
return randElements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new map of random numbers to be used by the samples list.
|
* Generates a map {index: high-dimensional distance to the node of index}
|
||||||
* @param {number} index - index of current node.
|
* to be used as samples set for the node of the specified index.
|
||||||
* @return {map} - map that contains random elements from data set.
|
* @param {number} index - index of the node to generate sample for
|
||||||
|
* @return {map}
|
||||||
*/
|
*/
|
||||||
function randomizeSample(index) {
|
function createRandomSamples(index) {
|
||||||
// Ignore the current neighbours of the node and itself.
|
// Ignore the current neighbours of the node and itself.
|
||||||
let exclude = [index];
|
let exclude = [index];
|
||||||
exclude = exclude.concat(Array.from(neighbours[index].keys()));
|
exclude = exclude.concat(Array.from(neighbours[index].keys()));
|
||||||
return createRandomSample(index, exclude, nodes.length, sampleSize);
|
return new Map(pickRandomNodesFor(index, exclude, sampleSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares the elements from sample set to the neighbour set and
|
* Compares the elements from sample set to the neighbour set and replaces the
|
||||||
* replaces the elements from neighbour set if better neighbours are
|
* elements in the neighbour set if any better neighbours are found.
|
||||||
* found in sample set.
|
* @param {map} neighbours - map of neighbours
|
||||||
* @param {number} index - index of current node.
|
* @param {map} samples - map of samples
|
||||||
|
* @return {map} - new map of neighbours
|
||||||
*/
|
*/
|
||||||
function findNewNeighbours(index) {
|
function findNewNeighbours(neighbours, samples) {
|
||||||
let sample = samples[index];
|
let combined = [...neighbours.entries()].concat([...samples.entries()]);
|
||||||
|
combined = combined.sort(sortDistances);
|
||||||
if (neighbours[index].size > 0) {
|
return new Map(combined.slice(0, neighbourSize));
|
||||||
for (let [key, value] of sample) {
|
|
||||||
let neighbMax = neighbours[index].entries().next().value;
|
|
||||||
|
|
||||||
// Check if a value from sample could be a better neighbour
|
|
||||||
// if so, replace it.
|
|
||||||
if (value < neighbMax[1]) {
|
|
||||||
neighbours[index].delete(neighbMax[0]);
|
|
||||||
neighbours[index].set(key, value)
|
|
||||||
neighbours[index] = new Map([...neighbours[index].entries()].sort(sortDistances));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the average velocity of the force calculation at the
|
|
||||||
* current iteration.
|
|
||||||
* @return {number} - average velocity.
|
|
||||||
*/
|
|
||||||
function getAvgVelocity() {
|
|
||||||
return velocity / ((neighbourSize + sampleSize) * nodes.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function getDistributionData() {
|
|
||||||
let d = [];
|
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
|
||||||
d.push({ "index": i, "size": neighbours[i].size });
|
|
||||||
}
|
|
||||||
return { "maxSize": neighbourSize, "l": nodes.length, "distribution": d };
|
|
||||||
}
|
|
||||||
|
|
||||||
// API for initializing the algorithm, setting parameters and querying
|
// API for initializing the algorithm, setting parameters and querying
|
||||||
// metrics.
|
// metrics.
|
||||||
@@ -244,42 +175,22 @@ export default function () {
|
|||||||
initialize();
|
initialize();
|
||||||
};
|
};
|
||||||
|
|
||||||
force.id = function (_) {
|
|
||||||
return arguments.length ? (id = _, force) : id;
|
|
||||||
};
|
|
||||||
|
|
||||||
force.neighbourSize = function (_) {
|
force.neighbourSize = function (_) {
|
||||||
return arguments.length ? (neighbourSize = +_, force) : neighbourSize;
|
return arguments.length ? (neighbourSize = +_, initDataSizeFactor(), force) : neighbourSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
force.sampleSize = function (_) {
|
force.sampleSize = function (_) {
|
||||||
return arguments.length ? (sampleSize = +_, force) : sampleSize;
|
return arguments.length ? (sampleSize = +_, initDataSizeFactor(), force) : sampleSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
force.distance = function (_) {
|
force.distance = function (_) {
|
||||||
return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), force) : distance;
|
return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), force) : distance;
|
||||||
};
|
};
|
||||||
|
|
||||||
force.stress = function () {
|
|
||||||
return getStress(nodes, distance);
|
|
||||||
};
|
|
||||||
|
|
||||||
force.velocity = function () {
|
force.velocity = function () {
|
||||||
return getAvgVelocity();
|
return getAvgVelocity();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*force.freeness = function (_) {
|
|
||||||
return arguments.length ? (freeness = +_, force) : freeness;
|
|
||||||
};*/
|
|
||||||
|
|
||||||
force.nodeNeighbours = function (_) {
|
|
||||||
return arguments.length ? neighbours[+_] : neighbours;
|
|
||||||
};
|
|
||||||
|
|
||||||
force.distributionData = function () {
|
|
||||||
return getDistributionData();
|
|
||||||
};
|
|
||||||
|
|
||||||
force.stableVeloHandler = function (_) {
|
force.stableVeloHandler = function (_) {
|
||||||
return arguments.length ? (stableVeloHandler = _, force) : stableVeloHandler;
|
return arguments.length ? (stableVeloHandler = _, force) : stableVeloHandler;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user