mirror of https://gitee.com/bigwinds/arangodb
Enhanced pathTo for directed and labelled graphs
The `pathTo` method accepts an options hash. Currently supported: * direction: "both", "outbound", "inbound" * labels: undefined or Array of Strings
This commit is contained in:
parent
70ae8d84d4
commit
f11acff837
|
@ -80,6 +80,18 @@ Array.prototype.pushIfNotFound = function (element) {
|
|||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add all elements of the other array, that are not already in here
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Array.prototype.merge = function (other_array) {
|
||||
var i;
|
||||
|
||||
for (i = 0; i < other_array.length; i += 1) {
|
||||
this.pushIfNotFound(other_array[i]);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shallow copy properties
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -773,25 +785,23 @@ Vertex.prototype.setProperty = function (name, value) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief find the shortest path to a certain vertex, return the ID
|
||||
///
|
||||
/// @FUN{@FA{vertex}.pathTo(@FA{target_vertex})}
|
||||
/// @FUN{@FA{vertex}.pathTo(@FA{target_vertex}, @FA{options})}
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.pathTo = function (target_vertex) {
|
||||
var predecessors = {}; // { ID => [ID] }
|
||||
|
||||
predecessors = target_vertex.determinePredecessors(this.getId());
|
||||
Vertex.prototype.pathTo = function (target_vertex, options) {
|
||||
var predecessors = target_vertex.determinePredecessors(this.getId(), options || {});
|
||||
return target_vertex.pathesForTree(predecessors);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Helper function for pathTo
|
||||
/// @brief determine all the pathes to this node from source id
|
||||
///
|
||||
/// @FUN{@FA{vertex}.determinePredecessors(@FA{source_id})}
|
||||
/// @FUN{@FA{vertex}.determinePredecessors(@FA{source_id}, @FA{options})}
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.determinePredecessors = function (source_id) {
|
||||
Vertex.prototype.determinePredecessors = function (source_id, options) {
|
||||
var determined_list = [], // [ID]
|
||||
predecessors = {}, // { ID => [ID] }
|
||||
todo_list = [source_id], // [ID]
|
||||
|
@ -803,43 +813,54 @@ Vertex.prototype.determinePredecessors = function (source_id) {
|
|||
|
||||
while (todo_list.length > 0) {
|
||||
current_vertex_id = this._getShortestDistance(todo_list, distances);
|
||||
current_vertex = this._graph.getVertex(current_vertex_id);
|
||||
|
||||
if (current_vertex_id === this.getId()) {
|
||||
break;
|
||||
} else {
|
||||
todo_list.removeLastOccurrenceOf(current_vertex_id);
|
||||
determined_list.push(current_vertex_id);
|
||||
current_vertex = this._graph.getVertex(current_vertex_id);
|
||||
current_vertex.processNeighbors(
|
||||
|
||||
todo_list.merge(current_vertex._processNeighbors(
|
||||
determined_list,
|
||||
todo_list,
|
||||
distances,
|
||||
predecessors
|
||||
);
|
||||
predecessors,
|
||||
options
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return predecessors;
|
||||
};
|
||||
|
||||
Vertex.prototype.processNeighbors = function (determined_list, todo_list, distances, predecessors) {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Helper function for determinePredecessors (changes distance and predecessors
|
||||
///
|
||||
/// @FUN{@FA{vertex}._processNeighbors(@FA{determinedt}, @FA{distances}, @FA{predecessors})}
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype._processNeighbors = function (determined_list, distances, predecessors, options) {
|
||||
var i,
|
||||
current_neighbor_id,
|
||||
current_distance,
|
||||
raw_neighborlist,
|
||||
compared_distance;
|
||||
compared_distance,
|
||||
not_determined_neighbors = [];
|
||||
|
||||
// FIXME: Choose the neighbors according to the graph (directed/undirected)
|
||||
raw_neighborlist = this.getNeighbors('both');
|
||||
// FIXME: Choose the neighbors according to labels
|
||||
raw_neighborlist = this.getNeighbors(options.direction || 'both', options.labels);
|
||||
// console.log("Processing Neighbors for: " + this.getId());
|
||||
// console.log(raw_neighborlist);
|
||||
|
||||
for (i = 0; i < raw_neighborlist.length; i += 1) {
|
||||
current_neighbor_id = raw_neighborlist[i];
|
||||
|
||||
if (determined_list.lastIndexOf(current_neighbor_id) === -1) {
|
||||
// FIXME: Take the weight if it is a weighted graph
|
||||
// FIXME: Weights other than 1
|
||||
current_distance = distances[this.getId()] + 1;
|
||||
|
||||
todo_list.pushIfNotFound(current_neighbor_id);
|
||||
not_determined_neighbors.push(current_neighbor_id);
|
||||
|
||||
compared_distance = distances[current_neighbor_id];
|
||||
if ((compared_distance === undefined) || (compared_distance > current_distance)) {
|
||||
|
@ -850,6 +871,8 @@ Vertex.prototype.processNeighbors = function (determined_list, todo_list, distan
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return not_determined_neighbors;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -152,7 +152,7 @@ function dijkstraSuite() {
|
|||
graph.addEdge(v1, v2, 8, 'a');
|
||||
graph.addEdge(v1, v3, 9, 'b');
|
||||
|
||||
result_array = v1.getNeighbors('both', ['a']);
|
||||
result_array = v1.getNeighbors('both', ['a', 'c']);
|
||||
|
||||
assertEqual(result_array.length, 1);
|
||||
assertEqual(result_array[0], 2);
|
||||
|
@ -218,7 +218,72 @@ function dijkstraSuite() {
|
|||
assertEqual(path[0].toString(), v1.getId());
|
||||
assertEqual(path[1].toString(), v2.getId());
|
||||
assertEqual(path[2].toString(), v3.getId());
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a short, distinct path on a directed graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testGetADirectedDistinctPath : function () {
|
||||
var v1 = graph.addVertex(1),
|
||||
v2 = graph.addVertex(2),
|
||||
v3 = graph.addVertex(3),
|
||||
v4 = graph.addVertex(4),
|
||||
e1 = graph.addEdge(v1, v2),
|
||||
e2 = graph.addEdge(v2, v3),
|
||||
e3 = graph.addEdge(v3, v4),
|
||||
e4 = graph.addEdge(v4, v1),
|
||||
pathes = v1.pathTo(v3, {direction: "outbound"});
|
||||
|
||||
assertEqual(pathes.length, 1);
|
||||
assertEqual(pathes[0][0].toString(), v1.getId());
|
||||
assertEqual(pathes[0][1].toString(), v2.getId());
|
||||
assertEqual(pathes[0][2].toString(), v3.getId());
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a short, distinct path on a directed graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testGetADirectedLabeledPath : function () {
|
||||
var v1 = graph.addVertex(1),
|
||||
v2 = graph.addVertex(2),
|
||||
v3 = graph.addVertex(3),
|
||||
v4 = graph.addVertex(4),
|
||||
e1 = graph.addEdge(v1, v2, 5, "no"),
|
||||
e2 = graph.addEdge(v1, v3, 6, "yes"),
|
||||
e3 = graph.addEdge(v3, v4, 7, "yeah"),
|
||||
e4 = graph.addEdge(v4, v2, 8, "yes"),
|
||||
pathes = v1.pathTo(v2, { labels: ["yes", "yeah"] });
|
||||
|
||||
assertEqual(pathes.length, 1);
|
||||
assertEqual(pathes[0][0].toString(), v1.getId());
|
||||
assertEqual(pathes[0][1].toString(), v3.getId());
|
||||
assertEqual(pathes[0][2].toString(), v4.getId());
|
||||
assertEqual(pathes[0][3].toString(), v2.getId());
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a short, distinct path on a weighted graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*testGetADirectedWeightedPath : function () {
|
||||
var v1 = graph.addVertex(1),
|
||||
v2 = graph.addVertex(2),
|
||||
v3 = graph.addVertex(3),
|
||||
v4 = graph.addVertex(4),
|
||||
e1 = graph.addEdge(v1, v2, 5, "5", { my_weight: 5 }),
|
||||
e2 = graph.addEdge(v1, v3, 6, "6", { my_weight: 1 }),
|
||||
e3 = graph.addEdge(v3, v4, 7, "7", { my_weight: 1 }),
|
||||
e4 = graph.addEdge(v4, v1, 8, "8", { my_weight: 1 }),
|
||||
pathes = v1.pathTo(v2, { weight: "my_weight" });
|
||||
|
||||
assertEqual(pathes.length, 1);
|
||||
assertEqual(pathes[0][0].toString(), v1.getId());
|
||||
assertEqual(pathes[0][1].toString(), v3.getId());
|
||||
assertEqual(pathes[0][2].toString(), v4.getId());
|
||||
assertEqual(pathes[0][3].toString(), v2.getId());
|
||||
}*/
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue