net.automatalib.util.automata.Automata Maven / Gradle / Ivy
Show all versions of automata-util Show documentation
/* 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.automata;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.annotation.ParametersAreNonnullByDefault;
import net.automatalib.automata.Automaton;
import net.automatalib.automata.DeterministicAutomaton;
import net.automatalib.automata.MutableDeterministic;
import net.automatalib.automata.UniversalAutomaton;
import net.automatalib.automata.UniversalDeterministicAutomaton;
import net.automatalib.automata.graphs.TransitionEdge;
import net.automatalib.automata.vpda.OneSEVPA;
import net.automatalib.graphs.Graph;
import net.automatalib.graphs.UniversalGraph;
import net.automatalib.util.automata.cover.Covers;
import net.automatalib.util.automata.equivalence.CharacterizingSets;
import net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest;
import net.automatalib.util.automata.equivalence.NearLinearEquivalenceTest;
import net.automatalib.util.automata.vpda.OneSEVPAUtil;
import net.automatalib.util.minimizer.Block;
import net.automatalib.util.minimizer.BlockMap;
import net.automatalib.util.minimizer.MinimizationResult;
import net.automatalib.util.minimizer.Minimizer;
import net.automatalib.util.ts.TS;
import net.automatalib.words.VPDAlphabet;
import net.automatalib.words.Word;
@ParametersAreNonnullByDefault
public class Automata extends TS {
public static Graph> asGraph(Automaton automaton,
Collection extends I> inputs) {
return automaton.transitionGraphView(inputs);
}
public static > A minimize(
UniversalDeterministicAutomaton automaton,
Collection extends I> inputs,
A output) {
UniversalGraph, SP, TransitionEdge.Property> aag =
asUniversalGraph(automaton, inputs);
MinimizationResult> mr =
Minimizer.minimize(aag, Collections.singleton(automaton.getInitialState()));
output.clear();
S init = automaton.getInitialState();
Block> initBlock = mr.getBlockForState(init);
BlockMap bm = new BlockMap<>(mr);
for (Block> block : mr.getBlocks()) {
S rep = mr.getRepresentative(block);
SO state;
SP repProp = automaton.getStateProperty(rep);
if (block == initBlock) {
state = output.addInitialState(repProp);
} else {
state = output.addState(repProp);
}
bm.put(block, state);
}
for (Block> block : mr.getBlocks()) {
S rep = mr.getRepresentative(block);
SO state = bm.get(block);
for (I input : inputs) {
T trans = automaton.getTransition(rep, input);
if (trans != null) {
TP prop = automaton.getTransitionProperty(trans);
S oldSucc = automaton.getSuccessor(trans);
Block> succBlock = mr.getBlockForState(oldSucc);
SO newSucc = bm.get(succBlock);
output.addTransition(state, input, newSucc, prop);
}
}
}
return output;
}
public static UniversalGraph, SP, TransitionEdge.Property> asUniversalGraph(
UniversalAutomaton automaton,
Collection extends I> inputs) {
return automaton.transitionGraphView(inputs);
}
@SuppressWarnings("unchecked")
public static > A invasiveMinimize(A automaton,
Collection extends I> inputs) {
List extends I> inputList;
if (inputs instanceof List) {
inputList = (List extends I>) inputs;
} else {
inputList = new ArrayList(inputs);
}
int numInputs = inputs.size();
UniversalGraph, SP, TransitionEdge.Property> aag =
asUniversalGraph(automaton, inputs);
MinimizationResult> mr =
Minimizer.minimize(aag, automaton.getInitialStates());
S init = automaton.getInitialState();
int initId = mr.getBlockForState(init).getId();
ResultStateRecord[] records = new ResultStateRecord[mr.getNumBlocks()];
for (Block> blk : mr.getBlocks()) {
int id = blk.getId();
S state = mr.getRepresentative(blk);
SP prop = automaton.getStateProperty(state);
ResultStateRecord rec = new ResultStateRecord<>(numInputs, prop);
records[id] = rec;
for (int i = 0; i < numInputs; i++) {
I input = inputList.get(i);
T trans = automaton.getTransition(state, input);
if (trans == null) {
continue;
}
TP transProp = automaton.getTransitionProperty(trans);
S succ = automaton.getSuccessor(trans);
int tgtId = mr.getBlockForState(succ).getId();
rec.transitions[i] = new ResultTransRecord<>(tgtId, transProp);
}
}
automaton.clear();
Object[] states = new Object[records.length];
for (int i = 0; i < records.length; i++) {
ResultStateRecord rec = records[i];
SP prop = rec.property;
S state;
if (i == initId) {
state = automaton.addInitialState(prop);
} else {
state = automaton.addState(prop);
}
states[i] = state;
}
for (int i = 0; i < records.length; i++) {
ResultStateRecord rec = records[i];
S state = (S) states[i];
for (int j = 0; j < numInputs; j++) {
ResultTransRecord transRec = rec.transitions[j];
if (transRec == null) {
continue;
}
S succ = (S) states[transRec.targetId];
I input = inputList.get(j);
automaton.addTransition(state, input, succ, transRec.property);
}
}
return automaton;
}
public static Word findShortestSeparatingWord(UniversalDeterministicAutomaton, I, ?, ?, ?> reference,
UniversalDeterministicAutomaton, I, ?, ?, ?> other,
Collection extends I> inputs) {
return DeterministicEquivalenceTest.findSeparatingWordLarge(reference, other, inputs);
}
public static boolean testEquivalence(UniversalDeterministicAutomaton, I, ?, ?, ?> reference,
UniversalDeterministicAutomaton, I, ?, ?, ?> other,
Collection extends I> inputs) {
return (findSeparatingWord(reference, other, inputs) == null);
}
public static boolean testEquivalence(final OneSEVPA, I> sevpa1,
final OneSEVPA, I> sevpa2,
final VPDAlphabet inputs) {
return OneSEVPAUtil.testEquivalence(sevpa1, sevpa2, inputs);
}
/**
* Finds a separating word for two automata. A separating word is a word that exposes a difference (differing state
* or transition properties, or a transition undefined in only one of the automata) between the two automata.
*
* @param
* input symbol type
* @param reference
* the one automaton to consider
* @param other
* the other automaton to consider
* @param inputs
* the input symbols to consider
*
* @return a separating word, or {@code null} if no such word could be found.
*/
public static Word findSeparatingWord(UniversalDeterministicAutomaton, I, ?, ?, ?> reference,
UniversalDeterministicAutomaton, I, ?, ?, ?> other,
Collection extends I> inputs) {
return NearLinearEquivalenceTest.findSeparatingWord(reference, other, inputs);
}
/**
* Finds a separating word for two states in an automaton. A separating word is a word that exposes a difference
* (differing state or transition properties, or a transition undefined in only one of the paths) between the two
* states.
*
* @param
* state type
* @param
* input symbol type
* @param automaton
* the automaton containing the states
* @param state1
* the one state
* @param state2
* the other state
* @param inputs
* the input symbols to consider
*
* @return a separating word, or {@code null} if no such word could be found
*/
public static Word findSeparatingWord(UniversalDeterministicAutomaton automaton,
S state1,
S state2,
Collection extends I> inputs) {
return NearLinearEquivalenceTest.findSeparatingWord(automaton, state1, state2, inputs);
}
public static Word findSeparatingWord(final OneSEVPA, I> sevpa1,
final OneSEVPA, I> sevpa2,
final VPDAlphabet inputs) {
return OneSEVPAUtil.findSeparatingWord(sevpa1, sevpa2, inputs);
}
/**
* Computes a characterizing set, and returns it as a {@link List}.
*
* @param
* input symbol type
* @param automaton
* the automaton for which to determine the characterizing set
* @param inputs
* the input symbols to consider
*
* @return a list containing the characterizing words
*
* @see CharacterizingSets
*/
public static List> characterizingSet(UniversalDeterministicAutomaton, I, ?, ?, ?> automaton,
Collection extends I> inputs) {
List> result = new ArrayList<>();
characterizingSet(automaton, inputs, result);
return result;
}
/**
* Computes a characterizing set for the given automaton.
*
* This is a convenience method acting as a shortcut to {@link CharacterizingSets#findCharacterizingSet(
* UniversalDeterministicAutomaton, Collection, Collection)}.
*
* @param
* input symbol type
* @param automaton
* the automaton for which to determine the characterizing set
* @param inputs
* the input symbols to consider
* @param result
* the collection in which to store the characterizing words
*
* @see CharacterizingSets
*/
public static void characterizingSet(UniversalDeterministicAutomaton, I, ?, ?, ?> automaton,
Collection extends I> inputs,
Collection super Word> result) {
CharacterizingSets.findCharacterizingSet(automaton, inputs, result);
}
public static boolean incrementalCharacterizingSet(UniversalDeterministicAutomaton, I, ?, ?, ?> automaton,
Collection extends I> inputs,
Collection extends Word> oldSuffixes,
Collection super Word> newSuffixes) {
return CharacterizingSets.findIncrementalCharacterizingSet(automaton, inputs, oldSuffixes, newSuffixes);
}
/**
* Computes a characterizing set for a single state, and returns it as a {@link List}.
*
* @param
* state type
* @param
* input symbol type
* @param automaton
* the automaton containing the state
* @param inputs
* the input symbols to consider
* @param state
* the state for which to determine a characterizing set
*
* @return a list containing the characterizing words
*
* @see CharacterizingSets
*/
public static List> stateCharacterizingSet(UniversalDeterministicAutomaton automaton,
Collection extends I> inputs,
S state) {
List> result = new ArrayList<>();
stateCharacterizingSet(automaton, inputs, state, result);
return result;
}
/**
* Computes a characterizing set for a single state.
*
* This is a convenience method acting as a shortcut to {@link CharacterizingSets#findCharacterizingSet(
* UniversalDeterministicAutomaton, Collection, Object, Collection)}.
*
* @param
* state type
* @param
* input symbol type
* @param automaton
* the automaton containing the state
* @param inputs
* the input symbols to consider
* @param state
* the state for which to determine a characterizing set
* @param result
* the collection in which to store the characterizing words
*
* @see CharacterizingSets
*/
public static void stateCharacterizingSet(UniversalDeterministicAutomaton automaton,
Collection extends I> inputs,
S state,
Collection super Word> result) {
CharacterizingSets.findCharacterizingSet(automaton, inputs, state, result);
}
/**
* Convenient method for computing a state cover.
*
* @param automaton
* the automaton for which the cover should be computed
* @param inputs
* the set of input symbols allowed in the cover sequences
* @param
* input symbol type
*
* @return the state cover for the given automaton
*
* @see Covers#stateCover(DeterministicAutomaton, Collection, Collection)
*/
public static List> stateCover(DeterministicAutomaton, I, ?> automaton,
Collection extends I> inputs) {
final List> result = new ArrayList<>(automaton.size());
Covers.stateCover(automaton, inputs, result);
return result;
}
/**
* Convenient method for computing a state cover.
*
* @param automaton
* the automaton for which the cover should be computed
* @param inputs
* the set of input symbols allowed in the cover sequences
* @param
* input symbol type
*
* @return the transition cover for the given automaton
*
* @see Covers#transitionCover(DeterministicAutomaton, Collection, Collection)
*/
public static List> transitionCover(DeterministicAutomaton, I, ?> automaton,
Collection extends I> inputs) {
final List> result = new ArrayList<>(automaton.size() * inputs.size());
Covers.transitionCover(automaton, inputs, result);
return result;
}
/**
* Convenient method for computing a structural cover.
*
* @param automaton
* the automaton for which the cover should be computed
* @param inputs
* the set of input symbols allowed in the cover sequences
* @param
* input symbol type
*
* @return the structural cover for the given automaton
*
* @see Covers#structuralCover(DeterministicAutomaton, Collection, Collection)
*/
public static List> structuralCover(DeterministicAutomaton, I, ?> automaton,
Collection extends I> inputs) {
final List> result = new ArrayList<>(automaton.size() * (inputs.size() + 1));
Covers.structuralCover(automaton, inputs, result);
return result;
}
public static Iterator> allDefinedInputsIterator(Automaton automaton,
Iterable extends I> inputs) {
return allDefinedInputsIterator(automaton, automaton.iterator(), inputs);
}
public static Iterable> allDefinedInputs(Automaton automaton,
Iterable extends I> inputs) {
return allDefinedInputs(automaton, automaton, inputs);
}
public static Iterable> allUndefinedInputs(Automaton automaton,
Iterable extends I> inputs) {
return allUndefinedTransitions(automaton, automaton, inputs);
}
public static boolean hasUndefinedInput(Automaton, I, ?> automaton, Iterable extends I> inputs) {
return findUndefinedInput(automaton, inputs) != null;
}
public static TransRef findUndefinedInput(Automaton automaton,
Iterable extends I> inputs) {
Iterator> it = allUndefinedInputsIterator(automaton, inputs);
if (!it.hasNext()) {
return null;
}
return it.next();
}
public static Iterator> allUndefinedInputsIterator(Automaton automaton,
Iterable extends I> inputs) {
return allUndefinedTransitionsIterator(automaton, automaton.iterator(), inputs);
}
private static final class ResultTransRecord {
public final int targetId;
public final TP property;
ResultTransRecord(int targetId, TP property) {
this.targetId = targetId;
this.property = property;
}
}
private static final class ResultStateRecord {
public final SP property;
public final ResultTransRecord[] transitions;
@SuppressWarnings("unchecked")
ResultStateRecord(int numInputs, SP property) {
this.property = property;
this.transitions = new ResultTransRecord[numInputs];
}
}
}