net.automatalib.util.graphs.traversal.GraphTraversal Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of automata-util Show documentation
Show all versions of automata-util Show documentation
This artifact provides various common utility operations for analyzing and manipulating
automata and graphs, such as traversal, minimization and copying.
/* 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 extends N> 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 extends N> initialNodes,
GraphTraversalVisitor vis) {
return traverse(order, graph, -1, initialNodes, vis);
}
public static
boolean breadthFirst(IndefiniteGraph graph, int limit, Collection extends N> 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 extends E> 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 extends N> 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 extends N> 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 extends N> initialNodes,
GraphTraversalVisitor vis) {
return depthFirst(graph, -1, initialNodes, vis);
}
public static
boolean dfs(IndefiniteGraph graph, int limit, Collection extends N> initialNodes, DFSVisitor super N, ? super E, D> visitor) {
GraphTraversalVisitor> traversalVisitor
= new DFSTraversalVisitor(graph, visitor);
return depthFirst(graph, limit, initialNodes, traversalVisitor);
}
public static
boolean dfs(IndefiniteGraph graph, N initialNode, DFSVisitor super N, ? super E, D> visitor) {
return dfs(graph, -1, Collections.singleton(initialNode), visitor);
}
public static
boolean dfs(IndefiniteGraph graph, Collection extends N> initialNodes, DFSVisitor super N, ? super E, D> visitor) {
return dfs(graph, -1, initialNodes, visitor);
}
public static Iterator bfIterator(IndefiniteGraph graph, Collection extends N> start) {
return new BreadthFirstIterator<>(graph, start);
}
public static Iterable breadthFirstOrder(
final IndefiniteGraph graph,
final Collection extends N> start) {
return new Iterable() {
@Override
public Iterator iterator() {
return bfIterator(graph, start);
}
};
}
public static Iterator dfIterator(IndefiniteGraph graph, Collection extends N> start) {
return new DepthFirstIterator<>(graph, start);
}
public static Iterable depthFirstOrder(
final IndefiniteGraph graph,
final Collection extends N> start) {
return new Iterable() {
@Override
public Iterator iterator() {
return dfIterator(graph, start);
}
};
}
private GraphTraversal() {} // prevent inheritance
}