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 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.automata;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

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.graphs.Graph;
import net.automatalib.graphs.UniversalGraph;
import net.automatalib.util.automata.asgraph.AutomatonAsGraph;
import net.automatalib.util.automata.asgraph.UniversalAutomatonAsGraph;
import net.automatalib.util.automata.equivalence.CharacterizingSets;
import net.automatalib.util.automata.equivalence.NearLinearEquivalenceTest;
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.Word;

public class Automata extends TS {

	public static 
	Graph> asGraph(
			Automaton automaton, Collection inputs) {
		return new AutomatonAsGraph>(automaton, inputs);
	}
	
	public static 
	UniversalGraph,SP,TransitionEdge.Property> asUniversalGraph(
			UniversalAutomaton automaton, Collection inputs) {
		return new UniversalAutomatonAsGraph>(automaton, 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;
	}
	
	private static final class ResultTransRecord {
		public final int targetId;
		public final TP property;
		
		public 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")
		public ResultStateRecord(int numInputs, SP property) {
			this.property = property;
			this.transitions = new ResultTransRecord[numInputs];
		}
	}
	
	@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 > A minimize(
			A automaton, Collection inputs) {
		return minimize(automaton, inputs, automaton);
	}*/
	
	/**
	 * 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 null if no such word could be found.
	 */
	public static  Word findSeparatingWord(
			UniversalDeterministicAutomaton reference,
			UniversalDeterministicAutomaton other,
			Collection inputs) {
		return NearLinearEquivalenceTest.findSeparatingWord(reference, other, inputs);
	}
	
	public static  boolean testEquivalence(
			UniversalDeterministicAutomaton reference,
			UniversalDeterministicAutomaton other,
			Collection inputs) {
		return (findSeparatingWord(reference, other, inputs) == null);
	}
	
	/**
	 * 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 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);
	}
	
	/**
	 * Computes a characterizing set for the given automaton.
	 * 

* This is a convenience method acting as a shortcut to * {@link CharacterizingSets#findCharacterizingSet(UniversalDeterministicAutomaton, Collection, Collection)}. * * @see CharacterizingSets * * @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 */ public static void characterizingSet(UniversalDeterministicAutomaton automaton, Collection inputs, Collection> result) { CharacterizingSets.findCharacterizingSet(automaton, inputs, result); } /** * Computes a characterizing set, and returns it as a {@link List}. * * @see CharacterizingSets * * @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 */ public static List> characterizingSet(UniversalDeterministicAutomaton automaton, Collection inputs) { List> result = new ArrayList>(); characterizingSet(automaton, inputs, result); return 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. *

* This is a convenience method acting as a shortcut to * {@link CharacterizingSets#findCharacterizingSet(UniversalDeterministicAutomaton, Collection, Object, Collection)}. * * @see CharacterizingSets * * @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 */ public static void stateCharacterizingSet(UniversalDeterministicAutomaton automaton, Collection inputs, S state, Collection> result) { CharacterizingSets.findCharacterizingSet(automaton, inputs, state, result); } /** * Computes a characterizing set for a single state, and returns it as a {@link List}. * * @see CharacterizingSets * * @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 */ public static List> stateCharacterizingSet(UniversalDeterministicAutomaton automaton, Collection inputs, S state) { List> result = new ArrayList>(); stateCharacterizingSet(automaton, inputs, state, result); return result; } public static void cover(DeterministicAutomaton automaton, Collection inputs, Collection> states, Collection> transitions) { Covers.cover(automaton, inputs, states, transitions); } public static List> stateCover(DeterministicAutomaton automaton, Collection inputs) { List> states = new ArrayList>(automaton.size()); cover(automaton, inputs, states, null); return states; } public static List> transitionCover(DeterministicAutomaton automaton, Collection inputs) { List> all = new ArrayList>(automaton.size() * inputs.size()); cover(automaton, inputs, all, all); return all; } public static boolean incrementalCover( DeterministicAutomaton automaton, Collection inputs, Collection> oldStates, Collection> oldTransitions, Collection> newStates, Collection> newTransitions) { return Covers.incrementalCover(automaton, inputs, oldStates, oldTransitions, newStates, newTransitions); } public static boolean incrementalStateCover( DeterministicAutomaton automaton, Collection inputs, Collection> oldStates, Collection> newStates) { return incrementalCover(automaton, inputs, oldStates, Collections.>emptyList(), newStates, null); } public static boolean incrementalStructuralCover( DeterministicAutomaton automaton, Collection inputs, Collection> oldStructural, Collection> newStructural) { return incrementalCover(automaton, inputs, oldStructural, Collections.>emptyList(), newStructural, newStructural); } 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 Iterator> allUndefinedInputsIterator( Automaton automaton, Iterable inputs) { return allUndefinedTransitionsIterator(automaton, automaton.iterator(), inputs); } public static Iterable> allUndefinedInputs( Automaton automaton, Iterable inputs) { return allUndefinedTransitions(automaton, automaton, inputs); } public static TransRef findUndefinedInput( Automaton automaton, Iterable inputs) { Iterator> it = allUndefinedInputsIterator(automaton, inputs); if (!it.hasNext()) { return null; } return it.next(); } public static boolean hasUndefinedInput( Automaton automaton, Iterable inputs) { return findUndefinedInput(automaton, inputs) != null; } }