From 047d89f004f6d6d24514b42606cd2922bc95b94a Mon Sep 17 00:00:00 2001 From: brian Date: Fri, 16 Mar 2018 10:20:00 +0700 Subject: [PATCH] Update 'src/interpolation/interpolationPivots.js' --- src/interpolation/interpolationPivots.js | 270 +++++++++++------------ 1 file changed, 135 insertions(+), 135 deletions(-) diff --git a/src/interpolation/interpolationPivots.js b/src/interpolation/interpolationPivots.js index c7ec82f..8b0231d 100644 --- a/src/interpolation/interpolationPivots.js +++ b/src/interpolation/interpolationPivots.js @@ -1,135 +1,135 @@ -import {pointOnCircle, takeSampleFrom} from "./helpers"; -import {placeNearToNearestNeighbour} from "./interpCommon"; - -/** - * Perform interpolation where the "parent" node is is estimated by pivot-based searching. - * - Pre-processing: assign random samples as pivots, - * put the others in each pivot's bucket. - * ie. a non-pivot sample X may be in - * - bucket 3 of pivot A, - * - bucket 1 of pivot B, - * - bucket 5 of pivot C, - * all at the same time - * For each point to be interpolated: - * - Phase 1: for each pivot: compare distance against the pivot - * compare against other points in the same bucket of that pivot - * note down the parent found - * this is essentially a near neighbour estimation problem. - * - Phase 2 and 3 are passed onto placeNearToNearestNeighbour - * @param {list} sampleSet - nodes already plotted on the 2D graph - * @param {list} remainderSet - nodes to be interpolated onto the graph - * @param {function} distanceFn - f(nodex, nodey) that calculate high-dimensional - * distance between 2 nodes - * @param {number} endingIts - for phase 3, how many iterations to refine the - * placement of each interpolated point - */ -export default function(sampleSet, remainderSet, numPivots, distanceFn, endingIts) { - // Pivot based parent finding - let numBuckets = Math.floor(Math.sqrt(sampleSet.length)); - let numNonPivots = sampleSet.length - numPivots; - let sets = takeSampleFrom(sampleSet, numPivots); - let pivots = sets.sample; - let nonPivotSamples = sets.remainder; - - let pivotsBuckets = []; // [ For each Pivot:[For each bucket:[each point in bucket]] ] - for (let i = 0; i < numPivots; i++) { - pivotsBuckets[i] = []; - for (let j = 0; j < numBuckets; j++) { - pivotsBuckets[i][j] = []; - } - } - - // Pre-calculate distance between each non-pivot sample to each pivot - // At the same time, determine the bucket width for each pivot based on furthest non-pivot sample - let distCache = []; // [ For each non-pivot sample:[For each Pivot: distance] ] - let bucketWidths = []; // [ For each Pivot: width of each bucket ] - - for (let i = 0; i < nonPivotSamples.length; i++) - distCache[i] = []; - - for (let j = 0; j < numPivots; j++) { - let pivot = pivots[j]; - let maxDist = -1; - - for (let i = 0; i < numNonPivots; i++) { - let sample = nonPivotSamples[i]; - distCache[i][j] = distanceFn(pivot, sample); - if (distCache[i][j] > maxDist) - maxDist = distCache[i][j]; - } - - bucketWidths.push(maxDist / numBuckets); - } - - // Put samples (pivot not included) into buckets - for (let j = 0; j < numPivots; j++) { - let bucketWidth = bucketWidths[j]; - for (let i = 0; i < numNonPivots; i++) { - let sample = nonPivotSamples[i]; - let bucketNumber = Math.floor(distCache[i][j] / bucketWidth); - if (bucketNumber >= numBuckets) { - bucketNumber = numBuckets - 1; - } else if (bucketNumber < 0) { // Should never be negative anyway - bucketNumber = 0; - } - pivotsBuckets[j][bucketNumber].push(sample); - } - } - // --------------------------------------------------------------------- - - - let sampleSubset = takeSampleFrom(sampleSet, Math.sqrt(sampleSet.length)).sample; - //Plot each of the remainder nodes - for (let i = remainderSet.length-1; i>=0; i--) { - let node = remainderSet[i]; - let sampleSubsetDistanceCache = [], - minDist, nearSample; - - // Pivot based parent search - for (let p = 0; p < numPivots; p++) { - let pivot = pivots[p]; - let bucketWidth = bucketWidths[p]; - - let dist = distanceFn(node, pivot); - let index = sampleSubset.indexOf(pivot); - if (index !== -1) { - sampleSubsetDistanceCache[index] = dist; - } - if (minDist === undefined || dist < minDist){ - minDist = dist; - nearSample = pivot; - } - - let bucketNumber = Math.floor(dist / bucketWidth); - if (bucketNumber >= numBuckets) { - bucketNumber = numBuckets - 1; - } else if (bucketNumber < 0) { // Should never be negative anyway - bucketNumber = 0; - } - - for (let j = pivotsBuckets[p][bucketNumber].length-1; j>=0; j--) { - let candidateNode = pivotsBuckets[p][bucketNumber][j]; - let index = sampleSubset.indexOf(candidateNode); - if (index !== -1 && sampleSubsetDistanceCache[index] !== undefined) - dist = sampleSubsetDistanceCache[index] - else { - dist = distanceFn(candidateNode, node); - if (index !== -1) - sampleSubsetDistanceCache[index] = dist; - } - - if (dist < minDist){ - minDist = dist; - nearSample = candidateNode; - } - } - } - - // Fill in holes in cache - for (let k = 0; k < sampleSubset.length; k++) { - if (sampleSubsetDistanceCache[k] === undefined) - sampleSubsetDistanceCache[k] = distanceFn(node, sampleSubset[k]); - } - placeNearToNearestNeighbour(node, nearSample, minDist, sampleSubset, sampleSubsetDistanceCache, endingIts); - } -} +import {takeSampleFrom} from "./helpers"; +import {placeNearToNearestNeighbour} from "./interpCommon"; + +/** + * Perform interpolation where the "parent" node is is estimated by pivot-based searching. + * - Pre-processing: assign random samples as pivots, + * put the others in each pivot's bucket. + * ie. a non-pivot sample X may be in + * - bucket 3 of pivot A, + * - bucket 1 of pivot B, + * - bucket 5 of pivot C, + * all at the same time + * For each point to be interpolated: + * - Phase 1: for each pivot: compare distance against the pivot + * compare against other points in the same bucket of that pivot + * note down the parent found + * this is essentially a near neighbour estimation problem. + * - Phase 2 and 3 are passed onto placeNearToNearestNeighbour + * @param {list} sampleSet - nodes already plotted on the 2D graph + * @param {list} remainderSet - nodes to be interpolated onto the graph + * @param {function} distanceFn - f(nodex, nodey) that calculate high-dimensional + * distance between 2 nodes + * @param {number} endingIts - for phase 3, how many iterations to refine the + * placement of each interpolated point + */ +export default function(sampleSet, remainderSet, numPivots, distanceFn, endingIts) { + // Pivot based parent finding + let numBuckets = Math.floor(Math.sqrt(sampleSet.length)); + let numNonPivots = sampleSet.length - numPivots; + let sets = takeSampleFrom(sampleSet, numPivots); + let pivots = sets.sample; + let nonPivotSamples = sets.remainder; + + let pivotsBuckets = []; // [ For each Pivot:[For each bucket:[each point in bucket]] ] + for (let i = 0; i < numPivots; i++) { + pivotsBuckets[i] = []; + for (let j = 0; j < numBuckets; j++) { + pivotsBuckets[i][j] = []; + } + } + + // Pre-calculate distance between each non-pivot sample to each pivot + // At the same time, determine the bucket width for each pivot based on furthest non-pivot sample + let distCache = []; // [ For each non-pivot sample:[For each Pivot: distance] ] + let bucketWidths = []; // [ For each Pivot: width of each bucket ] + + for (let i = 0; i < nonPivotSamples.length; i++) + distCache[i] = []; + + for (let j = 0; j < numPivots; j++) { + let pivot = pivots[j]; + let maxDist = -1; + + for (let i = 0; i < numNonPivots; i++) { + let sample = nonPivotSamples[i]; + distCache[i][j] = distanceFn(pivot, sample); + if (distCache[i][j] > maxDist) + maxDist = distCache[i][j]; + } + + bucketWidths.push(maxDist / numBuckets); + } + + // Put samples (pivot not included) into buckets + for (let j = 0; j < numPivots; j++) { + let bucketWidth = bucketWidths[j]; + for (let i = 0; i < numNonPivots; i++) { + let sample = nonPivotSamples[i]; + let bucketNumber = Math.floor(distCache[i][j] / bucketWidth); + if (bucketNumber >= numBuckets) { + bucketNumber = numBuckets - 1; + } else if (bucketNumber < 0) { // Should never be negative anyway + bucketNumber = 0; + } + pivotsBuckets[j][bucketNumber].push(sample); + } + } + // --------------------------------------------------------------------- + + + let sampleSubset = takeSampleFrom(sampleSet, Math.sqrt(sampleSet.length)).sample; + //Plot each of the remainder nodes + for (let i = remainderSet.length-1; i>=0; i--) { + let node = remainderSet[i]; + let sampleSubsetDistanceCache = [], + minDist, nearSample; + + // Pivot based parent search + for (let p = 0; p < numPivots; p++) { + let pivot = pivots[p]; + let bucketWidth = bucketWidths[p]; + + let dist = distanceFn(node, pivot); + let index = sampleSubset.indexOf(pivot); + if (index !== -1) { + sampleSubsetDistanceCache[index] = dist; + } + if (minDist === undefined || dist < minDist){ + minDist = dist; + nearSample = pivot; + } + + let bucketNumber = Math.floor(dist / bucketWidth); + if (bucketNumber >= numBuckets) { + bucketNumber = numBuckets - 1; + } else if (bucketNumber < 0) { // Should never be negative anyway + bucketNumber = 0; + } + + for (let j = pivotsBuckets[p][bucketNumber].length-1; j>=0; j--) { + let candidateNode = pivotsBuckets[p][bucketNumber][j]; + let index = sampleSubset.indexOf(candidateNode); + if (index !== -1 && sampleSubsetDistanceCache[index] !== undefined) + dist = sampleSubsetDistanceCache[index] + else { + dist = distanceFn(candidateNode, node); + if (index !== -1) + sampleSubsetDistanceCache[index] = dist; + } + + if (dist < minDist){ + minDist = dist; + nearSample = candidateNode; + } + } + } + + // Fill in holes in cache + for (let k = 0; k < sampleSubset.length; k++) { + if (sampleSubsetDistanceCache[k] === undefined) + sampleSubsetDistanceCache[k] = distanceFn(node, sampleSubset[k]); + } + placeNearToNearestNeighbour(node, nearSample, minDist, sampleSubset, sampleSubsetDistanceCache, endingIts); + } +}