net.automatalib.util.ts.traversal.TSTraversal 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-2019 TU Dortmund
* This file is part of AutomataLib, http://www.automatalib.net/.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.automatalib.util.ts.traversal;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import net.automatalib.commons.util.Holder;
import net.automatalib.ts.TransitionSystem;
import net.automatalib.util.traversal.TraversalOrder;
/**
* @author Malte Isberner
*/
public final class TSTraversal {
public static final int NO_LIMIT = -1;
private TSTraversal() {
}
public static boolean depthFirst(TransitionSystem ts,
Collection extends I> inputs,
TSTraversalVisitor vis) {
return depthFirst(ts, NO_LIMIT, inputs, vis);
}
public static boolean depthFirst(TransitionSystem ts,
int limit,
Collection extends I> inputs,
TSTraversalVisitor vis) {
Deque> dfsStack = new ArrayDeque<>();
Holder dataHolder = new Holder<>();
// setting the following to false means that the traversal had to be aborted
// due to reaching the limit
boolean complete = true;
int stateCount = 0;
for (S initS : ts.getInitialStates()) {
dataHolder.value = null;
TSTraversalAction act = vis.processInitial(initS, dataHolder);
switch (act) {
case ABORT_INPUT:
case ABORT_STATE:
case IGNORE:
continue;
case ABORT_TRAVERSAL:
return complete;
case EXPLORE:
if (stateCount != limit) {
dfsStack.push(new DFRecord<>(initS, inputs, dataHolder.value));
stateCount++;
} else {
complete = false;
}
break;
default:
throw new IllegalStateException("Unknown action " + act);
}
}
while (!dfsStack.isEmpty()) {
DFRecord current = dfsStack.peek();
S source = current.state;
D data = current.data;
if (current.start(ts)) {
if (!vis.startExploration(source, data)) {
dfsStack.pop();
continue;
}
}
if (!current.hasNextTransition(ts)) {
dfsStack.pop();
continue;
}
I input = current.input();
T trans = current.transition();
S succ = ts.getSuccessor(trans);
dataHolder.value = null;
TSTraversalAction act = vis.processTransition(source, data, input, trans, succ, dataHolder);
switch (act) {
case ABORT_INPUT:
current.advanceInput(ts);
break;
case ABORT_STATE:
dfsStack.pop();
break;
case ABORT_TRAVERSAL:
return complete;
case IGNORE:
current.advance(ts);
break;
case EXPLORE:
if (stateCount != limit) {
dfsStack.push(new DFRecord<>(succ, inputs, dataHolder.value));
stateCount++;
} else {
complete = false;
}
break;
default:
throw new IllegalStateException("Unknown action " + act);
}
}
return complete;
}
public static boolean breadthFirst(TransitionSystem ts,
Collection extends I> inputs,
TSTraversalVisitor vis) {
return breadthFirst(ts, NO_LIMIT, inputs, vis);
}
/**
* Traverses the given transition system in a breadth-first fashion. The traversal is steered by the specified
* visitor.
*
* @param ts
* the transition system.
* @param inputs
* the input alphabet.
* @param vis
* the visitor.
*/
public static boolean breadthFirst(TransitionSystem ts,
int limit,
Collection extends I> inputs,
TSTraversalVisitor vis) {
Deque> 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 stateCount = 0;
Holder dataHolder = new Holder<>();
for (S initS : ts.getInitialStates()) {
dataHolder.value = null;
TSTraversalAction act = vis.processInitial(initS, dataHolder);
switch (act) {
case ABORT_TRAVERSAL:
return complete;
case EXPLORE:
if (stateCount != limit) {
bfsQueue.offer(new BFSRecord<>(initS, dataHolder.value));
stateCount++;
} else {
complete = false;
}
break;
default: // case ABORT_INPUT: case ABORT_STATE: case IGNORE:
}
}
while (!bfsQueue.isEmpty()) {
BFSRecord current = bfsQueue.poll();
S state = current.state;
D data = current.data;
if (!vis.startExploration(state, data)) {
continue;
}
inputs_loop:
for (I input : inputs) {
Collection transitions = ts.getTransitions(state, input);
for (T trans : transitions) {
S succ = ts.getSuccessor(trans);
dataHolder.value = null;
TSTraversalAction act = vis.processTransition(state, data, input, trans, succ, dataHolder);
switch (act) {
case ABORT_INPUT:
continue inputs_loop;
case ABORT_STATE:
break inputs_loop;
case ABORT_TRAVERSAL:
return complete;
case EXPLORE:
if (stateCount != limit) {
bfsQueue.offer(new BFSRecord<>(succ, dataHolder.value));
stateCount++;
} else {
complete = false;
}
break;
case IGNORE:
break;
default:
throw new IllegalStateException("Unknown action " + act);
}
}
}
}
return complete;
}
public static boolean traverse(TraversalOrder order,
TransitionSystem ts,
Collection extends I> inputs,
TSTraversalVisitor vis) {
return traverse(order, ts, NO_LIMIT, inputs, vis);
}
public static boolean traverse(TraversalOrder order,
TransitionSystem ts,
int limit,
Collection extends I> inputs,
TSTraversalVisitor vis) {
switch (order) {
case BREADTH_FIRST:
return breadthFirst(ts, limit, inputs, vis);
case DEPTH_FIRST:
return depthFirst(ts, limit, inputs, vis);
default:
throw new IllegalArgumentException("Unknown traversal order: " + order);
}
}
}