Skip to content

Commit 3091f91

Browse files
Refactor MutablePathResult
Co-authored-by: Veselin Nikolov <[email protected]>
1 parent 7f578ce commit 3091f91

File tree

3 files changed

+47
-14
lines changed

3 files changed

+47
-14
lines changed

algo/src/main/java/org/neo4j/gds/paths/yens/MutablePathResult.java

+36-9
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ boolean matchesExactly(MutablePathResult path, int index) {
134134
if (relationshipIds.length == 0 || path.relationshipIds.length == 0) {
135135
return matches(path, index);
136136
}
137-
//System.out.println(Arrays.toString(Arrays.stream(relationshipIds).toArray()));
138137
for (int i = 0; i < index; i++) {
139138
if (nodeIds[i] != path.nodeIds[i]) {
140139
return false;
@@ -157,7 +156,9 @@ boolean matchesExactly(MutablePathResult path, int index) {
157156
* The cost value associated with the last value in this path, is added to
158157
* the costs for each node in the second path.
159158
*/
160-
void append(MutablePathResult path, boolean shouldstore) {
159+
160+
161+
private void append(MutablePathResult path, long[] relationships) {
161162
// spur node is end of first and beginning of second path
162163
assert nodeIds[nodeIds.length - 1] == path.nodeIds[0];
163164

@@ -166,15 +167,10 @@ void append(MutablePathResult path, boolean shouldstore) {
166167
var newNodeIds = new long[oldLength + path.nodeIds.length - 1];
167168
var newCosts = new double[oldLength + path.nodeIds.length - 1];
168169

169-
var oldRelationshipIdsLength = relationshipIds.length;
170-
var newRelationshipIds = new long[oldRelationshipIdsLength + path.relationshipIds.length];
171-
172170
// copy node ids
173171
System.arraycopy(this.nodeIds, 0, newNodeIds, 0, oldLength);
174172
System.arraycopy(path.nodeIds, 1, newNodeIds, oldLength, path.nodeIds.length - 1);
175-
// copy relationship ids
176-
System.arraycopy(this.relationshipIds, 0, newRelationshipIds, 0, oldRelationshipIdsLength);
177-
System.arraycopy(path.relationshipIds, 0, newRelationshipIds, oldRelationshipIdsLength, path.relationshipIds.length);
173+
178174
// copy costs
179175
System.arraycopy(this.costs, 0, newCosts, 0, oldLength);
180176
System.arraycopy(path.costs, 1, newCosts, oldLength, path.costs.length - 1);
@@ -186,10 +182,41 @@ void append(MutablePathResult path, boolean shouldstore) {
186182
}
187183

188184
this.nodeIds = newNodeIds;
189-
this.relationshipIds = shouldstore ? newRelationshipIds : new long[0];
185+
this.relationshipIds = relationships;
190186
this.costs = newCosts;
191187
}
192188

189+
void append(MutablePathResult path) {
190+
191+
var oldRelationshipIdsLength = relationshipIds.length;
192+
var newRelationshipIds = new long[oldRelationshipIdsLength + path.relationshipIds.length];
193+
// copy relationship ids
194+
System.arraycopy(this.relationshipIds, 0, newRelationshipIds, 0, oldRelationshipIdsLength);
195+
System.arraycopy(
196+
path.relationshipIds,
197+
0,
198+
newRelationshipIds,
199+
oldRelationshipIdsLength,
200+
path.relationshipIds.length
201+
);
202+
203+
append(path, newRelationshipIds);
204+
}
205+
206+
/**
207+
* Appends the given path to this path without creating an explicit relationship array.
208+
*
209+
* The last node in this path, must match the first node in the given path.
210+
* This node will only appear once in the resulting path.
211+
* The cost value associated with the last value in this path, is added to
212+
* the costs for each node in the second path.
213+
*/
214+
void appendWithoutRelationshipIds(MutablePathResult path) {
215+
// spur node is end of first and beginning of second path
216+
append(path, new long[0]);
217+
}
218+
219+
193220
@Override
194221
public boolean equals(Object o) {
195222
if (this == o) return true;

algo/src/main/java/org/neo4j/gds/paths/yens/Yens.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.Comparator;
4040
import java.util.Optional;
4141
import java.util.PriorityQueue;
42+
import java.util.function.BiConsumer;
4243
import java.util.function.ToLongBiFunction;
4344
import java.util.stream.Stream;
4445

@@ -55,6 +56,8 @@ public final class Yens extends Algorithm<DijkstraResult> {
5556
private final LongObjectScatterMap<LongHashSet> relationshipAvoidList;
5657
private final ToLongBiFunction
5758
<MutablePathResult, Integer> relationshipAvoidMapper;
59+
private final BiConsumer<MutablePathResult, PathResult> pathAppender;
60+
5861

5962
/**
6063
* Configure Yens to compute at most one source-target shortest path.
@@ -109,10 +112,12 @@ private Yens(Graph graph, Dijkstra dijkstra, ShortestPathYensBaseConfig config,
109112
// if we are in a multi-graph, we must store the relationships ids as they are
110113
//since two nodes may be connected by multiple relationships and we must know which to avoid
111114
relationshipAvoidMapper = (path, position) -> path.relationship(position);
115+
pathAppender = (rootPath, spurPath) -> rootPath.append(MutablePathResult.of(spurPath));
112116
} else {
113117
//otherwise the graph has surely no parallel edges, we do not need to explicitly store relationship ids
114118
//we can just store endpoints, so that we know which nodes a node should avoid
115119
relationshipAvoidMapper = (path, position) -> path.node(position + 1);
120+
pathAppender = (rootPath, spurPath) -> rootPath.appendWithoutRelationshipIds(MutablePathResult.of(spurPath));
116121
}
117122
dijkstra.withRelationshipFilter((source, target, relationshipId) ->
118123
!nodeAvoidList.contains(target)
@@ -196,7 +201,8 @@ public DijkstraResult compute() {
196201
}
197202

198203
// Entire path is made up of the root path and spur path.
199-
rootPath.append(MutablePathResult.of(spurPath.get()), graph.isMultiGraph());
204+
pathAppender.accept(rootPath, spurPath.get());
205+
200206
// Add the potential k-shortest path to the heap.
201207
if (!candidates.contains(rootPath)) {
202208
candidates.add(rootPath);
@@ -214,7 +220,7 @@ public DijkstraResult compute() {
214220
progressTracker.endSubTask();
215221

216222
progressTracker.endSubTask();
217-
223+
218224
return new DijkstraResult(kShortestPaths.stream().map(MutablePathResult::toPathResult));
219225
}
220226

algo/src/test/java/org/neo4j/gds/paths/yens/MutablePathResultTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ void append() {
170170
var path1 = testPath(0, 1, 2);
171171
var path2 = testPath(2, 3, 4);
172172

173-
path1.append(path2, true);
173+
path1.append(path2);
174174
var expected = testPath(0, 1, 2, 3, 4);
175175

176176
assertEquals(expected, path1);
@@ -184,7 +184,7 @@ void appendWithOffset() {
184184
var expected = MutablePathResult.of(ImmutablePathResult.builder().nodeIds(0, 1, 2, 3, 4).relationshipIds(0, 1, 2, 3).costs(0, 1, 42, 55, 79).sourceNode(0).targetNode(2).index(2).build());
185185
//@formatter:on
186186

187-
p1.append(p2, true);
187+
p1.append(p2);
188188

189189
assertEquals(expected, p1);
190190
assertEquals(expected.totalCost(), p1.totalCost());
@@ -195,6 +195,6 @@ void appendFailedAssertion() {
195195
var path1 = testPath(0, 1, 2);
196196
var path2 = testPath(4, 3, 5);
197197

198-
assertThatThrownBy(() -> path1.append(path2, true)).isInstanceOf(AssertionError.class);
198+
assertThatThrownBy(() -> path1.append(path2)).isInstanceOf(AssertionError.class);
199199
}
200200
}

0 commit comments

Comments
 (0)