net.automatalib.incremental.mealy.tree.IncrementalMealyTreeBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of automata-incremental Show documentation
Show all versions of automata-incremental Show documentation
A library for incremental automata construction. This artifact contains algorithms for incrementally
constructing DFAs (prefix-closed and non-prefix-closed), Mealy machines, and Moore machines from a finite,
incrementally growing set of example inputs/outputs.
/* Copyright (C) 2014 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.incremental.mealy.tree;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.automatalib.automata.transout.MealyMachine;
import net.automatalib.graphs.dot.DelegateDOTHelper;
import net.automatalib.graphs.dot.GraphDOTHelper;
import net.automatalib.incremental.ConflictException;
import net.automatalib.incremental.mealy.AbstractIncrementalMealyBuilder;
import net.automatalib.util.graphs.traversal.GraphTraversal;
import net.automatalib.words.Alphabet;
import net.automatalib.words.Word;
import net.automatalib.words.WordBuilder;
import com.google.common.base.Objects;
import com.google.common.collect.Iterators;
public class IncrementalMealyTreeBuilder extends AbstractIncrementalMealyBuilder {
private static final class Record {
private final S automatonState;
private final Node treeNode;
private final I incomingInput;
private final Iterator extends I> inputIt;
public Record(S automatonState, Node treeNode, I incomingInput, Iterator extends I> inputIt) {
this.automatonState = automatonState;
this.treeNode = treeNode;
this.inputIt = inputIt;
this.incomingInput = incomingInput;
}
}
public class GraphView extends AbstractGraphView,AnnotatedEdge> {
@Override
public Collection> getNodes() {
List> result = new ArrayList<>();
Iterators.addAll(result, GraphTraversal.dfIterator(this, Collections.singleton(root)));
return result;
}
@Override
public Collection> getOutgoingEdges(Node node) {
List> result = new ArrayList<>();
for(int i = 0; i < inputAlphabet.size(); i++) {
Edge edge = node.getEdge(i);
if(edge != null) {
result.add(new AnnotatedEdge<>(edge, inputAlphabet.getSymbol(i)));
}
}
return result;
}
@Override
public Node getTarget(AnnotatedEdge edge) {
return edge.getTarget();
}
@Override
@Nonnull
public Node getInitialNode() {
return root;
}
@Override
@Nullable
public I getInputSymbol(AnnotatedEdge edge) {
return edge.getInput();
}
@Override
@Nullable
public O getOutputSymbol(AnnotatedEdge edge) {
return edge.getOutput();
}
@Override
public GraphDOTHelper, AnnotatedEdge> getGraphDOTHelper() {
return new DelegateDOTHelper,AnnotatedEdge>(super.getGraphDOTHelper()) {
private int id = 0;
@Override
public boolean getNodeProperties(Node node,
Map properties) {
if(!super.getNodeProperties(node, properties)) {
return false;
}
properties.put(NodeAttrs.LABEL, "n" + (id++));
return true;
}
};
}
}
public class TransitionSystemView extends AbstractTransitionSystemView, Edge> {
@Override
public Edge getTransition(Node state, I input) {
int inputIdx = inputAlphabet.getSymbolIndex(input);
return state.getEdge(inputIdx);
}
@Override
public Node getSuccessor(Edge transition) {
return transition.getTarget();
}
@Override
public Node getInitialState() {
return root;
}
@Override
public O getTransitionOutput(Edge transition) {
return transition.getOutput();
}
}
private final Node root;
public IncrementalMealyTreeBuilder(Alphabet inputAlphabet) {
super(inputAlphabet);
this.root = new Node<>(inputAlphabet.size());
}
/*
* (non-Javadoc)
* @see net.automatalib.incremental.mealy.IncrementalMealyBuilder#insert(net.automatalib.words.Word, net.automatalib.words.Word)
*/
@Override
public void insert(Word extends I> input, Word extends O> outputWord) throws ConflictException {
Node curr = root;
Iterator extends O> outputIt = outputWord.iterator();
for(I sym : input) {
int symIdx = inputAlphabet.getSymbolIndex(sym);
O out = outputIt.next();
Edge edge = curr.getEdge(symIdx);
if(edge == null) {
curr = insertNode(curr, symIdx, out);
}
else {
if(!Objects.equal(out, edge.getOutput())) {
throw new ConflictException();
}
curr = curr.getSuccessor(symIdx);
}
}
}
/*
* (non-Javadoc)
* @see net.automatalib.incremental.mealy.IncrementalMealyBuilder#lookup(net.automatalib.words.Word, java.util.List)
*/
@Override
public boolean lookup(Word extends I> word, List super O> output) {
Node curr = root;
for(I sym : word) {
int symIdx = inputAlphabet.getSymbolIndex(sym);
Edge edge = curr.getEdge(symIdx);
if(edge == null) {
return false;
}
output.add(edge.getOutput());
curr = edge.getTarget();
}
return true;
}
/*
* (non-Javadoc)
* @see net.automatalib.incremental.IncrementalConstruction#findSeparatingWord(java.lang.Object, java.util.Collection, boolean)
*/
@Override
public Word findSeparatingWord(MealyMachine, I, ?, O> target,
Collection extends I> inputs, boolean omitUndefined) {
return doFindSeparatingWord(target, inputs, omitUndefined);
}
/*
* (non-Javadoc)
* @see net.automatalib.incremental.mealy.AbstractIncrementalMealyBuilder#hasDefinitiveInformation(net.automatalib.words.Word)
*/
@Override
public boolean hasDefinitiveInformation(Word extends I> word) {
Node curr = root;
Iterator extends I> symIt = word.iterator();
while(symIt.hasNext() && curr != null) {
int symIdx = inputAlphabet.getSymbolIndex(symIt.next());
curr = curr.getSuccessor(symIdx);
}
return (curr != null);
}
private Word doFindSeparatingWord(MealyMachine target, Collection extends I> inputs, boolean omitUndefined) {
Deque> dfsStack = new ArrayDeque<>();
dfsStack.push(new Record<>(target.getInitialState(), root, null, inputs.iterator()));
while(!dfsStack.isEmpty()) {
Record rec = dfsStack.peek();
if(!rec.inputIt.hasNext()) {
dfsStack.pop();
continue;
}
I input = rec.inputIt.next();
int inputIdx = inputAlphabet.getSymbolIndex(input);
Edge edge = rec.treeNode.getEdge(inputIdx);
if(edge == null) {
continue;
}
T trans = target.getTransition(rec.automatonState, input);
if(omitUndefined && trans == null) {
continue;
}
if(trans == null || !Objects.equal(target.getTransitionOutput(trans), edge.getOutput())) {
WordBuilder wb = new WordBuilder<>(dfsStack.size());
wb.append(input);
dfsStack.pop();
do {
wb.append(rec.incomingInput);
rec = dfsStack.pop();
} while(!dfsStack.isEmpty());
return wb.reverse().toWord();
}
dfsStack.push(new Record<>(target.getSuccessor(trans), edge.getTarget(), input, inputs.iterator()));
}
return null;
}
private Node insertNode(Node parent, int symIdx, O output) {
Node succ = new Node<>(inputAlphabet.size());
Edge edge = new Edge(output, succ);
parent.setEdge(symIdx, edge);
return succ;
}
@Override
public TransitionSystemView asTransitionSystem() {
return new TransitionSystemView();
}
@Override
public GraphView asGraph() {
return new GraphView();
}
}