Interp almost-complete brute-force interpolation

This commit is contained in:
Pitchaya Boonsarngsuk
2018-01-16 21:24:47 +00:00
parent a615ef199d
commit 7b6b5e46c6
4 changed files with 82 additions and 94 deletions

View File

@@ -166,7 +166,7 @@
<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/>
<input type="range" min="1" max="100" value="20" step="1" oninput="d3.select('#fullIterationsSliderOutput').text(value); FULL_ITERATIONS=value;"> <input type="range" min="0" max="100" value="20" step="1" oninput="d3.select('#fullIterationsSliderOutput').text(value); FULL_ITERATIONS=value;">
</label> </label>
<br/> <br/>
<label title="Full NeighbourSize"> <label title="Full NeighbourSize">

View File

@@ -297,16 +297,21 @@ function startHybridSimulation() {
simulation.stop(); simulation.stop();
p1 = performance.now(); p1 = performance.now();
hybridSimulation = d3.hybridSimulation(nodes); configuration = {
iteration: ITERATIONS,
hybridSimulation neighbourSize: NEIGHBOUR_SIZE,
.multiplier(MULTIPLIER) sampleSize: SAMPLE_SIZE,
.sampleIterations(ITERATIONS) distanceRange: SELECTED_DISTANCE * MULTIPLIER,
.pivots(PIVOTS) fullIterations: FULL_ITERATIONS,
.numPivots(NUM_PIVOTS) fullNeighbourSize: FULL_NEIGHBOUR_SIZE,
.fullIterations(FULL_ITERATIONS) fullSampleSize: FULL_SAMPLE_SIZE,
.neighbourSize(NEIGHBOUR_SIZE) fullDistanceRange: FULL_SELECTED_DISTANCE * MULTIPLIER,
distanceFn: function (s, t) {return distanceFunction(s, t, props, norm) * MULTIPLIER;},
pivots: PIVOTS,
numPivots: NUM_PIVOTS
};
.sampleSize(SAMPLE_SIZE); .sampleSize(SAMPLE_SIZE);
hybridSimulation = d3.hybridSimulation(nodes, configuration);
let sample = hybridSimulation.sample(); let sample = hybridSimulation.sample();
let remainder = hybridSimulation.remainder(); let remainder = hybridSimulation.remainder();

View File

@@ -16,34 +16,34 @@ export default function (nodes, config) {
FullneighbourSize = config.hasOwnProperty("fullNeighbourSize") ? config.fullNeighbourSize : 6, FullneighbourSize = config.hasOwnProperty("fullNeighbourSize") ? config.fullNeighbourSize : 6,
FullsampleSize = config.hasOwnProperty("fullSampleSize") ? config.fullSampleSize : 3, FullsampleSize = config.hasOwnProperty("fullSampleSize") ? config.fullSampleSize : 3,
FulldistanceRange = config.hasOwnProperty("fullDistanceRange") ? config.fullDistanceRange : 10, FulldistanceRange = config.hasOwnProperty("fullDistanceRange") ? config.fullDistanceRange : 10,
distanceFn = config.hasOwnProperty("distanceFn") ? config.distance : constant(300), distanceFn = config.hasOwnProperty("distanceFn") ? config.distanceFn : constant(300),
PIVOTS = config.hasOwnProperty("pivots") ? config.pivots : false, PIVOTS = config.hasOwnProperty("pivots") ? config.pivots : false,
NUMPIVOTS = config.hasOwnProperty("numPivots") ? config.numPivots : 3, NUMPIVOTS = config.hasOwnProperty("numPivots") ? config.numPivots : 3,
event = d3.dispatch("sampleTick", "fullTick", "startFull", "end"); event = d3.dispatch("sampleTick", "fullTick", "startFull", "end");
var sets = sampleFromNodes(nodes, nodes.length, Math.sqrt(nodes.length)); var sets = sampleFromNodes(nodes, Math.sqrt(nodes.length));
var sample = sets.sample; var sample = sets.sample;
var remainder = sets.remainder; var remainder = sets.remainder;
var interpSubset = sampleFromNodes(sample, sample.length, Math.sqrt(sample.length)).sample; var sampleSubset = sampleFromNodes(sample, Math.sqrt(sample.length)).sample;
var sampleSimulation = d3.forceSimulation(sample) var sampleSimulation = d3.forceSimulation(sample)
.stop() .stop()
.alphaDecay(1 - Math.pow(0.001, 1 / SAMPLE_ITERATIONS)); .alphaDecay(1 - Math.pow(0.001, 1 / SAMPLE_ITERATIONS))
sampleSimulation
.on("tick", function () { .on("tick", function () {
event.call("sampleTick", sampleSimulation); event.call("sampleTick", sampleSimulation);
}) })
.on("end", ended) .on("end", ended);
.force("neighbourSampling", neighbourSamplingDistance()
sampleSimulation.force("forces", neighbourSamplingDistance()
.neighbourSize(neighbourSize) .neighbourSize(neighbourSize)
.sampleSize(sampleSize) .sampleSize(sampleSize)
.distanceRange(distanceRange) .distanceRange(distanceRange)
.distance(distanceFn) .distance(distanceFn)
) );
.alpha(1).restart(); sampleSimulation.alpha(1).restart();
function ended() { function ended() {
event.call("startFull");
console.log("Ended sample simulation"); console.log("Ended sample simulation");
/* /*
if (PIVOTS) { if (PIVOTS) {
@@ -52,12 +52,16 @@ export default function (nodes, config) {
interpolation(sample, remainder, interpSubset, distance); interpolation(sample, remainder, interpSubset, distance);
} }
*/ */
if (FULL_ITERATIONS==0) return; event.call("fullTick");
alert('About to Full run');
if (FULL_ITERATIONS==0) {
event.call("end");
return;
}
fullSimulation = d3.forceSimulation() fullSimulation = d3.forceSimulation()
.stop() .stop()
.alphaDecay(1 - Math.pow(0.001, 1 / FULL_ITERATIONS)); .alphaDecay(1 - Math.pow(0.001, 1 / FULL_ITERATIONS));
event.call("startFull", fullSimulation);
fullSimulation fullSimulation
.force("neighbourSampling", neighbourSamplingDistance() .force("neighbourSampling", neighbourSamplingDistance()
@@ -139,8 +143,9 @@ export default function (nodes, config) {
} }
function sampleFromNodes(nodes, max, size) { function sampleFromNodes(nodes, size) {
var randElements = []; let randElements = [],
max = nodes.length;
for (var i = 0; i < size; ++i) { for (var i = 0; i < size; ++i) {
var rand = nodes[Math.floor((Math.random() * max))]; var rand = nodes[Math.floor((Math.random() * max))];

View File

@@ -1,60 +1,45 @@
export default function(sampleSet, remainderSet, interpSubset, distanceFunction) { export default function(sampleSet, remainderSet, sampleSubset, distanceFn) {
var distance = distanceFunction; var distance = distanceFunction;
// var distance = calculateEuclideanDistance; // var distance = calculateEuclideanDistance;
// console.log("Brute-force"); // console.log("Brute-force");
for (let node of remainderSet) {
let nearestSample = undefined,
minDist = undefined,
sampleSubsetDistanceCache = [];
for (var i = 0; i < remainderSet.length; i++) { for (let sample of sampleSet) {
var node = remainderSet[i], let dist = distanceFn(node, sample);
minNode = sampleSet[0], if (nearestSample === undefined || dist < minDist) {
minDist = 0, minDist = dist;
sampleCache = []; nearestSample = sample;
}
minDist = distance(node, minNode, props, norm); let index = sampleSubset.indexOf(sample);
if (index !== -1) {
for (var j = 1, sample; j < sampleSet.length; j++) { sampleSubsetDistanceCache[index] = dist;
sample = sampleSet[j];
if ((sample !== node) && (distance(node, sample, props, norm) < minDist)) {
minDist = distance(node, sample, props, norm);
minNode = sample;
} }
} }
// console.log() placeNearToNearestNeighbour(node, nearestSample, minDist, sampleSubset, sampleSubsetDistanceCache);
for (var k = 0; k < interpSubset.length; k++) {
sampleCache[k] = distance(node, interpSubset[k], props, norm);
}
var radius = distance(node, minNode, props, norm);
placeNearToNearestNeighbour(node, minNode, interpSubset, sampleCache, radius);
} }
} }
function placeNearToNearestNeighbour(node, minNode, sample, sampleCache, radius) { function placeNearToNearestNeighbour(node, minNode, radius, samples, realDistances) {
var let
dist0 = 0.0, dist0 = sumDistError(pointOnCircle(minNode.x, minNode.y, 0, radius), samples, realDistances),
dist90 = 0.0, dist90 = sumDistError(pointOnCircle(minNode.x, minNode.y, 90, radius), samples, realDistances),
dist180 = 0.0, dist180 = sumDistError(pointOnCircle(minNode.x, minNode.y, 180, radius), samples, realDistances),
dist270 = 0.0, dist270 = sumDistError(pointOnCircle(minNode.x, minNode.y, 270, radius), samples, realDistances),
lowBound = 0.0, lowBound = 0.0,
highBound = 0.0; highBound = 0.0;
dist0 = sumDistToSample(node, centerPoint(0, radius, minNode.x, minNode.y), sample, sampleCache);
dist90 = sumDistToSample(node, centerPoint(90, radius, minNode.x, minNode.y), sample, sampleCache);
dist180 = sumDistToSample(node, centerPoint(180, radius, minNode.x, minNode.y), sample, sampleCache);
dist270 = sumDistToSample(node, centerPoint(270, radius, minNode.x, minNode.y), sample, sampleCache);
// console.log(dist0, dist90, dist180, dist270);
// Determine the closest quadrant // Determine the closest quadrant
if (dist0 == dist180) { if (dist0 == dist180) {
if (dist90 > dist270) if (dist90 > dist270)
lowBound = highBound = 270; lowBound = highBound = 270;
else else
lowBound = highBound = 90; lowBound = highBound = 90;
} else if (dist90 == dist270) { } else if (dist90 == dist270) {
if (dist0 > dist180) if (dist0 > dist180)
lowBound = highBound = 180; lowBound = highBound = 180;
@@ -78,8 +63,11 @@ function placeNearToNearestNeighbour(node, minNode, sample, sampleCache, radius)
} }
} }
let angle = binarySearch(lowBound, highBound, minNode.x, minNode.y, radius, node, sample, realDistances); let angle = binarySearchMin(lowBound, highBound,
let newPoint = centerPoint(angle, radius, minNode.x, minNode.y); function(angle){
return sumDistError(pointOnCircle(minNode.x, minNode.y, angle, radius), samples, realDistances);
});
let newPoint = pointOnCircle(minNode.x, minNode.y, angle, radius);
// console.log(newPoint); // console.log(newPoint);
node.x = newPoint.x; node.x = newPoint.x;
@@ -110,17 +98,13 @@ function toRadians(degrees) {
return degrees * (Math.PI / 180); return degrees * (Math.PI / 180);
} }
function sumDistToSample(node, point, sample, sampleCache) { function sumDistError(currentPos, samples, realDistances) {
var total = 0.0; let total = 0.0;
// console.log(total, sample); for (let i = 0; i < samples.length; i++) {
let sample = samples[i];
for (var i = 0; i < sample.length; i++) { let lowDDistance = Math.hypot(sample.x - currentPos.x, sample.y - currentPos.y);
var s = sample[i]; total += Math.abs(lowDDistance - realDistances[i]);
var realDist = Math.hypot(s.x - point.x, s.y - point.y);
var desDist = sampleCache[i];
total += Math.abs(realDist - desDist);
} }
return total; return total;
} }
@@ -165,32 +149,26 @@ function sumForcesToSample(node, sample, sampleCache) {
} }
} }
function binarySearchMin(lb, hb, fn) {
function binarySearch(lb, hb, x, y, r, node, sample, sampleCache) {
while (lb <= hb) { while (lb <= hb) {
var mid = Math.round((lb + hb) / 2); if(lb === hb) return lb;
if(hb-lb == 1) {
if (fn(lb) >= fn(hb)) return hb;
else return lb;
}
if ((mid === lb) || (mid === hb)) { let range = hb-lb;
if (sumDistToSample(node, centerPoint(lb, r, x, y), sample, sampleCache) >= let valLowerHalf = fn(lb + range/4);
sumDistToSample(node, centerPoint(hb, r, x, y), sample, sampleCache)) { let valHigherHalf = fn(lb + range*3/4);
return hb;
} else {
return lb;
}
} else {
var distMidLeft = sumDistToSample(node, centerPoint(mid + 1, r, x, y), sample, sampleCache);
var distMidRight = sumDistToSample(node, centerPoint(mid - 1, r, x, y), sample, sampleCache);
var distMid = sumDistToSample(node, centerPoint(mid, r, x, y), sample, sampleCache);
if (distMid > distMidLeft) { if (valLowerHalf > valHigherHalf)
lb = mid + 1; lb = Math.floor((lb + hb) / 2);
} else if (distMid > distMidRight) { else if (valLowerHalf < valHigherHalf)
hb = mid - 1; hb = Math.ceil((lb + hb) / 2);
} else { else {
return mid; lb += Math.floor(range/4);
} hb -= Math.ceil(range/4);
} }
} }
return -1; return -1;
} }