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

net.automatalib.util.automata.Automata 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-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 inputs) {
        return automaton.transitionGraphView(inputs);
    }

    public static > A minimize(
            UniversalDeterministicAutomaton automaton,
            Collection 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 inputs) {
        return automaton.transitionGraphView(inputs);
    }

    @SuppressWarnings("unchecked")
    public static > A invasiveMinimize(A automaton,
                                                                                                        Collection inputs) {

        List inputList;
        if (inputs instanceof List) {
            inputList = (List) 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 reference,
                                                         UniversalDeterministicAutomaton other,
                                                         Collection inputs) {
        return DeterministicEquivalenceTest.findSeparatingWordLarge(reference, other, inputs);
    }

    public static  boolean testEquivalence(UniversalDeterministicAutomaton reference,
                                              UniversalDeterministicAutomaton other,
                                              Collection inputs) {
        return (findSeparatingWord(reference, other, inputs) == null);
    }

    public static  boolean testEquivalence(final OneSEVPA sevpa1,
                                              final OneSEVPA 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 reference,
                                                 UniversalDeterministicAutomaton other,
                                                 Collection 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 inputs) {
        return NearLinearEquivalenceTest.findSeparatingWord(automaton, state1, state2, inputs);
    }

    public static  Word findSeparatingWord(final OneSEVPA sevpa1,
                                                 final OneSEVPA 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 automaton,
                                                      Collection 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 automaton, Collection inputs, Collection> result) { CharacterizingSets.findCharacterizingSet(automaton, inputs, result); } public static boolean incrementalCharacterizingSet(UniversalDeterministicAutomaton automaton, Collection inputs, Collection> oldSuffixes, Collection> 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 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 inputs, S state, Collection> 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 automaton, Collection 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 automaton, Collection 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 automaton, Collection 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 inputs) { return allDefinedInputsIterator(automaton, automaton.iterator(), inputs); } public static Iterable> allDefinedInputs(Automaton automaton, Iterable inputs) { return allDefinedInputs(automaton, automaton, inputs); } public static Iterable> allUndefinedInputs(Automaton automaton, Iterable inputs) { return allUndefinedTransitions(automaton, automaton, inputs); } public static boolean hasUndefinedInput(Automaton automaton, Iterable inputs) { return findUndefinedInput(automaton, inputs) != null; } public static TransRef findUndefinedInput(Automaton automaton, Iterable inputs) { Iterator> it = allUndefinedInputsIterator(automaton, inputs); if (!it.hasNext()) { return null; } return it.next(); } public static Iterator> allUndefinedInputsIterator(Automaton automaton, Iterable 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]; } } }