io.github.amayaframework.di.graph.GraphUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of amaya-di Show documentation
Show all versions of amaya-di Show documentation
A framework responsible for monitoring and automating the dependency injection process.
package io.github.amayaframework.di.graph;
import java.util.*;
/**
* A utility class containing implementations of various operations on graphs.
*/
public final class GraphUtil {
private GraphUtil() {
}
private static List> graphToNodes(Graph graph) {
var ret = new LinkedList>();
var map = new HashMap>();
for (var node : graph) {
var t = new Node<>(node);
ret.add(t);
map.put(node, t);
}
for (var node : ret) {
var nodes = graph.getAdjacentNodes(node.value);
if (nodes == null || nodes.isEmpty()) {
node.adjacents = Collections.emptyList();
continue;
}
var adjacents = new ArrayList>();
nodes.forEach(e -> adjacents.add(map.get(e)));
node.adjacents = adjacents;
}
return ret;
}
private static List collectComponents(Node head, Deque> deque) {
var ret = new LinkedList();
var node = (Node) null;
do {
node = deque.pop();
node.onStack = false;
ret.add(node.value);
} while (node != head);
return ret;
}
private static int processNode(Node node, Deque> deque, List> components, int time) {
var stack = new LinkedList>();
stack.push(new Entry<>(node, 0));
while (!stack.isEmpty()) {
var entry = stack.pop();
var current = entry.node;
var local = entry.time;
var adjacents = current.adjacents;
if (local != 0) {
current.low = Math.min(current.low, adjacents.get(local - 1).low);
} else {
current.index = time;
current.low = time;
++time;
deque.push(current);
current.onStack = true;
}
var size = adjacents.size();
while (local < size && adjacents.get(local).index != -1) {
var w = adjacents.get(local);
if (w.onStack) {
current.low = Math.min(current.low, w.index);
}
++local;
}
if (local < size) {
var w = adjacents.get(local);
stack.push(new Entry<>(current, local + 1));
stack.push(new Entry<>(w, 0));
continue;
}
if (current.low != current.index) {
continue;
}
components.add(collectComponents(current, deque));
}
return time;
}
/**
* Searches for strongly connected components in the graph (cyclic connections).
* Uses Tarjan's iterative algorithm.
*
* @param graph the graph in which the search will be performed
* @param the type of nodes
* @return a list of lists containing found loops, or in other words, a list of strongly connected components
* @throws NullPointerException if graph is null
*/
public static List> findStronglyConnectedComponents(Graph graph) {
Objects.requireNonNull(graph);
var ret = new LinkedList>();
var nodes = graphToNodes(graph);
var time = 0;
var deque = new LinkedList>();
for (var node : nodes) {
if (node.index != -1) {
continue;
}
time = processNode(node, deque, ret, time);
}
return ret;
}
private static final class Node {
E value;
int index;
int low;
List> adjacents;
boolean onStack;
Node(E value) {
this.value = value;
this.index = -1;
this.low = -1;
}
}
private static final class Entry {
Node node;
int time;
Entry(Node node, int time) {
this.node = node;
this.time = time;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy