@@ -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