diff --git a/api/src/main/java/de/learnlib/api/Mapper.java b/api/src/main/java/de/learnlib/api/Mapper.java index 959c24775f..a03527c449 100644 --- a/api/src/main/java/de/learnlib/api/Mapper.java +++ b/api/src/main/java/de/learnlib/api/Mapper.java @@ -38,6 +38,18 @@ */ public interface Mapper { + /** + * Method that is invoked before any translation steps on a word are performed. Usually left un-implemented for + * stateless mappers. + */ + default void pre() {} + + /** + * Method that is invoked after all translation steps on a word are performed. Usually left un-implemented for + * stateless mappers. + */ + default void post() {} + /** * Method that maps an abstract input to a corresponding concrete input. * @@ -57,4 +69,47 @@ public interface Mapper { * @return the abstract output */ AO mapOutput(CO concreteOutput); + + /** + * A mapper refinement to establish the contract of a synchronized, symbol-wise translation of input words for + * reactive systems. This means, after each call to {@link #mapInput(Object)} the next call on {@code this} object + * will be {@link #mapOutput(Object)} which is passed the immediate answer to the previously mapped input. + * + * @param + * abstract input symbol type. + * @param + * abstract output symbol type. + * @param + * concrete input symbol type. + * @param + * concrete output symbol type. + * + * @author frohme + * @see AsynchronousMapper + */ + interface SynchronousMapper extends Mapper {} + + /** + * A mapper refinement to establish the contract of a asynchronous, query-wise translation of input words. This + * means, for a sequence of input symbols, {@link #mapInput(Object)} may be called multiple times before any call to + * {@link #mapOutput(Object)} occurs. + *

+ * Especially in the context of translating {@link de.learnlib.api.query.Query queries} for mealy machines, which + * support the concept of un-answered prefixes (combined with answered suffixes) this means, the number of {@link + * #mapInput(Object)} invocations may be larger than the size of the output word passed to the {@link + * #mapOutput(Object)} function. + * + * @param + * abstract input symbol type. + * @param + * abstract output symbol type. + * @param + * concrete input symbol type. + * @param + * concrete output symbol type. + * + * @author frohme + * @see SynchronousMapper + */ + interface AsynchronousMapper extends Mapper {} } diff --git a/drivers/mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java b/drivers/mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java index e2f0a7390a..59141b32d8 100644 --- a/drivers/mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java +++ b/drivers/mapper/src/main/java/de/learnlib/mapper/api/SULMapper.java @@ -20,6 +20,7 @@ import javax.annotation.Nonnull; import de.learnlib.api.Mapper; +import de.learnlib.api.Mapper.SynchronousMapper; import de.learnlib.api.SUL; import de.learnlib.api.exception.SULException; import de.learnlib.mapper.SULMappers; @@ -49,17 +50,7 @@ * * @author Malte Isberner */ -public interface SULMapper extends Mapper { - - /** - * Method that is invoked before any translation steps on a word are performed. - */ - void pre(); - - /** - * Method that is invoked after all translation steps on a word are performed. - */ - void post(); +public interface SULMapper extends SynchronousMapper { /** * Checks whether it is possible to {@link #fork() fork} this mapper. diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/MappedOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/MappedOracle.java index 713af6ff6a..36e815a7db 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/MappedOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/MappedOracle.java @@ -15,14 +15,10 @@ */ package de.learnlib.oracle.membership; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import de.learnlib.api.Mapper; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.api.query.DefaultQuery; -import de.learnlib.api.query.Query; +import de.learnlib.api.Mapper.AsynchronousMapper; +import de.learnlib.api.oracle.QueryAnswerer; +import de.learnlib.api.oracle.SingleQueryOracle; +import net.automatalib.words.Word; /** * A utility class that allows to lift a membership oracle of concrete input/output symbols to a membership oracle of @@ -39,31 +35,26 @@ * * @author frohme */ -public class MappedOracle implements MembershipOracle { +public class MappedOracle implements SingleQueryOracle { - private final MembershipOracle delegate; + private final QueryAnswerer delegate; - private final Mapper mapper; + private final AsynchronousMapper mapper; - public MappedOracle(MembershipOracle delegate, Mapper mapper) { + public MappedOracle(QueryAnswerer delegate, AsynchronousMapper mapper) { this.delegate = delegate; this.mapper = mapper; } @Override - public void processQueries(Collection> queries) { - final List> orderedQueries = new ArrayList<>(queries); - final List> mappedQueries = new ArrayList<>(queries.size()); + public AO answerQuery(Word prefix, Word suffix) { + mapper.pre(); - for (final Query q : orderedQueries) { - mappedQueries.add(new DefaultQuery<>(q.getPrefix().transform(mapper::mapInput), - q.getSuffix().transform(mapper::mapInput))); - } + final CO output = delegate.answerQuery(prefix.transform(mapper::mapInput), suffix.transform(mapper::mapInput)); + final AO result = mapper.mapOutput(output); - this.delegate.processQueries(mappedQueries); + mapper.post(); - for (int i = 0; i < orderedQueries.size(); i++) { - orderedQueries.get(i).answer(mapper.mapOutput(mappedQueries.get(i).getOutput())); - } + return result; } }