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

de.learnlib.algorithms.ttt.base.AbstractTTTHypothesis Maven / Gradle / Ivy

/* Copyright (C) 2013-2019 TU Dortmund
 * This file is part of LearnLib, http://www.learnlib.de/.
 *
 * 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 de.learnlib.algorithms.ttt.base;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import net.automatalib.SupportsGrowingAlphabet;
import net.automatalib.automata.DeterministicAutomaton;
import net.automatalib.automata.FiniteAlphabetAutomaton;
import net.automatalib.automata.fsa.DFA;
import net.automatalib.graphs.Graph;
import net.automatalib.visualization.DefaultVisualizationHelper;
import net.automatalib.visualization.VisualizationHelper;
import net.automatalib.words.Alphabet;
import net.automatalib.words.GrowingAlphabet;
import net.automatalib.words.impl.Alphabets;

/**
 * Hypothesis DFA for the {@link AbstractTTTLearner TTT algorithm}.
 *
 * @param 
 *         input symbol type
 *
 * @author Malte Isberner
 */
public abstract class AbstractTTTHypothesis implements DeterministicAutomaton, I, T>,
                                                                FiniteAlphabetAutomaton, I, T>,
                                                                DeterministicAutomaton.FullIntAbstraction,
                                                                SupportsGrowingAlphabet,
                                                                Serializable {

    protected final List> states = new ArrayList<>();

    protected transient Alphabet alphabet;
    private int alphabetSize;

    private TTTState initialState;

    /**
     * Constructor.
     *
     * @param alphabet
     *         the input alphabet
     */
    public AbstractTTTHypothesis(Alphabet alphabet) {
        this.alphabet = alphabet;
        this.alphabetSize = this.alphabet.size();
    }

    @Override
    public TTTState getInitialState() {
        return initialState;
    }

    @Override
    public T getTransition(int stateId, int symIdx) {
        TTTState state = states.get(stateId);
        TTTTransition trans = getInternalTransition(state, symIdx);
        return mapTransition(trans);
    }

    @Override
    public T getTransition(TTTState state, I input) {
        TTTTransition trans = getInternalTransition(state, input);
        return trans == null ? null : mapTransition(trans);
    }

    /**
     * Retrieves the internal transition (i.e., the {@link TTTTransition} object) for a given state and input.
     * This method is required since the {@link DFA} interface requires the return value of {@link
     * #getTransition(TTTState, Object)} to refer to the successor state directly.
     *
     * @param state
     *         the source state
     * @param input
     *         the input symbol triggering the transition
     *
     * @return the transition object
     */
    public TTTTransition getInternalTransition(TTTState state, I input) {
        int inputIdx = alphabet.getSymbolIndex(input);
        return getInternalTransition(state, inputIdx);
    }

    public TTTTransition getInternalTransition(TTTState state, int input) {
        return state.getTransition(input);
    }

    protected abstract T mapTransition(TTTTransition internalTransition);

    /**
     * Initializes the automaton, adding an initial state. Whether or not the initial state is accepting needs to be
     * known at this point.
     *
     * @return the initial state of this newly initialized automaton
     */
    public TTTState initialize() {
        assert !isInitialized();

        initialState = createState(null);
        return initialState;
    }

    /**
     * Checks whether this automaton was initialized (i.e., {@link #initialize()} has been called).
     *
     * @return {@code true} if this automaton was initialized, {@code false} otherwise.
     */
    public boolean isInitialized() {
        return (initialState != null);
    }

    public TTTState createState(TTTTransition parent) {
        TTTState state = newState(alphabet.size(), parent, states.size());
        states.add(state);
        if (parent != null) {
            parent.makeTree(state);
        }
        return state;
    }

    protected TTTState newState(int alphabetSize, TTTTransition parent, int id) {
        return new TTTState<>(alphabetSize, parent, id);
    }

    @Override
    public Alphabet getInputAlphabet() {
        return alphabet;
    }

    @Override
    public GraphView graphView() {
        return new GraphView();
    }

    @Override
    public int getIntInitialState() {
        return 0;
    }

    @Override
    public int numInputs() {
        return alphabet.size();
    }

    @Override
    public int getIntSuccessor(T trans) {
        return getSuccessor(trans).id;
    }

    @Override
    public DeterministicAutomaton.FullIntAbstraction fullIntAbstraction(Alphabet alphabet) {
        if (alphabet == this.alphabet) {
            return this;
        }
        return DeterministicAutomaton.super.fullIntAbstraction(alphabet);
    }

    @Override
    public void addAlphabetSymbol(I symbol) {
        final GrowingAlphabet growingAlphabet = Alphabets.toGrowingAlphabetOrThrowException(this.alphabet);

        if (!growingAlphabet.containsSymbol(symbol)) {
            growingAlphabet.addSymbol(symbol);
        }

        final int newAlphabetSize = growingAlphabet.size();

        if (alphabetSize < newAlphabetSize) {
            for (final TTTState s : this.getStates()) {
                s.ensureInputCapacity(newAlphabetSize);
            }

            alphabetSize = newAlphabetSize;
        }
    }

    @Override
    public Collection> getStates() {
        return Collections.unmodifiableList(states);
    }

    @Override
    public int size() {
        return states.size();
    }

    void setAlphabet(Alphabet alphabet) {
        this.alphabet = alphabet;
    }

    public static final class TTTEdge {

        public final TTTTransition transition;
        public final TTTState target;

        public TTTEdge(TTTTransition transition, TTTState target) {
            this.transition = transition;
            this.target = target;
        }
    }

    public class GraphView implements Graph, TTTEdge> {

        @Override
        public Collection> getNodes() {
            return states;
        }

        @Override
        public Collection> getOutgoingEdges(TTTState node) {
            List> result = new ArrayList<>();
            for (TTTTransition trans : node.getTransitions()) {
                for (TTTState target : trans.getDTTarget().subtreeStates()) {
                    result.add(new TTTEdge<>(trans, target));
                }
            }
            return result;
        }

        @Override
        public TTTState getTarget(TTTEdge edge) {
            return edge.target;
        }

        @Override
        public VisualizationHelper, TTTEdge> getVisualizationHelper() {
            return new DefaultVisualizationHelper, TTTEdge>() {

                @Override
                public boolean getEdgeProperties(TTTState src,
                                                 TTTEdge edge,
                                                 TTTState tgt,
                                                 Map properties) {
                    properties.put(EdgeAttrs.LABEL, String.valueOf(edge.transition.getInput()));
                    if (edge.transition.isTree()) {
                        properties.put(EdgeAttrs.STYLE, EdgeStyles.BOLD);
                    } else if (edge.transition.getDTTarget().isInner()) {
                        properties.put(EdgeAttrs.STYLE, EdgeStyles.DOTTED);
                    }
                    return true;
                }

            };
        }

    }
}