-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9463 from vnickolov/articulation-points
articulation points
- Loading branch information
Showing
51 changed files
with
2,798 additions
and
6 deletions.
There are no files selected for viewing
143 changes: 143 additions & 0 deletions
143
algo/src/main/java/org/neo4j/gds/articulationpoints/ArticulationPoints.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* | ||
* Copyright (c) "Neo4j" | ||
* Neo4j Sweden AB [http://neo4j.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.gds.articulationpoints; | ||
|
||
import com.carrotsearch.hppc.BitSet; | ||
import org.neo4j.gds.Algorithm; | ||
import org.neo4j.gds.api.Graph; | ||
import org.neo4j.gds.collections.ha.HugeLongArray; | ||
import org.neo4j.gds.collections.ha.HugeObjectArray; | ||
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker; | ||
|
||
public class ArticulationPoints extends Algorithm<BitSet> { | ||
private final Graph graph; | ||
|
||
private final BitSet visited; | ||
private final HugeLongArray tin; | ||
private final HugeLongArray low; | ||
private final HugeLongArray children; | ||
private long timer; | ||
private long stackIndex = -1; | ||
|
||
private final BitSet articulationPoints; | ||
|
||
public ArticulationPoints(Graph graph, ProgressTracker progressTracker) { | ||
super(progressTracker); | ||
|
||
this.graph = graph; | ||
|
||
this.visited = new BitSet(graph.nodeCount()); | ||
this.tin = HugeLongArray.newArray(graph.nodeCount()); | ||
this.low = HugeLongArray.newArray(graph.nodeCount()); | ||
this.children = HugeLongArray.newArray(graph.nodeCount()); | ||
|
||
this.articulationPoints = new BitSet(graph.nodeCount()); | ||
} | ||
|
||
@Override | ||
public BitSet compute() { | ||
timer = 0; | ||
visited.clear(); | ||
tin.setAll(__ -> -1); | ||
low.setAll(__ -> -1); | ||
progressTracker.beginSubTask("ArticulationPoints"); | ||
//each edge may have at most one event to the stack at the same time | ||
var stack = HugeObjectArray.newArray(StackEvent.class, graph.relationshipCount()); | ||
|
||
var n = graph.nodeCount(); | ||
for (int i = 0; i < n; ++i) { | ||
if (!visited.get(i)) { | ||
dfs(i, stack); | ||
} | ||
} | ||
progressTracker.endSubTask("ArticulationPoints"); | ||
return this.articulationPoints; | ||
} | ||
|
||
private void dfs(long node, HugeObjectArray<StackEvent> stack) { | ||
stack.set(++stackIndex, StackEvent.upcomingVisit(node,-1)); | ||
while (stackIndex >= 0) { | ||
var stackEvent = stack.get(stackIndex--); | ||
visitEvent(stackEvent, stack); | ||
} | ||
if (children.get(node) > 1) { | ||
articulationPoints.set(node); | ||
} else { | ||
articulationPoints.clear(node); | ||
} | ||
progressTracker.logProgress(); | ||
} | ||
|
||
private void visitEvent(StackEvent event, HugeObjectArray<StackEvent> stack) { | ||
if (event.lastVisit()) { | ||
var to = event.eventNode(); | ||
var v = event.triggerNode(); | ||
var lowV = low.get(v); | ||
var lowTo = low.get(to); | ||
low.set(v, Math.min(lowV, lowTo)); | ||
var tinV = tin.get(v); | ||
if (lowTo >= tinV) { | ||
articulationPoints.set(v); | ||
} | ||
children.addTo(v, 1); | ||
progressTracker.logProgress(); | ||
return; | ||
} | ||
|
||
if (!visited.get(event.eventNode())) { | ||
var v = event.eventNode(); | ||
visited.set(v); | ||
children.set(v, 0); | ||
var p = event.triggerNode(); | ||
tin.set(v, timer); | ||
low.set(v, timer++); | ||
///add post event (Should be before everything) | ||
if (p != -1) { | ||
stack.set(++stackIndex, StackEvent.lastVisit(v, p)); | ||
} | ||
graph.forEachRelationship(v, (s, to) -> { | ||
if (to == p) { | ||
return true; | ||
} | ||
stack.set(++stackIndex, StackEvent.upcomingVisit(to, v)); | ||
|
||
return true; | ||
}); | ||
|
||
} else { | ||
long v = event.triggerNode(); | ||
long to = event.eventNode(); | ||
var lowV = low.get(v); | ||
var tinTo = tin.get(to); | ||
low.set(v, Math.min(lowV, tinTo)); | ||
} | ||
} | ||
|
||
|
||
record StackEvent(long eventNode, long triggerNode, boolean lastVisit) { | ||
static StackEvent upcomingVisit(long node, long triggerNode) { | ||
return new StackEvent(node, triggerNode, false); | ||
} | ||
|
||
static StackEvent lastVisit(long node, long triggerNode) { | ||
return new StackEvent(node, triggerNode, true); | ||
} | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
algo/src/main/java/org/neo4j/gds/articulationpoints/ArticulationPointsBaseConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright (c) "Neo4j" | ||
* Neo4j Sweden AB [http://neo4j.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.gds.articulationpoints; | ||
|
||
import org.neo4j.gds.NodeLabel; | ||
import org.neo4j.gds.RelationshipType; | ||
import org.neo4j.gds.annotation.Configuration; | ||
import org.neo4j.gds.api.GraphStore; | ||
import org.neo4j.gds.config.AlgoBaseConfig; | ||
|
||
import java.util.Collection; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
import static org.neo4j.gds.utils.StringFormatting.formatWithLocale; | ||
|
||
public interface ArticulationPointsBaseConfig extends AlgoBaseConfig { | ||
|
||
@Configuration.GraphStoreValidationCheck | ||
default void requireUndirectedGraph( | ||
GraphStore graphStore, | ||
Collection<NodeLabel> ignored, | ||
Collection<RelationshipType> selectedRelationshipTypes | ||
) { | ||
if (!graphStore.schema().filterRelationshipTypes(Set.copyOf(selectedRelationshipTypes)).isUndirected()) { | ||
throw new IllegalArgumentException(formatWithLocale( | ||
"Articulation Points algorithm requires relationship projections to be UNDIRECTED. " + | ||
"Selected relationships `%s` are not all undirected.", | ||
selectedRelationshipTypes.stream().map(RelationshipType::name).collect(Collectors.toSet()) | ||
)); | ||
} | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
...ain/java/org/neo4j/gds/articulationpoints/ArticulationPointsMemoryEstimateDefinition.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright (c) "Neo4j" | ||
* Neo4j Sweden AB [http://neo4j.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.gds.articulationpoints; | ||
|
||
import org.neo4j.gds.bridges.Bridges; | ||
import org.neo4j.gds.collections.ha.HugeLongArray; | ||
import org.neo4j.gds.collections.ha.HugeObjectArray; | ||
import org.neo4j.gds.mem.Estimate; | ||
import org.neo4j.gds.mem.MemoryEstimateDefinition; | ||
import org.neo4j.gds.mem.MemoryEstimation; | ||
import org.neo4j.gds.mem.MemoryEstimations; | ||
import org.neo4j.gds.mem.MemoryRange; | ||
|
||
public class ArticulationPointsMemoryEstimateDefinition implements MemoryEstimateDefinition { | ||
@Override | ||
public MemoryEstimation memoryEstimation() { | ||
|
||
var builder = MemoryEstimations.builder(Bridges.class); | ||
builder | ||
.perNode("tin", HugeLongArray::memoryEstimation) | ||
.perNode("low", HugeLongArray::memoryEstimation) | ||
.perNode("children", HugeLongArray::memoryEstimation) | ||
.perNode("visited", Estimate::sizeOfBitset) | ||
.perNode("articulationPoints", Estimate::sizeOfBitset); | ||
|
||
builder.rangePerGraphDimension("stack", ((graphDimensions, concurrency) -> { | ||
long relationshipCount = graphDimensions.relCountUpperBound(); | ||
return MemoryRange.of( | ||
HugeObjectArray.memoryEstimation(relationshipCount, Estimate.sizeOfInstance(ArticulationPoints.StackEvent.class)) | ||
); | ||
|
||
|
||
})); | ||
|
||
return builder.build(); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
algo/src/main/java/org/neo4j/gds/articulationpoints/ArticulationPointsMutateConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright (c) "Neo4j" | ||
* Neo4j Sweden AB [http://neo4j.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.gds.articulationpoints; | ||
|
||
import org.neo4j.gds.annotation.Configuration; | ||
import org.neo4j.gds.config.MutateNodePropertyConfig; | ||
import org.neo4j.gds.core.CypherMapWrapper; | ||
|
||
import java.util.Map; | ||
|
||
@Configuration | ||
public interface ArticulationPointsMutateConfig extends ArticulationPointsBaseConfig, MutateNodePropertyConfig { | ||
static ArticulationPointsMutateConfig of(CypherMapWrapper cypherMapWrapper) { | ||
return new ArticulationPointsMutateConfigImpl(cypherMapWrapper); | ||
} | ||
|
||
static ArticulationPointsMutateConfig of(Map<String, Object> rawMapConfiguration) { | ||
return of(CypherMapWrapper.create(rawMapConfiguration)); | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
...src/main/java/org/neo4j/gds/articulationpoints/ArticulationPointsProgressTaskCreator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (c) "Neo4j" | ||
* Neo4j Sweden AB [http://neo4j.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.gds.articulationpoints; | ||
|
||
import org.neo4j.gds.core.utils.progress.tasks.Task; | ||
import org.neo4j.gds.core.utils.progress.tasks.Tasks; | ||
|
||
public final class ArticulationPointsProgressTaskCreator { | ||
|
||
private ArticulationPointsProgressTaskCreator() {} | ||
|
||
public static Task progressTask(long nodeCount) { | ||
return Tasks.leaf("ArticulationPoints", nodeCount); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
algo/src/main/java/org/neo4j/gds/articulationpoints/ArticulationPointsStatsConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright (c) "Neo4j" | ||
* Neo4j Sweden AB [http://neo4j.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.gds.articulationpoints; | ||
|
||
import org.neo4j.gds.annotation.Configuration; | ||
import org.neo4j.gds.core.CypherMapWrapper; | ||
|
||
import java.util.Map; | ||
|
||
@Configuration | ||
public interface ArticulationPointsStatsConfig extends ArticulationPointsBaseConfig { | ||
static ArticulationPointsStatsConfig of(CypherMapWrapper cypherMapWrapper) { | ||
return new ArticulationPointsStatsConfigImpl(cypherMapWrapper); | ||
} | ||
|
||
static ArticulationPointsStatsConfig of(Map<String, Object> rawMapConfiguration) { | ||
return of(CypherMapWrapper.create(rawMapConfiguration)); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
algo/src/main/java/org/neo4j/gds/articulationpoints/ArticulationPointsStreamConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright (c) "Neo4j" | ||
* Neo4j Sweden AB [http://neo4j.com] | ||
* | ||
* This file is part of Neo4j. | ||
* | ||
* Neo4j is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
package org.neo4j.gds.articulationpoints; | ||
|
||
import org.neo4j.gds.annotation.Configuration; | ||
import org.neo4j.gds.core.CypherMapWrapper; | ||
|
||
import java.util.Map; | ||
|
||
@Configuration | ||
public interface ArticulationPointsStreamConfig extends ArticulationPointsBaseConfig { | ||
static ArticulationPointsStreamConfig of(CypherMapWrapper cypherMapWrapper) { | ||
return new ArticulationPointsStreamConfigImpl(cypherMapWrapper); | ||
} | ||
|
||
static ArticulationPointsStreamConfig of(Map<String, Object> rawMapConfiguration) { | ||
return of(CypherMapWrapper.create(rawMapConfiguration)); | ||
} | ||
} |
Oops, something went wrong.