forked from jhackshaw/tspvis
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
183 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
--- | ||
type: heuristic-construction | ||
order: 3 | ||
solverKey: nearestInsertion | ||
friendlyName: Nearest Insertion | ||
defaults: | ||
evaluatingDetailLevel: 1 | ||
maxEvaluatingDetailLevel: 1 | ||
--- | ||
|
||
|
||
# Furthest Insertion | ||
|
||
This is a heuristic construction algorithm. It chooses the furthest point from the path to add to it, and then figures out where the best place to put it will be. | ||
|
||
1. From the starting point | ||
2. First, go to the closest point | ||
3. Choose the point that is **nearest** to the current path | ||
4. Find the cheapest place to add it in the path | ||
4. Chosen point is no longer an "available point" | ||
5. Continue from #3 until there are no available points, and then return to the start. | ||
|
||
|
||
## The code | ||
|
||
```javascript | ||
|
||
const furthestInsertion = async points => { | ||
// from the starting point | ||
const path = [points.shift()]; | ||
|
||
// | ||
// INITIALIZATION - go to the nearest point first | ||
// | ||
points.sort((a, b) => ( | ||
distance(path[0], b) - | ||
distance(path[0], a) | ||
)); | ||
path.push(points.pop()); | ||
|
||
|
||
while (points.length > 0) { | ||
// | ||
// SELECTION - nearest point to the path | ||
// | ||
let [selectedDistance, selectedIdx] = [Infinity, null]; | ||
for (const [freePointIdx, freePoint] of points.entries()) { | ||
|
||
// find the minimum distance to the path for freePoint | ||
let [bestCostToPath, costToPathIdx] = [Infinity, null]; | ||
for (const pathPoint of path) { | ||
const dist = distance(freePoint, pathPoint); | ||
if (dist < bestCostToPath) { | ||
[bestCostToPath, costToPathIdx] = [dist, freePointIdx] | ||
} | ||
} | ||
|
||
// if this point is closer to the path than the currently selected | ||
if (bestCostToPath < selectedDistance) { | ||
[selectedDistance, selectedIdx] = [bestCostToPath, costToPathIdx]; | ||
} | ||
} | ||
const [ nextPoint ] = points.splice(selectedIdx, 1); | ||
|
||
// | ||
// INSERTION - find the insertion spot that minimizes distance | ||
// | ||
let [bestCost, bestIdx] = [Infinity, null]; | ||
for (let i=1; i<path.length; i++) { | ||
const insertionCost = pathCost([ | ||
path[i-1], nextPoint, path[i] | ||
]) | ||
if (insertionCost < bestCost) { | ||
[bestCost, bestIdx] = [insertionCost, i]; | ||
} | ||
} | ||
path.splice(bestIdx, 0, nextPoint); | ||
} | ||
|
||
// return to start after visiting all other points | ||
path.push(path[0]); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* eslint-disable no-restricted-globals */ | ||
import makeSolver from '../makeSolver'; | ||
import { pathCost, distance } from '../cost'; | ||
|
||
|
||
const furthestInsertion = async points => { | ||
// from the starting point | ||
const path = [points.shift()]; | ||
|
||
// | ||
// INITIALIZATION - go to the nearest point first | ||
// | ||
points.sort((a, b) => ( | ||
distance(path[0], b) - | ||
distance(path[0], a) | ||
)); | ||
path.push(points.pop()); | ||
|
||
self.setEvaluatingPaths(() => ({ | ||
paths: [{ path }], | ||
cost: pathCost(path) | ||
})) | ||
|
||
await self.sleep(); | ||
|
||
|
||
while (points.length > 0) { | ||
// | ||
// SELECTION - nearest point to the path | ||
// | ||
let [selectedDistance, selectedIdx] = [0, null]; | ||
for (const [freePointIdx, freePoint] of points.entries()) { | ||
|
||
// find the minimum distance to the path for freePoint | ||
let [bestCostToPath, costToPathIdx] = [Infinity, null]; | ||
for (const pathPoint of path) { | ||
const dist = distance(freePoint, pathPoint); | ||
if (dist < bestCostToPath) { | ||
[bestCostToPath, costToPathIdx] = [dist, freePointIdx] | ||
} | ||
} | ||
|
||
// if this point is closer to the path than the currently selected | ||
if (bestCostToPath < selectedDistance) { | ||
[selectedDistance, selectedIdx] = [bestCostToPath, costToPathIdx]; | ||
} | ||
} | ||
|
||
// get the next point to add | ||
const [ nextPoint ] = points.splice(selectedIdx, 1); | ||
|
||
// | ||
// INSERTION - find the insertion spot that minimizes distance | ||
// | ||
let [bestCost, bestIdx] = [Infinity, null]; | ||
for (let i=1; i<path.length; i++) { | ||
const insertionCost = pathCost([ | ||
path[i-1], nextPoint, path[i] | ||
]) | ||
if (insertionCost < bestCost) { | ||
[bestCost, bestIdx] = [insertionCost, i]; | ||
} | ||
} | ||
path.splice(bestIdx, 0, nextPoint); | ||
|
||
|
||
self.setEvaluatingPaths(() => ({ | ||
paths: [{ path }], | ||
cost: pathCost(path) | ||
})) | ||
|
||
await self.sleep(); | ||
} | ||
|
||
// return to start after visiting all other points | ||
path.push(path[0]); | ||
const cost = pathCost(path); | ||
|
||
self.setEvaluatingPaths(() => ({ | ||
paths: [{ path }], | ||
cost | ||
})) | ||
await self.sleep(); | ||
|
||
self.setBestPath(path, cost) | ||
|
||
} | ||
|
||
makeSolver(furthestInsertion); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters