All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.amayaframework.di.graph.GraphUtil Maven / Gradle / Ivy

Go to download

A framework responsible for monitoring and automating the dependency injection process.

There is a newer version: 2.2.0
Show newest version
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