
de.learnlib.algorithm.aaar.AbstractAAARLearner Maven / Gradle / Ivy
Show all versions of learnlib-aaar Show documentation
/* Copyright (C) 2013-2023 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.algorithm.aaar;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import de.learnlib.algorithm.LearnerConstructor;
import de.learnlib.algorithm.LearningAlgorithm;
import de.learnlib.algorithm.aaar.abstraction.AbstractAbstractionTree;
import de.learnlib.oracle.MembershipOracle;
import de.learnlib.query.DefaultQuery;
import net.automatalib.alphabet.Alphabet;
import net.automatalib.alphabet.GrowingAlphabet;
import net.automatalib.alphabet.GrowingMapAlphabet;
import net.automatalib.alphabet.SupportsGrowingAlphabet;
import net.automatalib.automaton.MutableDeterministic;
import net.automatalib.automaton.UniversalDeterministicAutomaton;
import net.automatalib.word.Word;
import net.automatalib.word.WordBuilder;
/**
* Base implementation of the learner presented in "Automata Learning with Automated Alphabet Abstraction Refinement" by
* Howar et al.
*
* This implementation is a {@link LearningAlgorithm} for abstract models but operates on concrete systems with concrete
* input symbols. Therefore, the learner receives concrete counterexamples which are transformed into abstract ones
* (using the simultaneously inferred {@link AbstractAbstractionTree abstraction tree}) whose symbols are then mapped to
* their concrete representatives again, prior to actual refinement. Since this concept is agnostic to the actual
* learning process, this learner can be parameterized with an arbitrary (concrete) learning algorithm for the acutal
* inference.
*
* There exist several accessor for different views on the current hypothesis, e.g., the actual hypothesis of the
* internal learner, an abstracted hypothesis, and a translating hypothesis which automatically performs the previously
* mentioned translation steps for offering a model that is able to handle previously unobserved (concrete) input
* symbols.
*
* @param
* learner type
* @param
* abstract model type
* @param
* concrete model type
* @param
* abstract input symbol type
* @param
* concrete input symbol type
* @param
* output domain type
*/
public abstract class AbstractAAARLearner & SupportsGrowingAlphabet, AM, CM, AI, CI, D>
implements LearningAlgorithm {
private final L learner;
private final MembershipOracle oracle;
private final GrowingAlphabet rep;
private final GrowingAlphabet abs;
public AbstractAAARLearner(LearnerConstructor learnerConstructor, MembershipOracle o) {
this.oracle = o;
this.rep = new GrowingMapAlphabet<>();
this.abs = new GrowingMapAlphabet<>();
this.learner = learnerConstructor.constructLearner(rep, oracle);
}
@Override
public void startLearning() {
for (AI ai : getInitialAbstracts()) {
this.abs.addSymbol(ai);
}
for (CI ci : getInitialRepresentatives()) {
this.rep.addSymbol(ci);
this.learner.addAlphabetSymbol(ci);
}
learner.startLearning();
}
@Override
public boolean refineHypothesis(DefaultQuery query) {
final Word input = query.getInput();
final WordBuilder wb = new WordBuilder<>(input.size());
Word prefix = Word.epsilon();
for (int i = 0; i < input.size(); i++) {
final CI cur = input.getSymbol(i);
// lift & lower
final AbstractAbstractionTree tree = getTreeForRepresentative(cur);
final AI a = tree.getAbstractSymbol(cur);
final CI r = tree.getRepresentative(a);
final Word suffix = input.suffix(input.size() - i - 1);
final Word testOld = prefix.append(r).concat(suffix);
final Word testNew = prefix.append(cur).concat(suffix);
final D outOld = oracle.answerQuery(testOld);
final D outNew = oracle.answerQuery(testNew);
if (!Objects.equals(outOld, outNew)) { // add new abstraction
final AI newA = tree.splitLeaf(r, cur, prefix, suffix, outOld);
abs.addSymbol(newA);
rep.addSymbol(cur);
learner.addAlphabetSymbol(cur);
return true;
} else {
prefix = prefix.append(r);
wb.append(r);
}
}
final int prefixLen = query.getPrefix().length();
final DefaultQuery concreteCE =
new DefaultQuery<>(wb.toWord(0, prefixLen), wb.toWord(prefixLen, wb.size()), query.getOutput());
return learner.refineHypothesis(concreteCE);
}
/**
* Returns the (abstract) alphabet of the current (abstract) hypothesis model (cf. {@link #getHypothesisModel()}).
*
* @return the (abstract) alphabet of the current (abstract) hypothesis model
*/
public Alphabet getAbstractAlphabet() {
return this.abs;
}
/**
* Returns the (concrete) alphabet of the current (concrete) internal hypothesis model (cf.
* {@link #getLearnerHypothesisModel()}).
*
* @return the (concrete) alphabet of the current (concrete) internal hypothesis model
*/
public abstract Alphabet getLearnerAlphabet();
/**
* Returns the (concrete) hypothesis model form the provided internal learner.
*
* @return the (concrete) hypothesis model form the provided internal learner
*/
public CM getLearnerHypothesisModel() {
return learner.getHypothesisModel();
}
/**
* Returns a model of the current internal hypothesis model (cf. {@link #getLearnerHypothesisModel()}) that
* automatically transforms (concrete) input symbols to abstract ones and uses their representatives to actually
* perform transitions. This allows the returned model to handle (concrete) input symbols that have not yet been
* added to the hypothesis by previous abstraction refinements. Note that this model requires the
* {@link MembershipOracle} passed to the constructor of this learner to still function in order to determine the
* abstract input symbols.
*
* @return the (concrete) hypothesis model that automatically transforms input symbols
*/
public abstract CM getTranslatingHypothesisModel();
/**
* Returns the created instance of the provided internal learner.
*
* @return the created instance of the provided internal learner
*/
public L getLearner() {
return this.learner;
}
protected void copyAbstract(UniversalDeterministicAutomaton src,
MutableDeterministic tgt) {
// states
final Map states = new HashMap<>();
final Map statesRev = new HashMap<>();
for (S1 s : src.getStates()) {
final SP sp = src.getStateProperty(s);
final S2 n = tgt.addState(sp);
tgt.setInitial(n, Objects.equals(s, src.getInitialState()));
states.put(n, s);
statesRev.put(s, n);
}
// transitions
for (Entry e : states.entrySet()) {
for (CI r : rep) {
final AbstractAbstractionTree tree = getTreeForRepresentative(r);
final AI a = tree.getAbstractSymbol(r);
tgt.setTransition(e.getKey(),
a,
statesRev.get(src.getSuccessor(e.getValue(), r)),
src.getTransitionProperty(e.getValue(), r));
}
}
}
protected abstract AbstractAbstractionTree getTreeForRepresentative(CI ci);
protected abstract Collection getInitialAbstracts();
protected abstract Collection getInitialRepresentatives();
}