Refactor: Extract functions
This commit is contained in:
@@ -129,7 +129,7 @@
|
||||
<div class="left">
|
||||
<p>Select algorithm:</p>
|
||||
<div id="algorithms">
|
||||
<input id="HLButton" type="radio" name="algorithm" onclick="d3.select('#startSimulation').on('click', startHybridSimulation)">Hybrid
|
||||
<input id="HLButton" type="radio" name="algorithm" checked onclick="d3.select('#startSimulation').on('click', startHybridSimulation)">Hybrid
|
||||
layout
|
||||
<br>
|
||||
<div id="HLParameters" class="parameters" style="display:none">
|
||||
@@ -232,7 +232,7 @@
|
||||
<div class="left">
|
||||
<p>Select distance function:</p>
|
||||
<div id="distance">
|
||||
<input type="radio" name="distance" onclick="distanceFunction=calculateDistance"> General<br>
|
||||
<input type="radio" name="distance" checked onclick="distanceFunction=calculateDistance"> General<br>
|
||||
<input type="radio" name="distance" onclick="distanceFunction=calculateEuclideanDistance"> Euclidean<br>
|
||||
<input type="radio" name="distance" onclick="distanceFunction=calculateManhattanDistance"> Manhattan<br>
|
||||
<input type="radio" name="distance" onclick="distanceFunction=calculateJaccardDissimilarity"> Jaccard<br>
|
||||
@@ -252,6 +252,9 @@
|
||||
<script src="js/lib/intercom.js"></script>
|
||||
<script src="../build/d3-neighbour-sampling.js"></script>
|
||||
<script src="js/src/neighbourSampling-papaparsing.js"></script>
|
||||
<script src="js/src/neighbourSampling-papaparsing/hybrid.js"></script>
|
||||
<script src="js/src/neighbourSampling-papaparsing/linkForce.js"></script>
|
||||
<script src="js/src/neighbourSampling-papaparsing/neighbourSampling.js"></script>
|
||||
<script src="js/distances/distancePokerHands.js"></script>
|
||||
<script src="js/distances/distance.js"></script>
|
||||
<script src="js/distances/euclideanDistance.js"></script>
|
||||
|
||||
43
examples/js/src/neighbourSampling-papaparsing/hybrid.js
Normal file
43
examples/js/src/neighbourSampling-papaparsing/hybrid.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Initialize the hybrid layout algorithm and start simulation.
|
||||
*/
|
||||
function startHybridSimulation() {
|
||||
console.log("startHybridSimulation");
|
||||
springForce = false;
|
||||
d3.selectAll(".nodes").remove();
|
||||
simulation.stop();
|
||||
p1 = performance.now();
|
||||
|
||||
configuration = {
|
||||
iteration: ITERATIONS,
|
||||
neighbourSize: NEIGHBOUR_SIZE,
|
||||
sampleSize: SAMPLE_SIZE,
|
||||
distanceRange: SELECTED_DISTANCE * MULTIPLIER,
|
||||
fullIterations: FULL_ITERATIONS,
|
||||
fullNeighbourSize: FULL_NEIGHBOUR_SIZE,
|
||||
fullSampleSize: FULL_SAMPLE_SIZE,
|
||||
fullDistanceRange: FULL_SELECTED_DISTANCE * MULTIPLIER,
|
||||
distanceFn: function (s, t) {return distanceFunction(s, t, props, norm) * MULTIPLIER;},
|
||||
pivots: PIVOTS,
|
||||
numPivots: NUM_PIVOTS
|
||||
};
|
||||
console.log(configuration);
|
||||
hybridSimulation = d3.hybridSimulation(nodes, configuration);
|
||||
|
||||
let sample = hybridSimulation.sample();
|
||||
let remainder = hybridSimulation.remainder();
|
||||
|
||||
addNodesToDOM(sample);
|
||||
|
||||
hybridSimulation
|
||||
.on("sampleTick", ticked)
|
||||
.on("fullTick", ticked)
|
||||
.on("startFull", startedFull)
|
||||
.on("end", ended);
|
||||
|
||||
function startedFull() {
|
||||
console.log("startedFull");
|
||||
d3.selectAll(".nodes").remove();
|
||||
addNodesToDOM(nodes);
|
||||
}
|
||||
}
|
||||
40
examples/js/src/neighbourSampling-papaparsing/linkForce.js
Normal file
40
examples/js/src/neighbourSampling-papaparsing/linkForce.js
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
/**
|
||||
* Initialize the link force algorithm and start simulation.
|
||||
*/
|
||||
function startLinkSimulation() {
|
||||
console.log("startLinkSimulation")
|
||||
springForce = false;
|
||||
simulation.stop();
|
||||
p1 = performance.now();
|
||||
let links = [];
|
||||
|
||||
// Initialize link array.
|
||||
nodes = simulation.nodes();
|
||||
for (i = 0; i < nodes.length; i++) {
|
||||
for (j = 0; j < nodes.length; j++) {
|
||||
if (i !== j) {
|
||||
links.push({
|
||||
source: nodes[i],
|
||||
target: nodes[j],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the links to the simulation.
|
||||
simulation.force(forceName, d3.forceLink().links(links));
|
||||
|
||||
simulation
|
||||
.alphaDecay(1 - Math.pow(0.001, 1 / ITERATIONS))
|
||||
.force(forceName)
|
||||
// The distance function that will be used to calculate distances
|
||||
// between nodes.
|
||||
.distance(function (n) {
|
||||
return distanceFunction(n.source, n.target, props, norm) * MULTIPLIER;
|
||||
})
|
||||
// Set the parameter for the algorithm (optional).
|
||||
.strength(1);
|
||||
// Restart the simulation.
|
||||
simulation.alpha(1).restart();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Initialize the Chalmers' 1996 algorithm and start simulation.
|
||||
*/
|
||||
function startNeighbourSamplingSimulation() {
|
||||
console.log("startNeighbourSamplingSimulation");
|
||||
springForce = true;
|
||||
simulation.stop();
|
||||
p1 = performance.now();
|
||||
|
||||
simulation
|
||||
.alphaDecay(1 - Math.pow(0.001, 1 / ITERATIONS))
|
||||
.force(forceName, d3.forceNeighbourSamplingDistance()
|
||||
// Set the parameters for the algorithm (optional).
|
||||
.neighbourSize(NEIGHBOUR_SIZE)
|
||||
.sampleSize(SAMPLE_SIZE)
|
||||
// .freeness(0.5)
|
||||
.distanceRange(SELECTED_DISTANCE * MULTIPLIER)
|
||||
// The distance function that will be used to calculate distances
|
||||
// between nodes.
|
||||
.distance(function (s, t) {
|
||||
return distanceFunction(s, t, props, norm) * MULTIPLIER;
|
||||
})
|
||||
.stableVelocity(1.2 * MULTIPLIER)
|
||||
.stableVeloHandler( function(){simulation.stop(); ended();} )
|
||||
);
|
||||
// Restart the simulation.
|
||||
console.log(simulation.force(forceName).neighbourSize(), simulation.force(forceName).sampleSize());
|
||||
simulation.alpha(1).restart();
|
||||
}
|
||||
43
examples/js/src/neighbourSampling-papaparsing/otherAlgo.js
Normal file
43
examples/js/src/neighbourSampling-papaparsing/otherAlgo.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Initialize the t-SNE algorithm and start simulation.
|
||||
*/
|
||||
function starttSNE() {
|
||||
springForce = false;
|
||||
simulation.stop();
|
||||
p1 = performance.now();
|
||||
|
||||
simulation
|
||||
.alphaDecay(1 - Math.pow(0.001, 1 / ITERATIONS))
|
||||
.force(forceName, d3.tSNE()
|
||||
// Set the parameter for the algorithm (optional).
|
||||
.perplexity(PERPLEXITY)
|
||||
.learningRate(LEARNING_RATE)
|
||||
// The distance function that will be used to calculate distances
|
||||
// between nodes.
|
||||
.distance(function (s, t) {
|
||||
return distanceFunction(s, t, props, norm) * MULTIPLIER;
|
||||
}));
|
||||
// Restart the simulation.
|
||||
console.log(simulation.force(forceName).perplexity(), simulation.force(forceName).learningRate());
|
||||
simulation.alpha(1).restart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Barnes-Hut algorithm and start simulation.
|
||||
*/
|
||||
function startBarnesHutSimulation() {
|
||||
springForce = false;
|
||||
simulation.stop();
|
||||
p1 = performance.now();
|
||||
|
||||
simulation
|
||||
.alphaDecay(1 - Math.pow(0.001, 1 / ITERATIONS))
|
||||
.force(forceName, d3.forceBarnesHut()
|
||||
// The distance function that will be used to calculate distances
|
||||
// between nodes.
|
||||
.distance(function (s, t) {
|
||||
return distanceFunction(s, t, props, norm) * MULTIPLIER;
|
||||
}));
|
||||
// Restart the simulation.
|
||||
simulation.alpha(1).restart();
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { dispatch } from "d3-dispatch";
|
||||
import constant from "./constant";
|
||||
import interpolation from "./interpolation";
|
||||
import interpolationPivots from "./interpolationPivots";
|
||||
import interpBruteForce from "./interpolation/interpBruteForce";
|
||||
import interpolationPivots from "./interpolation/interpolationPivots";
|
||||
import neighbourSamplingDistance from "./neighbourSamplingDistance";
|
||||
import { takeSampleFrom } from "./interpolation/helpers";
|
||||
|
||||
export default function (nodes, config) {
|
||||
|
||||
@@ -21,10 +22,9 @@ export default function (nodes, config) {
|
||||
NUMPIVOTS = config.hasOwnProperty("numPivots") ? config.numPivots : 3,
|
||||
event = d3.dispatch("sampleTick", "fullTick", "startFull", "end");
|
||||
|
||||
var sets = sampleFromNodes(nodes, Math.sqrt(nodes.length));
|
||||
var sets = takeSampleFrom(nodes, Math.sqrt(nodes.length));
|
||||
var sample = sets.sample;
|
||||
var remainder = sets.remainder;
|
||||
var sampleSubset = sampleFromNodes(sample, Math.sqrt(sample.length)).sample;
|
||||
|
||||
var sampleSimulation = d3.forceSimulation(sample)
|
||||
.stop()
|
||||
@@ -46,15 +46,19 @@ export default function (nodes, config) {
|
||||
.alpha(1).restart();
|
||||
|
||||
function ended() {
|
||||
sample.forEach(function (d) {
|
||||
d.vx = 0;
|
||||
d.vy = 0;
|
||||
});
|
||||
event.call("startFull");
|
||||
console.log("Ended sample simulation");
|
||||
alert('About to interpolate');
|
||||
interpolation(sample, remainder, sampleSubset, distanceFn);
|
||||
interpBruteForce(sample, remainder, distanceFn);
|
||||
/*
|
||||
if (PIVOTS) {
|
||||
interpolationPivots(sample, remainder, sampleSubSet, NUMPIVOTS, distance);
|
||||
} else {
|
||||
interpolation(sample, remainder, sampleSubSet, distance);
|
||||
interpBruteForce(sample, remainder, sampleSubSet, distance);
|
||||
}
|
||||
*/
|
||||
event.call("fullTick");
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
export default function(sampleSet, remainderSet, sampleSubset, distanceFn) {
|
||||
// var distance = calculateEuclideanDistance;
|
||||
// console.log("Brute-force");
|
||||
for (let node of remainderSet) {
|
||||
let nearestSample = undefined,
|
||||
minDist = undefined,
|
||||
sampleSubsetDistanceCache = [];
|
||||
|
||||
for (let sample of sampleSet) {
|
||||
let dist = distanceFn(node, sample);
|
||||
if (nearestSample === undefined || dist < minDist) {
|
||||
minDist = dist;
|
||||
nearestSample = sample;
|
||||
}
|
||||
|
||||
let index = sampleSubset.indexOf(sample);
|
||||
if (index !== -1) {
|
||||
sampleSubsetDistanceCache[index] = dist;
|
||||
}
|
||||
}
|
||||
|
||||
placeNearToNearestNeighbour(node, nearestSample, minDist, sampleSubset, sampleSubsetDistanceCache);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function placeNearToNearestNeighbour(node, minNode, radius, sampleSubset, realDistances) {
|
||||
let
|
||||
dist0 = sumDistError(pointOnCircle(minNode.x, minNode.y, 0, radius), sampleSubset, realDistances),
|
||||
dist90 = sumDistError(pointOnCircle(minNode.x, minNode.y, 90, radius), sampleSubset, realDistances),
|
||||
dist180 = sumDistError(pointOnCircle(minNode.x, minNode.y, 180, radius), sampleSubset, realDistances),
|
||||
dist270 = sumDistError(pointOnCircle(minNode.x, minNode.y, 270, radius), sampleSubset, realDistances),
|
||||
lowBound = 0.0,
|
||||
highBound = 0.0;
|
||||
|
||||
// Determine the closest quadrant
|
||||
if (dist0 == dist180) {
|
||||
if (dist90 > dist270)
|
||||
lowBound = highBound = 270;
|
||||
else
|
||||
lowBound = highBound = 90;
|
||||
} else if (dist90 == dist270) {
|
||||
if (dist0 > dist180)
|
||||
lowBound = highBound = 180;
|
||||
else
|
||||
lowBound = highBound = 0;
|
||||
} else if (dist0 > dist180) {
|
||||
if (dist90 > dist270) {
|
||||
lowBound = 180;
|
||||
highBound = 270;
|
||||
} else {
|
||||
lowBound = 90;
|
||||
highBound = 180;
|
||||
}
|
||||
} else {
|
||||
if (dist90 > dist270) {
|
||||
lowBound = 270;
|
||||
highBound = 360;
|
||||
} else {
|
||||
lowBound = 0;
|
||||
highBound = 90;
|
||||
}
|
||||
}
|
||||
|
||||
let angle = binarySearchMin(lowBound, highBound,
|
||||
function(angle){
|
||||
return sumDistError(pointOnCircle(minNode.x, minNode.y, angle, radius), sampleSubset, realDistances);
|
||||
});
|
||||
let newPoint = pointOnCircle(minNode.x, minNode.y, angle, radius);
|
||||
|
||||
// console.log(newPoint);
|
||||
node.x = newPoint.x;
|
||||
node.y = newPoint.y;
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
let forces = sumForcesToSample(node, sampleSubset, realDistances);
|
||||
// console.log(forces);
|
||||
node.x += forces.x*0.5;
|
||||
node.y += forces.y*0.5;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// With a circle radius r, and center at (h,k),
|
||||
// Find the coordinate of a point at angle degree
|
||||
function pointOnCircle(h, k, angle, r) {
|
||||
let x = h + r*Math.cos(toRadians(angle));
|
||||
let y = k + r*Math.sin(toRadians(angle));
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y: y
|
||||
};
|
||||
}
|
||||
|
||||
function toRadians(degrees) {
|
||||
return degrees * (Math.PI / 180);
|
||||
}
|
||||
|
||||
function sumDistError(currentPos, samples, realDistances) {
|
||||
let total = 0.0;
|
||||
for (let i = 0; i < samples.length; i++) {
|
||||
let sample = samples[i];
|
||||
let lowDDistance = Math.hypot(sample.x - currentPos.x, sample.y - currentPos.y);
|
||||
total += Math.abs(lowDDistance - realDistances[i]);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
function sumForcesToSample(node, samples, sampleCache) {
|
||||
let nodeVx = 0,
|
||||
nodeVy = 0;
|
||||
|
||||
for (let i = 0; i < samples.length; i++) {
|
||||
var sample = samples[i];
|
||||
if(sample === node) continue;
|
||||
|
||||
let x = node.x - sample.x,
|
||||
y = node.y - sample.y,
|
||||
l = Math.sqrt(x * x + y * y);
|
||||
|
||||
l = (l - sampleCache[i]) / l;
|
||||
x *= l, y *= l;
|
||||
nodeVx -= x;
|
||||
nodeVy -= y;
|
||||
}
|
||||
return {x: nodeVx, y: nodeVy};
|
||||
}
|
||||
|
||||
function binarySearchMin(lb, hb, fn) {
|
||||
while (lb <= hb) {
|
||||
if(lb === hb) return lb;
|
||||
if(hb-lb == 1) {
|
||||
if (fn(lb) >= fn(hb)) return hb;
|
||||
else return lb;
|
||||
}
|
||||
|
||||
let range = hb-lb;
|
||||
let valLowerHalf = fn(lb + range/4);
|
||||
let valHigherHalf = fn(lb + range*3/4);
|
||||
|
||||
if (valLowerHalf > valHigherHalf)
|
||||
lb = Math.floor((lb + hb) / 2);
|
||||
else if (valLowerHalf < valHigherHalf)
|
||||
hb = Math.ceil((lb + hb) / 2);
|
||||
else {
|
||||
lb += Math.floor(range/4);
|
||||
hb -= Math.ceil(range/4);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
48
src/interpolation/helpers.js
Normal file
48
src/interpolation/helpers.js
Normal file
@@ -0,0 +1,48 @@
|
||||
export function takeSampleFrom(nodes, amount) {
|
||||
let randElements = [],
|
||||
max = nodes.length;
|
||||
|
||||
for (var i = 0; i < amount; ++i) {
|
||||
var rand = nodes[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.includes(rand)) {
|
||||
rand = nodes[Math.floor((Math.random() * max))];
|
||||
}
|
||||
randElements.push(rand);
|
||||
}
|
||||
var remainder = nodes.filter(function (node) {
|
||||
return !randElements.includes(node);
|
||||
});
|
||||
|
||||
return {
|
||||
sample: randElements,
|
||||
remainder: remainder
|
||||
};
|
||||
}
|
||||
|
||||
// With a circle radius r, and center at (h,k),
|
||||
// Find the coordinate of a point at angle degree
|
||||
export function pointOnCircle(h, k, angle, r) {
|
||||
let x = h + r*Math.cos(toRadians(angle));
|
||||
let y = k + r*Math.sin(toRadians(angle));
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y: y
|
||||
};
|
||||
}
|
||||
|
||||
function toRadians(degrees) {
|
||||
return degrees * (Math.PI / 180);
|
||||
}
|
||||
|
||||
export function sumDistError(node, samples, realDistances) {
|
||||
let total = 0.0;
|
||||
for (let i = 0; i < samples.length; i++) {
|
||||
let sample = samples[i];
|
||||
let lowDDistance = Math.hypot(sample.x - node.x, sample.y - node.y);
|
||||
total += Math.abs(lowDDistance - realDistances[i]);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
27
src/interpolation/interpBruteForce.js
Normal file
27
src/interpolation/interpBruteForce.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { pointOnCircle, takeSampleFrom } from "./helpers";
|
||||
import { placeNearToNearestNeighbour } from "./interpCommon";
|
||||
|
||||
export default function(sampleSet, remainderSet, distanceFn) {
|
||||
// var distance = calculateEuclideanDistance;
|
||||
// console.log("Brute-force");
|
||||
let sampleSubset = takeSampleFrom(sampleSet, Math.sqrt(sampleSet.length)).sample;
|
||||
|
||||
for (let node of remainderSet) {
|
||||
let nearestSample = undefined,
|
||||
minDist = undefined,
|
||||
sampleSubsetDistanceCache = [];
|
||||
|
||||
for (let sample of sampleSet) {
|
||||
let dist = distanceFn(node, sample);
|
||||
if (nearestSample === undefined || dist < minDist) {
|
||||
minDist = dist;
|
||||
nearestSample = sample;
|
||||
}
|
||||
|
||||
let index = sampleSubset.indexOf(sample);
|
||||
if (index !== -1)
|
||||
sampleSubsetDistanceCache[index] = dist;
|
||||
}
|
||||
placeNearToNearestNeighbour(node, nearestSample, minDist, sampleSubset, sampleSubsetDistanceCache);
|
||||
}
|
||||
}
|
||||
102
src/interpolation/interpCommon.js
Normal file
102
src/interpolation/interpCommon.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import { pointOnCircle, sumDistError } from "./helpers";
|
||||
|
||||
export function placeNearToNearestNeighbour(node, nearNeighbour, radius, sampleSubset, realDistances) {
|
||||
let
|
||||
dist0 = sumDistError(pointOnCircle(nearNeighbour.x, nearNeighbour.y, 0, radius), sampleSubset, realDistances),
|
||||
dist90 = sumDistError(pointOnCircle(nearNeighbour.x, nearNeighbour.y, 90, radius), sampleSubset, realDistances),
|
||||
dist180 = sumDistError(pointOnCircle(nearNeighbour.x, nearNeighbour.y, 180, radius), sampleSubset, realDistances),
|
||||
dist270 = sumDistError(pointOnCircle(nearNeighbour.x, nearNeighbour.y, 270, radius), sampleSubset, realDistances),
|
||||
lowBound = 0.0,
|
||||
highBound = 0.0;
|
||||
|
||||
// Determine the closest quadrant
|
||||
if (dist0 == dist180) {
|
||||
if (dist90 > dist270)
|
||||
lowBound = highBound = 270;
|
||||
else
|
||||
lowBound = highBound = 90;
|
||||
} else if (dist90 == dist270) {
|
||||
if (dist0 > dist180)
|
||||
lowBound = highBound = 180;
|
||||
else
|
||||
lowBound = highBound = 0;
|
||||
} else if (dist0 > dist180) {
|
||||
if (dist90 > dist270) {
|
||||
lowBound = 180;
|
||||
highBound = 270;
|
||||
} else {
|
||||
lowBound = 90;
|
||||
highBound = 180;
|
||||
}
|
||||
} else {
|
||||
if (dist90 > dist270) {
|
||||
lowBound = 270;
|
||||
highBound = 360;
|
||||
} else {
|
||||
lowBound = 0;
|
||||
highBound = 90;
|
||||
}
|
||||
}
|
||||
|
||||
let angle = binarySearchMin(lowBound, highBound,
|
||||
function(angle){
|
||||
return sumDistError(pointOnCircle(nearNeighbour.x, nearNeighbour.y, angle, radius), sampleSubset, realDistances);
|
||||
});
|
||||
let newPoint = pointOnCircle(nearNeighbour.x, nearNeighbour.y, angle, radius);
|
||||
|
||||
// console.log(newPoint);
|
||||
node.x = newPoint.x;
|
||||
node.y = newPoint.y;
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
let forces = sumForcesToSample(node, sampleSubset, realDistances);
|
||||
//console.log(forces);
|
||||
node.x += forces.x*0.5;
|
||||
node.y += forces.y*0.5;
|
||||
}
|
||||
}
|
||||
|
||||
function sumForcesToSample(node, samples, sampleCache) {
|
||||
let nodeVx = 0,
|
||||
nodeVy = 0;
|
||||
|
||||
for (let i = 0; i < samples.length; i++) {
|
||||
var sample = samples[i];
|
||||
if(sample === node) continue;
|
||||
|
||||
let x = node.x - sample.x,
|
||||
y = node.y - sample.y,
|
||||
l = Math.sqrt(x * x + y * y);
|
||||
|
||||
l = (l - sampleCache[i]) / l;
|
||||
x *= l, y *= l;
|
||||
nodeVx -= x;
|
||||
nodeVy -= y;
|
||||
}
|
||||
return {x: nodeVx, y: nodeVy};
|
||||
}
|
||||
|
||||
function binarySearchMin(lb, hb, fn) {
|
||||
while (lb <= hb) {
|
||||
if(lb === hb) return lb;
|
||||
|
||||
if(hb-lb == 1) {
|
||||
if (fn(lb) >= fn(hb)) return hb;
|
||||
else return lb;
|
||||
}
|
||||
|
||||
let range = hb-lb;
|
||||
let valLowerHalf = fn(lb + range/4);
|
||||
let valHigherHalf = fn(lb + range*3/4);
|
||||
|
||||
if (valLowerHalf > valHigherHalf)
|
||||
lb = Math.floor((lb + hb) / 2);
|
||||
else if (valLowerHalf < valHigherHalf)
|
||||
hb = Math.ceil((lb + hb) / 2);
|
||||
else {
|
||||
lb += Math.floor(range/4);
|
||||
hb -= Math.ceil(range/4);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -56,8 +56,10 @@ export default function () {
|
||||
// for each node.
|
||||
findNewNeighbours(i);
|
||||
}
|
||||
velocity /= nodes.length*alpha;
|
||||
// Now total velocity changes per node, alpha not considered
|
||||
velocity /= nodes.length*(neighbours.length+samples.length)*alpha;
|
||||
// Now total velocity changes per link, alpha not considered
|
||||
// TODO per property too
|
||||
stableVelocity = 0;
|
||||
if(Math.abs(velocity)<stableVelocity && stableVeloHandler!== null){
|
||||
console.log("Neighbour sampling is now", velocity, ", calling stableVeloHandler().")
|
||||
stableVeloHandler();
|
||||
|
||||
Reference in New Issue
Block a user