Skip to content

Commit 597be29

Browse files
Addressing Veselin's comments and some bug fixing
Co-authored-by: Veselin Nikolov <veselin.nikolov@neotechnology.com>
1 parent 586b3f4 commit 597be29

File tree

2 files changed

+41
-31
lines changed

2 files changed

+41
-31
lines changed

algo/src/main/java/org/neo4j/gds/spanningtree/SpanningTree.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ public double costToParent(long nodeId) {
7474

7575
public void forEach(RelationshipWithPropertyConsumer consumer) {
7676
for (int i = 0; i < nodeCount; i++) {
77-
final long parent = this.parent.get(i);
78-
final double cost = this.costToParent(i);
77+
long parent = this.parent.get(i);
78+
double cost = this.costToParent(i);
7979
if (parent == -1) {
8080
continue;
8181
}

alpha/alpha-algo/src/main/java/org/neo4j/gds/impl/spanningtree/KSpanningTree.java

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ private HugeLongPriorityQueue createPriorityQueue(long parentSize, boolean pruni
9999

100100
@Override
101101
public void release() {
102+
graph.release();
102103
graph = null;
103104
}
104105

@@ -153,21 +154,22 @@ private SpanningTree cutLeafApproach(SpanningTree spanningTree) {
153154
for (long i = 0; i < numberOfDeletions; ++i) {
154155
var nextNode = priorityQueue.pop();
155156
long affectedNode;
156-
157-
if (nextNode == root) {
157+
158+
if (nextNode == root) { //the affecte node is its single child
158159
affectedNode = rootChild;
159160
totalCost -= rootCost;
160161
clearNode(rootChild, parent, costToParent);
162+
clearNode(root, parent, costToParent);
161163
root = affectedNode;
162-
} else {
164+
} else { //the affected node is its paret
163165
affectedNode = parent.get(nextNode);
164166
totalCost -= costToParent.get(nextNode);
165167
clearNode(nextNode, parent, costToParent);
166168
}
167169

168170
degree.set(affectedNode, degree.get(affectedNode) - 1);
169171
double associatedCost = -1;
170-
if (degree.get(affectedNode) == 1) {
172+
if (degree.get(affectedNode) == 1) { //it becomes a leaf
171173
if (affectedNode == root) {
172174
//if it is root, we loop at its neighbors to find its single alive child
173175
MutableDouble mutRootCost = new MutableDouble();
@@ -192,7 +194,7 @@ private SpanningTree cutLeafApproach(SpanningTree spanningTree) {
192194
progressTracker.logProgress();
193195
}
194196
progressTracker.endSubTask();
195-
return new SpanningTree(-1, graph.nodeCount(), k, parent, costToParent, totalCost);
197+
return new SpanningTree(root, graph.nodeCount(), k, parent, costToParent, totalCost);
196198
}
197199

198200
private SpanningTree growApproach(SpanningTree spanningTree) {
@@ -201,8 +203,6 @@ private SpanningTree growApproach(SpanningTree spanningTree) {
201203
//when it is about to get larger than K, we crop the current worst leaf if the new value to be added
202204
// is actually better
203205

204-
//TODO: Handle to be able to delete startNode as well (not much different from above approach)
205-
206206
HugeLongArray outDegree = HugeLongArray.newArray(graph.nodeCount());
207207

208208
HugeLongArray parent = HugeLongArray.newArray(graph.nodeCount());
@@ -213,11 +213,12 @@ private SpanningTree growApproach(SpanningTree spanningTree) {
213213
var priorityQueue = createPriorityQueue(graph.nodeCount(), false);
214214
var toTrim = createPriorityQueue(graph.nodeCount(), true);
215215

216-
//priority-queue does not have a remove method so we need something to know if a node is still a leaf or not
216+
//priority-queue does not have a remove method
217+
// so we need something to know if a node is still a leaf or not
217218
BitSet exterior = new BitSet(graph.nodeCount());
218219
//at any point, the tree has a root we mark its neighbors in this bitset to avoid looping to find them
219220
BitSet rootNodeAdjacent = new BitSet(graph.nodeCount());
220-
//we just save which nodes are in the final output and not (just to do clean-up; probably be avoided)
221+
//we just save which nodes are in the final output and not (just to do clean-up; probably can be avoided)
221222
BitSet included = new BitSet(graph.nodeCount());
222223

223224
priorityQueue.add(startNodeId, 0);
@@ -259,66 +260,75 @@ private SpanningTree growApproach(SpanningTree spanningTree) {
259260
clearNode(nodeToTrim, parent, costToParent);
260261
totalCost -= value; //as well as its cost from the solution
261262

262-
if (parentOfTrimmed != -1) { //we are not removing the actual root
263+
if (root != nodeToTrim) { //we are not removing the actual root
263264
//reduce degree of parent
264265
outDegree.set(parentOfTrimmed, outDegree.get(parentOfTrimmed) - 1);
265266
long affectedNode = -1;
266267
double affectedCost = -1;
267-
long parentDegree = outDegree.get(parentOfTrimmed);
268-
if (parentOfTrimmed == root) {
269-
rootNodeAdjacent.clear(nodeToTrim);
270-
if (parentDegree == 1) { //it is a leaf
268+
long parentOutDegree = outDegree.get(parentOfTrimmed);
269+
if (parentOfTrimmed == root) { //if its parent is the root
270+
rootNodeAdjacent.clear(nodeToTrim); //remove the trimmed child
271+
if (parentOutDegree == 1) { //root becomes a leaf
271272
assert rootNodeAdjacent.cardinality() == 1;
273+
//get the single sole child of root
272274
var rootChild = rootNodeAdjacent.nextSetBit(0);
273275
affectedNode = root;
274276
affectedCost = costToParent.get(rootChild);
275277
}
276278
} else {
277-
if (parentDegree == 0) {
279+
if (parentOutDegree == 0) { //if parent is a leaf
278280
affectedNode = parentOfTrimmed;
279281
affectedCost = costToParent.get(parentOfTrimmed);
280282
}
281283
}
282-
if (affectedNode != -1) {
283-
toTrim.add(affectedNode, affectedCost);
284-
exterior.set(affectedNode);
284+
if (affectedNode != -1) { //if a node has been converted to a leaf
285+
toTrim.add(affectedNode, affectedCost); //add it to pq
286+
exterior.set(affectedNode); //and mark it in the exterior
285287
}
286288
} else {
287289
//the root is removed, long live the new root!
288290
assert rootNodeAdjacent.cardinality() == 1;
291+
//the new root is the single sole child of old root
289292
var newRoot = rootNodeAdjacent.nextSetBit(0);
290293
rootNodeAdjacent.clear(); //empty everything
294+
//find the children of the new root (this can happen once per node)
291295
graph.forEachRelationship(newRoot, (s, t) -> {
292-
if (parent.get(t) == s) {
296+
//relevant are only those nodes which are currently
297+
//in the k-tree
298+
if (parent.get(t) == s && included.get(t)) {
293299
rootNodeAdjacent.set(t);
294300
}
295301
return true;
296302
});
297303
root = newRoot;
304+
//set it as root
298305
clearNode(root, parent, costToParent);
299-
//see if root is a degree-1 to add to exterior
306+
//check if root is a degree-1 to add to exterior
300307
if (outDegree.get(root) == 1) {
308+
//get single child
301309
var rootChild = rootNodeAdjacent.nextSetBit(0);
302-
priorityQueue.add(rootChild, costToParent.get(rootChild));
310+
priorityQueue.add(root, costToParent.get(rootChild));
303311
exterior.set(root);
304312
}
305313
}
306314
}
307315
}
308316
if (nodeAdded) {
309-
included.set(node);
310-
totalCost += associatedCost;
311-
if (nodeParent == root) {
317+
included.set(node); // include it in the solution (for now!)
318+
totalCost += associatedCost; //add its associated cost to the weight of tree
319+
if (nodeParent == root) { //if it's parent is the root, update the bitset
312320
rootNodeAdjacent.set(node);
313321
}
314-
if (node != root) {
322+
if (node != root) { //this only happens for startNode to be fair
323+
//the node's parent gets an update in degree
315324
outDegree.set(nodeParent, outDegree.get(nodeParent) + 1);
316-
exterior.clear(nodeParent);
325+
exterior.clear(nodeParent); //and remoed from exterior if included
317326
}
327+
//then the node (being a leaf) is added to the trimming priority queu
318328
toTrim.add(node, associatedCost);
319-
exterior.set(node);
329+
exterior.set(node); //and the exterior
320330

321-
graph.forEachRelationship(node, 1.0, (s, t, w) -> {
331+
graph.forEachRelationship(node, (s, t) -> {
322332
if (parent.get(t) == s) {
323333
//TODO: work's only on mst edges for now (should be doable to re-find an k-MST from whole graph)
324334
if (!priorityQueue.containsElement(t)) {
@@ -341,7 +351,7 @@ private SpanningTree growApproach(SpanningTree spanningTree) {
341351
return true;
342352
});
343353
progressTracker.endSubTask();
344-
return new SpanningTree(-1, graph.nodeCount(), k, parent, costToParent, totalCost);
354+
return new SpanningTree(root, graph.nodeCount(), k, parent, costToParent, totalCost);
345355

346356
}
347357

0 commit comments

Comments
 (0)