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

openllet.reachability.SCC Maven / Gradle / Ivy

package openllet.reachability;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import openllet.core.utils.SetUtils;

/**
 * @author Evren Sirin
 */
public class SCC
{

	private SCC()
	{
		// No instance allow.
	}

	/**
	 * Computes the strongly connected components of a graph. This implementation is based on Tarjan's algorithm
	 */
	public static  List>> computeSCC(final ReachabilityGraph graph)
	{
		return new SCCComputer().computeSCC(graph);
	}

	/*
	 * Simple structure to keep track of info for _nodes.
	 */
	private static class NodeInfo
	{
		private final Node _node;

		private int _index;

		private int _lowlink;

		private boolean _onStack;

		private NodeInfo(final Node n)
		{
			_node = n;
			_index = -1;
			_lowlink = -1;
			_onStack = false;
		}

		@Override
		public String toString()
		{
			return _node.toString();
		}

		public boolean isEntityNode()
		{
			return _node.isEntityNode();
		}

		public  EntityNode asEntityNode()
		{
			return _node.asEntityNode();
		}

	}

	private static class SCCComputer
	{

		private final List>> _stronglyConnectedComponents = new ArrayList<>();

		private int _index;

		private ArrayList _stack;

		private final Map _nodeInfos = new ConcurrentHashMap<>();

		public List>> computeSCC(final ReachabilityGraph graph)
		{
			final Collection> nodes = graph.getEntityNodes();
			for (final Node node : nodes)
			{
				if (_nodeInfos.containsKey(node))
					continue;

				computeSCC(node);
			}

			return _stronglyConnectedComponents;
		}

		private void computeSCC(final Node node)
		{
			_index = 0;
			_stack = new ArrayList<>();
			visit(new NodeInfo(node));
		}

		private void visit(final NodeInfo nodeInfo)
		{
			_nodeInfos.put(nodeInfo._node, nodeInfo);
			nodeInfo._index = _index;
			nodeInfo._lowlink = _index;
			_index = _index + 1;

			_stack.add(nodeInfo);
			nodeInfo._onStack = true;

			for (final Node out : nodeInfo._node.getOutputs())
			{
				// ignore AndNodes because connectivity through AndNode does not
				// necessarily mean equivalent modules
				if (out instanceof AndNode)
					continue;

				NodeInfo outInfo = _nodeInfos.get(out);
				if (outInfo == null)
				{
					outInfo = new NodeInfo(out);
					visit(outInfo);
					nodeInfo._lowlink = Math.min(nodeInfo._lowlink, outInfo._lowlink);
				}
				else
					if (outInfo._onStack)
						nodeInfo._lowlink = Math.min(nodeInfo._lowlink, outInfo._index);
			}

			if (nodeInfo._lowlink == nodeInfo._index)
			{
				final Set> connectedComponent = SetUtils.create();

				int i = _stack.size() - 1;
				NodeInfo info = null;
				while (info != nodeInfo)
				{
					info = _stack.get(i);
					info._onStack = false;
					// do not include OrNodes in the component
					if (info.isEntityNode())
						connectedComponent.add(info.asEntityNode());
					i--;
				}

				// ignore if the component was a singleton OrNode
				if (connectedComponent.size() > 0)
					_stronglyConnectedComponents.add(connectedComponent);
				_stack.subList(i + 1, _stack.size()).clear();
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy