mirror of
https://github.com/anvaka/ngraph.path.git
synced 2026-01-18 15:13:12 +00:00
Added proper oriented search
This commit is contained in:
parent
29ce133e59
commit
889a5d28a5
@ -61,6 +61,8 @@ function aStarBi(graph, options) {
|
||||
|
||||
pool.reset();
|
||||
|
||||
var callVisitor = oriented ? orientedVisitor : nonOrientedVisitor;
|
||||
|
||||
// Maps nodeId to NodeSearchState.
|
||||
var nodeState = new Map();
|
||||
|
||||
@ -116,19 +118,32 @@ function aStarBi(graph, options) {
|
||||
|
||||
if (current.distanceToSource > lMin) continue;
|
||||
|
||||
graph.forEachLinkedNode(current.node.id, callVisitor, oriented);
|
||||
graph.forEachLinkedNode(current.node.id, callVisitor);
|
||||
|
||||
if (minFrom && minTo) {
|
||||
// This is not necessary the best path, but we are so greedy that we
|
||||
// can't resist:
|
||||
return reconstructBiDirectionalPath(minFrom, minTo);
|
||||
}
|
||||
}
|
||||
|
||||
return NO_PATH; // No path.
|
||||
|
||||
function callVisitor(otherNode, link) {
|
||||
function nonOrientedVisitor(otherNode, link) {
|
||||
return visitNode(otherNode, link, current);
|
||||
}
|
||||
|
||||
function orientedVisitor(otherNode, link) {
|
||||
// For oritned graphs we need to reverse graph, when traveling
|
||||
// backwards. So, we use non-oriented ngraph's traversal, and
|
||||
// filter link orientation here.
|
||||
if (currentOpener === BY_FROM) {
|
||||
if (link.fromId === current.node.id) return visitNode(otherNode, link, current)
|
||||
} else if (currentOpener === BY_TO) {
|
||||
if (link.toId === current.node.id) return visitNode(otherNode, link, current);
|
||||
}
|
||||
}
|
||||
|
||||
function canExit(currentNode) {
|
||||
var opener = currentNode.open
|
||||
if (opener && opener !== currentOpener) {
|
||||
@ -142,12 +157,12 @@ function aStarBi(graph, options) {
|
||||
var pathOfNodes = [];
|
||||
var aParent = a;
|
||||
while(aParent) {
|
||||
pathOfNodes.unshift(aParent.node);
|
||||
pathOfNodes.push(aParent.node);
|
||||
aParent = aParent.parent;
|
||||
}
|
||||
var bParent = b;
|
||||
while (bParent) {
|
||||
pathOfNodes.push(bParent.node);
|
||||
pathOfNodes.unshift(bParent.node);
|
||||
bParent = bParent.parent
|
||||
}
|
||||
return pathOfNodes;
|
||||
@ -180,7 +195,6 @@ function aStarBi(graph, options) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var tentativeDistance = cameFrom.distanceToSource + distance(otherSearchState.node, cameFrom.node, link);
|
||||
|
||||
if (tentativeDistance >= otherSearchState.distanceToSource) {
|
||||
|
||||
@ -38,6 +38,9 @@ function nba(graph, options) {
|
||||
|
||||
pool.reset();
|
||||
|
||||
var forwardVisitor = oriented ? visitN1Oriented : visitN1;
|
||||
var reverseVisitor = oriented ? visitN2Oriented : visitN2;
|
||||
|
||||
// Maps nodeId to NBASearchState.
|
||||
var nodeState = new Map();
|
||||
|
||||
@ -90,7 +93,7 @@ function nba(graph, options) {
|
||||
cameFrom.closed = true;
|
||||
|
||||
if (cameFrom.f1 < lMin && (cameFrom.g1 + f2 - heuristic(from, cameFrom.node)) < lMin) {
|
||||
graph.forEachLinkedNode(cameFrom.node.id, visitN1, options.oriented) // todo - needs to reverse correctly
|
||||
graph.forEachLinkedNode(cameFrom.node.id, forwardVisitor);
|
||||
}
|
||||
|
||||
if (open1Set.length > 0) {
|
||||
@ -106,7 +109,7 @@ function nba(graph, options) {
|
||||
cameFrom.closed = true;
|
||||
|
||||
if (cameFrom.f2 < lMin && (cameFrom.g2 + f1 - heuristic(cameFrom.node, to)) < lMin) {
|
||||
graph.forEachLinkedNode(cameFrom.node.id, visitN2, options.oriented) // todo - needs to reverse correctly
|
||||
graph.forEachLinkedNode(cameFrom.node.id, reverseVisitor);
|
||||
}
|
||||
|
||||
if (open2Set.length > 0) {
|
||||
@ -169,6 +172,15 @@ function nba(graph, options) {
|
||||
minNode = otherSearchState;
|
||||
}
|
||||
}
|
||||
|
||||
function visitN2Oriented(otherNode, link) {
|
||||
// we are going backwards, graph needs to be reversed.
|
||||
if (link.toId === cameFrom.node.id) return visitN2(otherNode, link);
|
||||
}
|
||||
function visitN1Oriented(otherNode, link) {
|
||||
// this is forward direction, so we should be coming FROM:
|
||||
if (link.fromId === cameFrom.node.id) return visitN1(otherNode, link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@ var fromDot = require('ngraph.fromdot');
|
||||
var asciiUtils = require('./utils/graphFromAscii');
|
||||
|
||||
test('it can find weighted', t => {
|
||||
let createGraph = require('ngraph.graph');
|
||||
let graph = createGraph();
|
||||
|
||||
graph.addLink('a', 'b', {weight: 10});
|
||||
@ -28,6 +27,64 @@ test('it can find weighted', t => {
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('A* can find directed path', t => {
|
||||
let graph = createGraph();
|
||||
|
||||
// We want to find a path from a to e.
|
||||
// a -> b <- e
|
||||
// \ /
|
||||
// c -> d
|
||||
// In undirected graph the `a, b, e` will be the solution.
|
||||
// In directed graph it sohuld be `a c d e`
|
||||
graph.addLink('a', 'b');
|
||||
graph.addLink('e', 'b');
|
||||
|
||||
graph.addLink('a', 'c');
|
||||
graph.addLink('c', 'd');
|
||||
graph.addLink('d', 'e');
|
||||
|
||||
|
||||
var pathFinder = aStar(graph, {
|
||||
oriented: true
|
||||
});
|
||||
let path = pathFinder.find('a', 'e');
|
||||
|
||||
t.equals(path[0].id, 'e', 'e is here');
|
||||
t.equals(path[1].id, 'd', 'd is here');
|
||||
t.equals(path[2].id, 'c', 'c is here');
|
||||
t.equals(path[3].id, 'a', 'a is here');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('A* greedy can find directed path', t => {
|
||||
let graph = createGraph();
|
||||
|
||||
// We want to find a path from a to e.
|
||||
// a -> b <- e
|
||||
// \ /
|
||||
// c -> d
|
||||
// In undirected graph the `a, b, e` will be the solution.
|
||||
// In directed graph it sohuld be `a c d e`
|
||||
graph.addLink('a', 'b');
|
||||
graph.addLink('e', 'b');
|
||||
|
||||
graph.addLink('a', 'c');
|
||||
graph.addLink('c', 'd');
|
||||
graph.addLink('d', 'e');
|
||||
|
||||
var pathFinder = aGreedy(graph, {
|
||||
oriented: true
|
||||
});
|
||||
let path = pathFinder.find('a', 'e');
|
||||
|
||||
t.equals(path[0].id, 'e', 'e is here');
|
||||
t.equals(path[1].id, 'd', 'd is here');
|
||||
t.equals(path[2].id, 'c', 'c is here');
|
||||
t.equals(path[3].id, 'a', 'a is here');
|
||||
t.end();
|
||||
});
|
||||
|
||||
|
||||
test('it can use heuristic', t => {
|
||||
let createGraph = require('ngraph.graph');
|
||||
let graph = createGraph();
|
||||
@ -85,10 +142,12 @@ test('it can find path without any config', t => {
|
||||
t.equals(path[2].id, 'a', 'a is here');
|
||||
|
||||
var pathFinderBi = aGreedy(graph);
|
||||
var pathBi = pathFinderBi.find('a', 'c');
|
||||
t.equals(pathBi[0].id, 'c', 'c is here');
|
||||
t.equals(pathBi[1].id, 'b', 'b is here');
|
||||
t.equals(pathBi[2].id, 'a', 'a is here');
|
||||
let foundNodes = new Set();
|
||||
pathFinderBi.find('a', 'c').forEach(n => foundNodes.add(n.id));
|
||||
|
||||
t.ok(foundNodes.has('c'), 'c is here');
|
||||
t.ok(foundNodes.has('b'), 'b is here');
|
||||
t.ok(foundNodes.has('a'), 'a is here');
|
||||
|
||||
t.end();
|
||||
})
|
||||
|
||||
54
test/nba.js
Normal file
54
test/nba.js
Normal file
@ -0,0 +1,54 @@
|
||||
var test = require('tap').test;
|
||||
var nba = require('../').nba;
|
||||
var createGraph = require('ngraph.graph');
|
||||
|
||||
test('it can find path', t => {
|
||||
let graph = createGraph();
|
||||
|
||||
graph.addLink('a', 'b', {weight: 10});
|
||||
graph.addLink('a', 'c', {weight: 10});
|
||||
graph.addLink('c', 'd', {weight: 5});
|
||||
graph.addLink('b', 'd', {weight: 10});
|
||||
|
||||
|
||||
var pathFinder = nba(graph, {
|
||||
distance(a, b, link) {
|
||||
return link.data.weight;
|
||||
}
|
||||
});
|
||||
let path = pathFinder.find('a', 'd');
|
||||
|
||||
t.equals(path[0].id, 'd', 'd is here');
|
||||
t.equals(path[1].id, 'c', 'c is here');
|
||||
t.equals(path[2].id, 'a', 'a is here');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('it can find directed path', t => {
|
||||
let graph = createGraph();
|
||||
|
||||
// We want to find a path from a to e.
|
||||
// a -> b <- e
|
||||
// \ /
|
||||
// c -> d
|
||||
// In undirected graph the `a, b, e` will be the solution.
|
||||
// In directed graph it sohuld be `a c d e`
|
||||
graph.addLink('a', 'b');
|
||||
graph.addLink('e', 'b');
|
||||
|
||||
graph.addLink('a', 'c');
|
||||
graph.addLink('c', 'd');
|
||||
graph.addLink('d', 'e');
|
||||
|
||||
|
||||
var pathFinder = nba(graph, {
|
||||
oriented: true
|
||||
});
|
||||
let path = pathFinder.find('a', 'e');
|
||||
|
||||
t.equals(path[0].id, 'e', 'e is here');
|
||||
t.equals(path[1].id, 'd', 'd is here');
|
||||
t.equals(path[2].id, 'c', 'c is here');
|
||||
t.equals(path[3].id, 'a', 'a is here');
|
||||
t.end();
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user