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

net.automatalib.util.automata.equivalence.DeterministicEquivalenceTest 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.equivalence;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Objects;
import java.util.Queue;

import net.automatalib.automata.UniversalDeterministicAutomaton;
import net.automatalib.automata.concepts.StateIDs;
import net.automatalib.words.Word;
import net.automatalib.words.WordBuilder;



public class DeterministicEquivalenceTest {
	
	private static final class StatePair {
		public final S ref;
		public final S2 other;
		public StatePair(S ref, S2 other) {
			this.ref = ref;
			this.other = other;
		}
	}
	
	private static final class Pred {
		public final int id;
		public final I symbol;
		public Pred(int id, I input) {
			this.id = id;
			this.symbol = input;
		}
	}
	
	private final UniversalDeterministicAutomaton reference;
	
	public DeterministicEquivalenceTest(UniversalDeterministicAutomaton reference) {
		this.reference = reference;
	}
	
	public Word findSeparatingWord(UniversalDeterministicAutomaton other,
			Collection inputs) {
		return findSeparatingWord(reference, other, inputs);
	}
	
	@SuppressWarnings("unchecked")
	public static 
	Word findSeparatingWord(UniversalDeterministicAutomaton reference,
			UniversalDeterministicAutomaton other,
			Collection inputs) {
		Queue> bfsQueue = new ArrayDeque<>();
		
		S refInit = reference.getInitialState();
		S2 otherInit = other.getInitialState();
		
		Object refStateProp = reference.getStateProperty(refInit),
				otherStateProp = other.getStateProperty(otherInit);
		
		if(!Objects.equals(refStateProp, otherStateProp))
			return Word.epsilon();
		
		bfsQueue.offer(new StatePair<>(refInit, otherInit));
		
		int refSize = reference.size();
		int totalStates = refSize * other.size();
		
		StateIDs refStateIds = reference.stateIDs();
		StateIDs otherStateIds = other.stateIDs();
		
		StatePair currPair = null;
		int lastId = otherStateIds.getStateId(otherInit) * refSize + refStateIds.getStateId(refInit);
		
		Pred[] preds = new Pred[totalStates];
		preds[lastId] = new Pred(-1, null);
		
		int currDepth = 0;
		int inCurrDepth = 1;
		int inNextDepth = 0;
		
		I lastSym = null;
		
bfs:	while((currPair = bfsQueue.poll()) != null) {
			S refState = currPair.ref;
			S2 otherState = currPair.other;
			
			
			int currId = otherStateIds.getStateId(otherState) * refSize + refStateIds.getStateId(refState);
			lastId = currId;
			
			
			for(I in : inputs) {
				lastSym = in;
				T refTrans = reference.getTransition(refState, in);
				T2 otherTrans = other.getTransition(otherState, in);
				
				if((refTrans == null || otherTrans == null) && refTrans != otherTrans)
					break bfs;
				
				Object refProp = reference.getTransitionProperty(refTrans);
				Object otherProp = other.getTransitionProperty(otherTrans);
				if(!Objects.equals(refProp, otherProp))
					break bfs;
				
				
				S refSucc = reference.getSuccessor(refTrans);
				S2 otherSucc = other.getSuccessor(otherTrans);
				
				int succId = otherStateIds.getStateId(otherSucc) * refSize + refStateIds.getStateId(refSucc);
				
				if(preds[succId] == null) {
					refStateProp = reference.getStateProperty(refSucc);
					otherStateProp = other.getStateProperty(otherSucc);
					
					if(!Objects.equals(refStateProp, otherStateProp))
						break bfs;
					
					preds[succId] = new Pred<>(currId, in);
					bfsQueue.offer(new StatePair<>(refSucc, otherSucc));
					inNextDepth++;
				}
			}
			
			lastSym = null;
			
			
			// Next level in BFS reached
			if(--inCurrDepth == 0) {
				inCurrDepth = inNextDepth;
				inNextDepth = 0;
				currDepth++;
			}
		}
		
		if(lastSym == null)
			return null;
		
		WordBuilder sep = new WordBuilder(null, currDepth+1);
		int index = currDepth;
		sep.setSymbol(index--, lastSym);
		
		Pred pred = preds[lastId];
		I sym = pred.symbol;
		while(sym != null) {
			sep.setSymbol(index--, sym);
			pred = preds[pred.id];
			sym = pred.symbol;
		}
		
		
		return sep.toWord();
	} 
}