de.learnlib.api.oracle.AutomatonOracle Maven / Gradle / Ivy
Show all versions of learnlib-api Show documentation
/* Copyright (C) 2013-2020 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.api.oracle;
import java.util.Collection;
import java.util.Queue;
import java.util.Stack;
import de.learnlib.api.query.DefaultQuery;
import net.automatalib.automata.DeterministicAutomaton;
import net.automatalib.automata.fsa.DFA;
import net.automatalib.automata.transducers.MealyMachine;
import net.automatalib.words.Word;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Finds counterexamples (to particular claims) to an hypothesis, while generating words that are in the given
* hypothesis.
*
* @param the automaton type
* @param the input type
* @param the output type
*
* @author Jeroen Meijer
*/
public interface AutomatonOracle, I, D> {
/**
* Returns whether the given input and output is a counter example for the given hypothesis.
*
* @param hypothesis
* the hypothesis
* @param inputs
* the input sequence
* @param output
* the output corresponding to the input.
*
* @return whether the given input and output is a counter example.
*/
boolean isCounterExample(A hypothesis, Iterable extends I> inputs, D output);
/**
* Returns the next input word, or {@code null} if there is no next input.
*
* Implementations could for example return words in a breadth-first, or depth-first manner.
*
* @return the next input word, or {@code null} if t here is no next input.
*/
@Nullable Word nextInput();
/**
* Add a new input word.
*
* Implementations could add words to e.g. a {@link Stack}, or {@link Queue}.
*
* @param input
* the input word to add.
*/
void addWord(Word input);
/**
* Setup method which is called immediately before
* {@link #findCounterExample(DeterministicAutomaton, Collection, int)} is called.
*/
void pre();
/**
* Returns the multiplier used to compute the number of queries this automaton oracle should perform to
* decide whether a given hypothesis is a counter example.
*
* @return the multiplier
*/
double getMultiplier();
/**
* @see #getMultiplier()
* @param multiplier
* the multiplier
*/
void setMultiplier(double multiplier);
/**
* Processes the given input. Implementations could use membership oracles to process the query.
*
* @param hypothesis
* the hypothesis.
* @param input
* the input to process.
*
* @return the processed query.
*/
DefaultQuery processInput(A hypothesis, Word input);
/**
* Adds words to a datastructure. The key part of the implementation is that undefined inputs will be skipped.
*
* @param hypothesis
* the automaton to add words for.
* @param inputs
* the input alphabet.
* @param prefix
* the current prefix to extend.
*/
default void addWords(A hypothesis, Collection extends I> inputs, Word prefix) {
for (I i : inputs) {
final Word word = prefix.append(i);
// skip undefined inputs
if (!hypothesis.getStates(word).isEmpty()) {
addWord(word);
}
}
}
/**
* Returns whether the given input is accepted by the given hypothesis.
*
* @param hypothesis
* the hypothesis automaton.
* @param input
* the input.
* @param length
* the length of the input.
*
* @return whether the given input is accepted.
*/
boolean accepts(A hypothesis, Iterable extends I> input, int length);
/**
* Find a counterexample for a given {@code hypothesis}.
*
* @param hypothesis
* the hypothesis to find a counter example to.
* @param inputs
* the alphabet.
* @param maxQueries
* the maximum number of queries.
*
* @return the counterexample, or {@code null} if a counter example does not exist.
*/
default @Nullable DefaultQuery findCounterExample(A hypothesis,
Collection extends I> inputs,
int maxQueries) {
pre();
DefaultQuery ce = null;
int queries = 0;
for (Word input = nextInput(); input != null && ce == null && queries != maxQueries; input = nextInput()) {
addWords(hypothesis, inputs, input);
if (accepts(hypothesis, input, input.length())) {
final DefaultQuery query = processInput(hypothesis, input);
ce = isCounterExample(hypothesis, query.getInput(), query.getOutput()) ? query : null;
queries++;
}
}
return ce;
}
/**
* Finds a counter example to the given hypothesis. By default the maximum number of queries performed are
* {@code hypothesis.size() * getMultiplier()}.
*
* @param hypothesis
* the hypothesis automaton.
* @param inputs
* the input alphabet.
*
* @return the counter example, or {@code null} if a counter example does not exist
*/
default @Nullable DefaultQuery findCounterExample(A hypothesis, Collection extends I> inputs) {
return findCounterExample(hypothesis, inputs, (int) (hypothesis.size() * getMultiplier()));
}
interface DFAOracle extends AutomatonOracle, I, Boolean> {
@Override
default boolean accepts(DFA, I> hypothesis, Iterable extends I> input, int length) {
return hypothesis.accepts(input);
}
}
interface MealyOracle extends AutomatonOracle, I, Word> {
@Override
default boolean accepts(MealyMachine, I, ?, O> hypothesis, Iterable extends I> input, int length) {
return hypothesis.computeOutput(input) != null;
}
}
}