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

net.automatalib.util.graphs.traversal.GraphTraversal Maven / Gradle / Ivy

Go to download

This artifact provides various common utility operations for analyzing and manipulating automata and graphs, such as traversal, minimization and copying.

There is a newer version: 0.11.0
Show newest version
/* Copyright (C) 2013 TU Dortmund
 * This file is part of AutomataLib, http://www.automatalib.net/.
 * 
 * AutomataLib is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 3.0 as published by the Free Software Foundation.
 * 
 * AutomataLib 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
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with AutomataLib; if not, see
 * http://www.gnu.de/documents/lgpl.en.html.
 */
package net.automatalib.util.graphs.traversal;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.Queue;

import net.automatalib.commons.util.Holder;
import net.automatalib.graphs.IndefiniteGraph;
import net.automatalib.util.graphs.traversal.DFRecord.LastEdge;
import net.automatalib.util.traversal.TraversalOrder;


public abstract class GraphTraversal {
	
	
	public static 
	boolean traverse(TraversalOrder order,
			IndefiniteGraph graph, 
			int limit, 
			Collection initialNodes, 
			GraphTraversalVisitor vis) {
		switch(order) {
		case BREADTH_FIRST:
			return breadthFirst(graph, limit, initialNodes, vis);
		case DEPTH_FIRST:
			return depthFirst(graph, limit, initialNodes, vis);
		default:
			throw new IllegalArgumentException("Unknown traversal order " + order);
		}
	}
	
	public static 
	boolean traverse(TraversalOrder order,
			IndefiniteGraph graph,
			int limit,
			N initialNode,
			GraphTraversalVisitor vis) {
		return traverse(order, graph, limit, Collections.singleton(initialNode), vis);
	}
	
	public static 
	boolean traverse(TraversalOrder order,
			IndefiniteGraph graph,
			N initialNode,
			GraphTraversalVisitor vis) {
		return traverse(order, graph, -1, Collections.singleton(initialNode), vis);
	}
	
	public static 
	boolean traverse(TraversalOrder order,
			IndefiniteGraph graph,
			Collection initialNodes,
			GraphTraversalVisitor vis) {
		return traverse(order, graph, -1, initialNodes, vis);
	}
	
	
	public static 
	boolean breadthFirst(IndefiniteGraph graph, int limit, Collection initialNodes, GraphTraversalVisitor vis) {
		
		Queue> bfsQueue = new ArrayDeque>();
		
		// setting the following to false means that the traversal had to be aborted
		// due to reaching the limit
		boolean complete = true;
		int nodeCount = 0;
		
		Holder dataHolder = new Holder<>();
		
		for(N init : initialNodes) {
			dataHolder.value = null;
			GraphTraversalAction act = vis.processInitial(init, dataHolder);
				
			switch(act) {
			case IGNORE:
			case ABORT_NODE:
				continue;
			case ABORT_TRAVERSAL:
				return complete;
			case EXPLORE:
				if(nodeCount != limit) { // not equals will always be true for negative limit values
					bfsQueue.add(new BFRecord(init, dataHolder.value));
					nodeCount++;
				}
				else
					complete = false;
				break;
			}
		}
		
		
bfs_loop:
		while(!bfsQueue.isEmpty()) {
			BFRecord current = bfsQueue.poll();
			
			N currNode = current.node;
			D currData = current.data;
			
			if(!vis.startExploration(currNode, currData))
				continue;
			
			Collection edges = graph.getOutgoingEdges(currNode);

			
			for(E edge : edges) {
				
				N tgtNode = graph.getTarget(edge);
				
				dataHolder.value = null;
				GraphTraversalAction act = vis.processEdge(currNode, currData, edge, tgtNode, dataHolder);

				
				switch(act) {
				case IGNORE:
					continue;
				case ABORT_NODE:
					continue bfs_loop;
				case ABORT_TRAVERSAL:
					return complete;
				case EXPLORE:
					if(nodeCount != limit) { // not equals will always be true for negative limit values
						bfsQueue.offer(new BFRecord(tgtNode, dataHolder.value));
						nodeCount++;
					}
					else
						complete = false;
				}
			}
			
			vis.finishExploration(currNode, currData);
		}
		
		return complete;
	}
	
	public static 
	boolean breadthFirst(IndefiniteGraph graph, int limit, N initialNode, GraphTraversalVisitor visitor) {
		return breadthFirst(graph, limit, Collections.singleton(initialNode), visitor);
	}
	
	public static 
	boolean breadthFirst(IndefiniteGraph graph, Collection initialNodes, GraphTraversalVisitor visitor) {
		return breadthFirst(graph, -1, initialNodes, visitor);
	}
	
	public static 
	boolean breadthFirst(IndefiniteGraph graph, N initialNode, GraphTraversalVisitor visitor) {
		return breadthFirst(graph, -1, Collections.singleton(initialNode), visitor);
	}
	
	
	
	
	public static 
	boolean depthFirst(IndefiniteGraph graph, int limit, Collection initialNodes,
			GraphTraversalVisitor vis) {
		
		// setting the following to false means that the traversal had to be aborted
		// due to reaching the limit
		boolean complete = true;
		
		int nodeCount = 0;
			
		
		Deque> dfsStack
			= new ArrayDeque>();
		
		Holder dataHolder = new Holder<>();
		
		for(N init : initialNodes) {
			
			dataHolder.value = null;
			GraphTraversalAction act = vis.processInitial(init, dataHolder);
			
			switch(act) {
			case IGNORE:
			case ABORT_NODE:
				continue;
			case ABORT_TRAVERSAL:
				return complete;
			case EXPLORE:
				if(nodeCount != limit) {
					dfsStack.push(new DFRecord(init, dataHolder.value));
					nodeCount++;
				}
				else
					complete = false;
				break;
			}
		}
		
		
		while(!dfsStack.isEmpty()) {
			DFRecord current = dfsStack.peek();
			
			N currNode = current.node;
			D currData = current.data;
			
			if(current.start(graph)) {
				if(!vis.startExploration(currNode, currData)) {
					dfsStack.pop();
					continue;
				}
			}
			
			LastEdge lastEdge = current.getLastEdge();
			if(lastEdge != null) {
				vis.backtrackEdge(currNode, currData, lastEdge.edge,
						lastEdge.node, lastEdge.data);
			}
			
			if(!current.hasNextEdge()) {
				dfsStack.pop();
				vis.finishExploration(currNode, currData);
				continue;
			}
			
			E edge = current.nextEdge();
			
			N tgt = graph.getTarget(edge);
			
			GraphTraversalAction act = vis.processEdge(currNode, currData, edge, tgt, dataHolder);
			
			switch(act) {
			case IGNORE:
				continue;
			case ABORT_NODE:
				dfsStack.pop();
				continue;
			case ABORT_TRAVERSAL:
				return complete;
			case EXPLORE:
				if(nodeCount != limit) {
					D data = dataHolder.value;
					current.setLastEdge(edge, tgt, data);
					dfsStack.push(new DFRecord(tgt, data));
					nodeCount++;
				}
				else
					complete = false;
				break;
			}
		}
		
		return complete;
	}
	
	public static 
	boolean depthFirst(IndefiniteGraph graph, N initNode,
			GraphTraversalVisitor vis) {
		return depthFirst(graph, -1, initNode, vis);
	}
	
	public static 
	boolean depthFirst(IndefiniteGraph graph, int limit, N initNode,
			GraphTraversalVisitor vis) {
		return depthFirst(graph, Collections.singleton(initNode), vis);
	}
	
	public static 
	boolean depthFirst(IndefiniteGraph graph, Collection initialNodes,
			GraphTraversalVisitor vis) {
		return depthFirst(graph, -1, initialNodes, vis);
	}
	
	
	
	
	
	public static 
	boolean dfs(IndefiniteGraph graph, int limit, Collection initialNodes, DFSVisitor visitor) {
		GraphTraversalVisitor> traversalVisitor
			= new DFSTraversalVisitor(graph, visitor);
		return depthFirst(graph, limit, initialNodes, traversalVisitor);
	}
	
	public static 
	boolean dfs(IndefiniteGraph graph, N initialNode, DFSVisitor visitor) {
		return dfs(graph, -1, Collections.singleton(initialNode), visitor);
	}
	
	public static 
	boolean dfs(IndefiniteGraph graph, Collection initialNodes, DFSVisitor visitor) {
		return dfs(graph, -1, initialNodes, visitor);
	}
	
	
	public static  Iterator bfIterator(IndefiniteGraph graph, Collection start) {
		return new BreadthFirstIterator<>(graph, start);
	}
	
	public static  Iterable breadthFirstOrder(
			final IndefiniteGraph graph,
			final Collection start) {
		
		return new Iterable() {
			@Override
			public Iterator iterator() {
				return bfIterator(graph, start);
			}
		};
	}
	
	public static  Iterator dfIterator(IndefiniteGraph graph, Collection start) {
		return new DepthFirstIterator<>(graph, start);
	}
	
	public static  Iterable depthFirstOrder(
			final IndefiniteGraph graph,
			final Collection start) {
		
		return new Iterable() {
			@Override
			public Iterator iterator() {
				return dfIterator(graph, start);
			}
		};
	}
	
	private GraphTraversal() {} // prevent inheritance

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy