mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
method to compute graph of strongly connected components moved to service
This commit is contained in:
@@ -27,12 +27,7 @@ import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.Chunk;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.graph.CachingSemiGraph;
|
||||
import com.intellij.util.graph.DFSTBuilder;
|
||||
import com.intellij.util.graph.Graph;
|
||||
import com.intellij.util.graph.GraphGenerator;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import gnu.trove.TIntProcedure;
|
||||
import com.intellij.util.graph.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
@@ -92,47 +87,7 @@ public final class ModuleCompilerUtil {
|
||||
}
|
||||
|
||||
public static <Node> Graph<Chunk<Node>> toChunkGraph(final Graph<Node> graph) {
|
||||
final DFSTBuilder<Node> builder = new DFSTBuilder<Node>(graph);
|
||||
final TIntArrayList sccs = builder.getSCCs();
|
||||
|
||||
final List<Chunk<Node>> chunks = new ArrayList<Chunk<Node>>(sccs.size());
|
||||
final Map<Node, Chunk<Node>> nodeToChunkMap = new LinkedHashMap<Node, Chunk<Node>>();
|
||||
sccs.forEach(new TIntProcedure() {
|
||||
int myTNumber = 0;
|
||||
public boolean execute(int size) {
|
||||
final Set<Node> chunkNodes = new LinkedHashSet<Node>();
|
||||
final Chunk<Node> chunk = new Chunk<Node>(chunkNodes);
|
||||
chunks.add(chunk);
|
||||
for (int j = 0; j < size; j++) {
|
||||
final Node node = builder.getNodeByTNumber(myTNumber + j);
|
||||
chunkNodes.add(node);
|
||||
nodeToChunkMap.put(node, chunk);
|
||||
}
|
||||
|
||||
myTNumber += size;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<Chunk<Node>>() {
|
||||
public Collection<Chunk<Node>> getNodes() {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
public Iterator<Chunk<Node>> getIn(Chunk<Node> chunk) {
|
||||
final Set<Node> chunkNodes = chunk.getNodes();
|
||||
final Set<Chunk<Node>> ins = new LinkedHashSet<Chunk<Node>>();
|
||||
for (final Node node : chunkNodes) {
|
||||
for (Iterator<Node> nodeIns = graph.getIn(node); nodeIns.hasNext();) {
|
||||
final Node in = nodeIns.next();
|
||||
if (!chunk.containsNode(in)) {
|
||||
ins.add(nodeToChunkMap.get(in));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ins.iterator();
|
||||
}
|
||||
}));
|
||||
return GraphAlgorithms.getInstance().computeSCCGraph(graph);
|
||||
}
|
||||
|
||||
public static void sortModules(final Project project, final List<Module> modules) {
|
||||
|
||||
+6
@@ -17,6 +17,8 @@ package com.intellij.util.graph;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.util.Chunk;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -46,4 +48,8 @@ public abstract class GraphAlgorithms {
|
||||
|
||||
@NotNull
|
||||
public abstract <Node> Graph<Node> invertEdgeDirections(@NotNull Graph<Node> graph);
|
||||
|
||||
public abstract <Node> Graph<Chunk<Node>> computeSCCGraph(final Graph<Node> graph);
|
||||
|
||||
public abstract <Node> Graph<Node> createGraphByInArcs(MultiMap<Node, Node> inArcs);
|
||||
}
|
||||
@@ -16,8 +16,11 @@
|
||||
package com.intellij.util.graph.impl;
|
||||
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.util.graph.Graph;
|
||||
import com.intellij.util.graph.GraphAlgorithms;
|
||||
import com.intellij.util.Chunk;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.graph.*;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import gnu.trove.TIntProcedure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@@ -63,6 +66,69 @@ public class GraphAlgorithmsImpl extends GraphAlgorithms {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Node> Graph<Chunk<Node>> computeSCCGraph(final Graph<Node> graph) {
|
||||
final DFSTBuilder<Node> builder = new DFSTBuilder<Node>(graph);
|
||||
final TIntArrayList sccs = builder.getSCCs();
|
||||
|
||||
final List<Chunk<Node>> chunks = new ArrayList<Chunk<Node>>(sccs.size());
|
||||
final Map<Node, Chunk<Node>> nodeToChunkMap = new LinkedHashMap<Node, Chunk<Node>>();
|
||||
sccs.forEach(new TIntProcedure() {
|
||||
int myTNumber = 0;
|
||||
public boolean execute(int size) {
|
||||
final Set<Node> chunkNodes = new LinkedHashSet<Node>();
|
||||
final Chunk<Node> chunk = new Chunk<Node>(chunkNodes);
|
||||
chunks.add(chunk);
|
||||
for (int j = 0; j < size; j++) {
|
||||
final Node node = builder.getNodeByTNumber(myTNumber + j);
|
||||
chunkNodes.add(node);
|
||||
nodeToChunkMap.put(node, chunk);
|
||||
}
|
||||
|
||||
myTNumber += size;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<Chunk<Node>>() {
|
||||
public Collection<Chunk<Node>> getNodes() {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
public Iterator<Chunk<Node>> getIn(Chunk<Node> chunk) {
|
||||
final Set<Node> chunkNodes = chunk.getNodes();
|
||||
final Set<Chunk<Node>> ins = new LinkedHashSet<Chunk<Node>>();
|
||||
for (final Node node : chunkNodes) {
|
||||
for (Iterator<Node> nodeIns = graph.getIn(node); nodeIns.hasNext(); ) {
|
||||
final Node in = nodeIns.next();
|
||||
if (!chunk.containsNode(in)) {
|
||||
ins.add(nodeToChunkMap.get(in));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ins.iterator();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Node> Graph<Node> createGraphByInArcs(final MultiMap<Node, Node> inArcs) {
|
||||
final Set<Node> nodes = new LinkedHashSet<Node>();
|
||||
nodes.addAll(inArcs.keySet());
|
||||
nodes.addAll(inArcs.values());
|
||||
return new GraphGenerator<Node>(new CachingSemiGraph<Node>(new GraphGenerator.SemiGraph<Node>() {
|
||||
@Override
|
||||
public Collection<Node> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Node> getIn(Node n) {
|
||||
return inArcs.get(n).iterator();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <Node> List<List<Node>> removePathsWithCycles(@NotNull List<List<Node>> paths) {
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.util.graph;
|
||||
|
||||
import com.intellij.util.Chunk;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: Sep 27, 2004
|
||||
*/
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
public class ChunkGraphTest extends GraphTestCase {
|
||||
|
||||
public void testGraph1() {
|
||||
final Map<String, String> arcs = new HashMap<String, String>();
|
||||
arcs.put("a", "b");
|
||||
arcs.put("b", "c");
|
||||
arcs.put("c", "bd");
|
||||
arcs.put("d", "e");
|
||||
arcs.put("e", "d");
|
||||
|
||||
final Graph<Chunk<String>> graph = getAlgorithmsInstance().computeSCCGraph(initGraph(arcs));
|
||||
|
||||
final List<Chunk<String>> expectedNodes = new ArrayList<Chunk<String>>();
|
||||
Chunk<String> A = new Chunk<String>("a");
|
||||
expectedNodes.add(A);
|
||||
Chunk<String> BC = new Chunk<String>(toSet("b", "c"));
|
||||
expectedNodes.add(BC);
|
||||
Chunk<String> DE = new Chunk<String>(toSet("d", "e"));
|
||||
expectedNodes.add(DE);
|
||||
|
||||
checkVertices(expectedNodes, graph.getNodes().iterator());
|
||||
|
||||
final Map<Chunk<String>, Set<Chunk<String>>> expectedArcs = new HashMap<Chunk<String>, Set<Chunk<String>>>();
|
||||
expectedArcs.put(A, toSet());
|
||||
expectedArcs.put(BC, toSet(A));
|
||||
expectedArcs.put(DE, toSet(BC));
|
||||
|
||||
checkArcs(expectedArcs, graph);
|
||||
}
|
||||
|
||||
public void testGraph2() {
|
||||
final Map<String, String> arcs = new HashMap<String, String>();
|
||||
arcs.put("a", "b");
|
||||
arcs.put("b", "ac");
|
||||
arcs.put("c", "ad");
|
||||
arcs.put("d", "");
|
||||
|
||||
final Graph<Chunk<String>> graph = getAlgorithmsInstance().computeSCCGraph(initGraph(arcs));
|
||||
|
||||
final List<Chunk<String>> expectedNodes = new ArrayList<Chunk<String>>();
|
||||
Chunk<String> ABC = new Chunk<String>(toSet("a", "b", "c"));
|
||||
expectedNodes.add(ABC);
|
||||
Chunk<String> D = new Chunk<String>("d");
|
||||
expectedNodes.add(D);
|
||||
|
||||
checkVertices(expectedNodes, graph.getNodes().iterator());
|
||||
|
||||
final Map<Chunk<String>, Set<Chunk<String>>> expectedArcs = new HashMap<Chunk<String>, Set<Chunk<String>>>();
|
||||
expectedArcs.put(ABC, toSet());
|
||||
expectedArcs.put(D, toSet(ABC));
|
||||
|
||||
checkArcs(expectedArcs, graph);
|
||||
}
|
||||
|
||||
private static void checkArcs(Map<Chunk<String>, Set<Chunk<String>>> expectedArcs, Graph<Chunk<String>> graph) {
|
||||
for (Chunk<String> chunk : graph.getNodes()) {
|
||||
final List<Chunk<String>> ins = new ArrayList<Chunk<String>>();
|
||||
final Iterator<Chunk<String>> insIterator = graph.getIn(chunk);
|
||||
while (insIterator.hasNext()) {
|
||||
ins.add(insIterator.next());
|
||||
}
|
||||
final Set<Chunk<String>> expectedIns = expectedArcs.get(chunk);
|
||||
assertTrue(expectedIns.size() == ins.size());
|
||||
assertTrue(expectedIns.equals(new HashSet<Chunk<String>>(ins)));
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> Set<T> toSet(T... strings) {
|
||||
return new HashSet<T>(Arrays.asList(strings));
|
||||
}
|
||||
|
||||
private static Set<Chunk<String>> toSet() {
|
||||
return new HashSet<Chunk<String>>();
|
||||
}
|
||||
|
||||
private static Set<Chunk<String>> toSet(Chunk<String> c) {
|
||||
return Collections.singleton(c);
|
||||
}
|
||||
|
||||
|
||||
private static void checkVertices(List<Chunk<String>> expected, Iterator<Chunk<String>> nodes) {
|
||||
List<Chunk<String>> realNodes = new ArrayList<Chunk<String>>();
|
||||
while (nodes.hasNext()) {
|
||||
realNodes.add(nodes.next());
|
||||
}
|
||||
assertTrue(expected.size() == realNodes.size());
|
||||
assertTrue(new HashSet<Chunk<String>>(expected).equals(new HashSet<Chunk<String>>(realNodes)));
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.util.graph;
|
||||
|
||||
import com.intellij.util.graph.impl.GraphAlgorithmsImpl;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.*;
|
||||
@@ -23,6 +24,10 @@ import java.util.*;
|
||||
* @author nik
|
||||
*/
|
||||
public abstract class GraphTestCase extends TestCase {
|
||||
protected static GraphAlgorithmsImpl getAlgorithmsInstance() {
|
||||
return new GraphAlgorithmsImpl();
|
||||
}
|
||||
|
||||
protected static Graph<String> initGraph(final Map<String, String> graph) {
|
||||
final Map<String, List<String>> out = new HashMap<String, List<String>>();
|
||||
final Map<String, List<String>> in = new HashMap<String, List<String>>();
|
||||
|
||||
+1
-2
@@ -150,8 +150,7 @@ public class KShortestPathsFinderTest extends GraphTestCase {
|
||||
|
||||
private static void doTest(Map<String, String> graph, final String start, final String finish, final int k, String... expectedPaths) {
|
||||
final Graph<String> generator = initGraph(graph);
|
||||
final KShortestPathsFinder<String> finder = new KShortestPathsFinder<String>(generator, start, finish, new EmptyProgressIndicator());
|
||||
final List<List<String>> paths = finder.findShortestPaths(k);
|
||||
final List<List<String>> paths = getAlgorithmsInstance().findKShortestPaths(generator, start, finish, k, new EmptyProgressIndicator());
|
||||
List<String> pathStrings = new ArrayList<String>();
|
||||
Set<Integer> sizes = new HashSet<Integer>();
|
||||
for (List<String> path : paths) {
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package com.intellij.util.graph;
|
||||
|
||||
import com.intellij.util.graph.impl.CycleFinder;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.testFramework.UsefulTestCase;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
@@ -81,8 +83,7 @@ public class SearchCyclesTest extends GraphTestCase {
|
||||
}
|
||||
|
||||
private static void doTest(HashMap<String, String> graph, final String node, String... expected) {
|
||||
Graph<String> stringGraph = initGraph(graph);
|
||||
final Set<List<String>> nodeCycles = new CycleFinder<String>(stringGraph).getNodeCycles(node);
|
||||
final Set<List<String>> nodeCycles = getAlgorithmsInstance().findCycles(initGraph(graph), node);
|
||||
checkResult(expected, nodeCycles);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.intellij.util.graph;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.graph.impl.ShortestPathFinder;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -90,7 +89,6 @@ public class ShortestPathTest extends GraphTestCase {
|
||||
|
||||
@Nullable
|
||||
private static List<String> getShortestPath(Map<String, String> graph, final String from, final String to) {
|
||||
Graph<String> graphGenerator = initGraph(graph);
|
||||
return new ShortestPathFinder<String>(graphGenerator).findPath(from, to);
|
||||
return getAlgorithmsInstance().findShortestPath(initGraph(graph), from, to);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user