diff --git a/CHANGELOG.md b/CHANGELOG.md index d96d292b84..215013c8b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Added the OSTIA passive learning algorithm, thanks to [Aleksander Mendoza-Drosik](https://github.com/aleksander-mendoza). * Added the OML (optimal-MAT-learner) active learning algorithm, thanks to [Falk Howar](https://github.com/fhowar). * Added a new learning algorithm for systems of procedural automata (SPAs). +* Added Moore versions of the learners `DT`, `TTT`, `LStar`, thanks to [Mohamad Bayram](https://github.com/mohbayram). ### Changed @@ -21,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * The `ADT` class is no longer initialized with a `leafSplitter` but the `extendLeaf` and `splitLeaf` methods take an additional argument. This allows for a more customizable behavior. * The `{DFA,Mealy}CacheOracle`s and the `SULCache` are no longer thread-safe because the intended pipeline of a parallel setup (as suggested by the LearnLib factory methods) consists of a single-threaded cache that delegates to parallel (non-cached) oracles. Here, the synchronization logic only adds unnecessary overhead. In case you want a shared, thread-safe cache (which was currently not conveniently possible to setup) the `learnlib-parallelism` module now contains the `ThreadSafe{DFA,Mealy,SUL}Caches` factories which allow one to construct parallel oracles (whose parameters and return types are tailored towards using our `ParallelOracleBuilders` factory) with a shared cache. See the in-tree `ParallelismExample2` for reference. * `SymbolQueryCache` now needs to be created via the `MealyCaches` factory. +* `AbstractTTTHypothesis` has received an additional type parameter for its state type. ### Removed diff --git a/README.md b/README.md index 6f00be8ca7..13fd8bd257 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,17 @@ While certain features have been stripped for improved modularity, development h Currently, the following learning algorithms with respective target models are supported: -Algorithm (active) | Target models || Algorithm (passive) | Models +Algorithm (active) | Target models || Algorithm (passive) | Models --- | --- | --- | --- | --- -ADT | `Mealy` || OSTIA | `SST` -DHC | `Mealy` || RPNI | `DFA` `Mealy` -Discrimination Tree | `DFA` `Mealy` `VPDA` || RPNI (EDSM) | `DFA` -Kearns & Vazirani | `DFA` `Mealy` || RPNI (MDL) | `DFA` -L* (incl. variants) | `DFA` `Mealy` +ADT | `Mealy` || OSTIA | `SST` +DHC | `Mealy` || RPNI | `DFA` `Mealy` +Discrimination Tree | `DFA` `Mealy` `Moore` `VPDA` || RPNI (EDSM) | `DFA` +Kearns & Vazirani | `DFA` `Mealy` || RPNI (MDL) | `DFA` +L* (incl. variants) | `DFA` `Mealy` `Moore` NL* | `NFA` OML | `DFA` `Mealy` SPA | `SPA` -TTT | `DFA` `Mealy` `VPDA` +TTT | `DFA` `Mealy` `Moore` `VPDA` Additionally, LearnLib offers a variety of tools to ease the practical application of automata learning on real-world systems. diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/moore/DTLearnerMoore.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/moore/DTLearnerMoore.java new file mode 100644 index 0000000000..83cfba7710 --- /dev/null +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/moore/DTLearnerMoore.java @@ -0,0 +1,87 @@ +/* Copyright (C) 2013-2022 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.discriminationtree.moore; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import de.learnlib.algorithms.discriminationtree.AbstractDTLearner; +import de.learnlib.algorithms.discriminationtree.DTLearnerState; +import de.learnlib.algorithms.discriminationtree.hypothesis.HState; +import de.learnlib.algorithms.discriminationtree.hypothesis.HTransition; +import de.learnlib.api.algorithm.LearningAlgorithm.MooreLearner; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.AbstractQuery; +import de.learnlib.api.query.Query; +import de.learnlib.counterexamples.LocalSuffixFinder; +import de.learnlib.datastructure.discriminationtree.MultiDTree; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A {@link MooreMachine}-based specialization of the DT learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author bayram + * @author frohme + */ +public class DTLearnerMoore extends AbstractDTLearner, I, Word, O, Void> + implements MooreLearner { + + private HypothesisWrapperMoore hypWrapper; + + @GenerateBuilder(defaults = AbstractDTLearner.BuilderDefaults.class) + public DTLearnerMoore(Alphabet alphabet, + MembershipOracle> oracle, + LocalSuffixFinder> suffixFinder, + boolean repeatedCounterexampleEvaluation) { + + super(alphabet, oracle, suffixFinder, repeatedCounterexampleEvaluation, new MultiDTree<>(oracle)); + this.hypWrapper = new HypothesisWrapperMoore<>(getHypothesisDS()); + + } + + @Override + protected @Nullable Query> spQuery(HState, O, Void> state) { + return new AbstractQuery>(state.getAccessSequence(), Word.epsilon()) { + + @Override + public void answer(Word output) { + state.setProperty(output.firstSymbol()); + } + }; + } + + @Override + protected @Nullable Query> tpQuery(HTransition, O, Void> transition) { + return null; + } + + @Override + public MooreMachine getHypothesisModel() { + return hypWrapper; + } + + @Override + public void resume(DTLearnerState, O, Void> state) { + super.resume(state); + this.hypWrapper = new HypothesisWrapperMoore<>(getHypothesisDS()); + } +} \ No newline at end of file diff --git a/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/moore/HypothesisWrapperMoore.java b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/moore/HypothesisWrapperMoore.java new file mode 100644 index 0000000000..134220aa6a --- /dev/null +++ b/algorithms/active/discrimination-tree/src/main/java/de/learnlib/algorithms/discriminationtree/moore/HypothesisWrapperMoore.java @@ -0,0 +1,71 @@ +/* Copyright (C) 2013-2022 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.discriminationtree.moore; + +import java.util.Collection; + +import de.learnlib.algorithms.discriminationtree.hypothesis.DTLearnerHypothesis; +import de.learnlib.algorithms.discriminationtree.hypothesis.HState; +import de.learnlib.algorithms.discriminationtree.hypothesis.HTransition; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Word; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A {@link MooreMachine}-based specialization of the DT learner hypothesis. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author bayram + * @author frohme + */ +public class HypothesisWrapperMoore + implements MooreMachine, O, Void>, I, HTransition, O, Void>, O> { + + private final DTLearnerHypothesis, O, Void> dtHypothesis; + + HypothesisWrapperMoore(DTLearnerHypothesis, O, Void> dtHypothesis) { + this.dtHypothesis = dtHypothesis; + } + + @Override + public O getStateOutput(HState, O, Void> state) { + return state.getProperty(); + } + + @Override + public Collection, O, Void>> getStates() { + return dtHypothesis.getStates(); + } + + @Override + public @Nullable HState, O, Void> getInitialState() { + return dtHypothesis.getInitialState(); + } + + @Override + public @Nullable HTransition, O, Void> getTransition(HState, O, Void> state, I input) { + return dtHypothesis.getTransition(state, input); + } + + @Override + public HState, O, Void> getSuccessor(HTransition, O, Void> transition) { + return dtHypothesis.getSuccessor(transition); + } +} \ No newline at end of file diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreGrowingAlphabetTest.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreGrowingAlphabetTest.java new file mode 100644 index 0000000000..80c35231fa --- /dev/null +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreGrowingAlphabetTest.java @@ -0,0 +1,36 @@ +/* Copyright (C) 2013-2022 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.discriminationtree; + +import de.learnlib.algorithms.discriminationtree.moore.DTLearnerMoore; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.counterexamples.LocalSuffixFinders; +import de.learnlib.testsupport.AbstractGrowingAlphabetMooreTest; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class DTLearnerMooreGrowingAlphabetTest + extends AbstractGrowingAlphabetMooreTest> { + + @Override + protected DTLearnerMoore getLearner(MembershipOracle> oracle, + Alphabet alphabet) { + return new DTLearnerMoore<>(alphabet, oracle, LocalSuffixFinders.RIVEST_SCHAPIRE, true); + } +} diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreIT.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreIT.java new file mode 100644 index 0000000000..cb1c48faf5 --- /dev/null +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreIT.java @@ -0,0 +1,47 @@ +/* Copyright (C) 2013-2022 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.discriminationtree; + +import de.learnlib.algorithms.discriminationtree.moore.DTLearnerMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; +import de.learnlib.counterexamples.LocalSuffixFinder; +import de.learnlib.counterexamples.LocalSuffixFinders; +import de.learnlib.testsupport.it.learner.AbstractMooreLearnerIT; +import de.learnlib.testsupport.it.learner.LearnerVariantList.MooreLearnerVariantList; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.testng.annotations.Test; + +@Test +public class DTLearnerMooreIT extends AbstractMooreLearnerIT { + + @Override + protected void addLearnerVariants(Alphabet alphabet, + MooreMembershipOracle mqOracle, + MooreLearnerVariantList variants) { + DTLearnerMooreBuilder builder = new DTLearnerMooreBuilder<>(); + builder.setAlphabet(alphabet); + builder.setOracle(mqOracle); + + for (LocalSuffixFinder> suffixFinder : LocalSuffixFinders.values()) { + builder.setSuffixFinder(suffixFinder); + + String name = "suffixFinder=" + suffixFinder.toString(); + variants.addLearnerVariant(name, builder.create()); + } + } + +} \ No newline at end of file diff --git a/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreResumableLearnerTest.java b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreResumableLearnerTest.java new file mode 100644 index 0000000000..abd8049df7 --- /dev/null +++ b/algorithms/active/discrimination-tree/src/test/java/de/learnlib/algorithms/discriminationtree/DTLearnerMooreResumableLearnerTest.java @@ -0,0 +1,41 @@ +/* Copyright (C) 2013-2022 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.discriminationtree; + +import de.learnlib.algorithms.discriminationtree.moore.DTLearnerMoore; +import de.learnlib.algorithms.discriminationtree.moore.DTLearnerMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.AbstractResumableLearnerMooreTest; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class DTLearnerMooreResumableLearnerTest + extends AbstractResumableLearnerMooreTest, DTLearnerState, Character, Void>> { + + @Override + protected DTLearnerMoore getLearner(final MembershipOracle> oracle, + final Alphabet alphabet) { + return new DTLearnerMooreBuilder().withAlphabet(alphabet).withOracle(oracle).create(); + } + + @Override + protected int getRounds() { + return 5; + } +} diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/ClassicLStarMoore.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/ClassicLStarMoore.java new file mode 100644 index 0000000000..751e963f78 --- /dev/null +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/ClassicLStarMoore.java @@ -0,0 +1,100 @@ +/* Copyright (C) 2013-2022 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.lstar.moore; + +import java.util.Collections; +import java.util.List; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import de.learnlib.algorithms.lstar.AbstractExtensibleAutomatonLStar; +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandler; +import de.learnlib.algorithms.lstar.closing.ClosingStrategy; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.datastructure.observationtable.ObservationTable; +import de.learnlib.datastructure.observationtable.Row; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMoore; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A {@link MooreMachine}-based specialization of the classic L* learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author bayram + * @author frohme + */ +public class ClassicLStarMoore + extends AbstractExtensibleAutomatonLStar, I, @Nullable O, Integer, Integer, O, Void, CompactMoore> { + + @GenerateBuilder(defaults = AbstractExtensibleAutomatonLStar.BuilderDefaults.class) + public ClassicLStarMoore(Alphabet alphabet, + MembershipOracle oracle, + List> initialPrefixes, + List> initialSuffixes, + ObservationTableCEXHandler cexHandler, + ClosingStrategy closingStrategy) { + super(alphabet, + oracle, + new CompactMoore<>(alphabet), + initialPrefixes, + LStarMooreUtil.ensureSuffixCompliancy(initialSuffixes), + cexHandler, + closingStrategy); + } + + @Override + protected MooreMachine exposeInternalHypothesis() { + return internalHyp; + } + + @Override + protected O stateProperty(ObservationTable table, Row stateRow) { + return table.cellContents(stateRow, 0); + } + + @Override + protected Void transitionProperty(ObservationTable table, Row stateRow, int inputIdx) { + return null; + } + + @Override + protected SuffixOutput hypothesisOutput() { + + return new SuffixOutput() { + + @Override + public @Nullable O computeOutput(Iterable input) { + return computeSuffixOutput(Collections.emptyList(), input); + } + + @Override + public @Nullable O computeSuffixOutput(Iterable prefix, Iterable suffix) { + Word wordOut = internalHyp.computeSuffixOutput(prefix, suffix); + if (wordOut.isEmpty()) { + return null; + } + return wordOut.lastSymbol(); + } + }; + } +} \ No newline at end of file diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/ExtensibleLStarMoore.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/ExtensibleLStarMoore.java new file mode 100644 index 0000000000..26a5301a44 --- /dev/null +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/ExtensibleLStarMoore.java @@ -0,0 +1,94 @@ +/* Copyright (C) 2013-2022 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.lstar.moore; + +import java.util.Collections; +import java.util.List; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import de.learnlib.algorithms.lstar.AbstractExtensibleAutomatonLStar; +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandler; +import de.learnlib.algorithms.lstar.closing.ClosingStrategy; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.datastructure.observationtable.OTLearner.OTLearnerMoore; +import de.learnlib.datastructure.observationtable.ObservationTable; +import de.learnlib.datastructure.observationtable.Row; +import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMoore; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * A {@link MooreMachine}-based specialization of the extensible L* learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author bayram + * @author frohme + */ +public class ExtensibleLStarMoore + extends AbstractExtensibleAutomatonLStar, I, Word, Integer, Integer, O, Void, CompactMoore> + implements OTLearnerMoore { + + public ExtensibleLStarMoore(Alphabet alphabet, + MembershipOracle> oracle, + List> initialSuffixes, + ObservationTableCEXHandler> cexHandler, + ClosingStrategy> closingStrategy) { + this(alphabet, oracle, Collections.singletonList(Word.epsilon()), initialSuffixes, cexHandler, closingStrategy); + } + + @GenerateBuilder(defaults = AbstractExtensibleAutomatonLStar.BuilderDefaults.class) + public ExtensibleLStarMoore(Alphabet alphabet, + MembershipOracle> oracle, + List> initialPrefixes, + List> initialSuffixes, + ObservationTableCEXHandler> cexHandler, + ClosingStrategy> closingStrategy) { + super(alphabet, + oracle, + new CompactMoore<>(alphabet), + initialPrefixes, + LStarMooreUtil.ensureSuffixCompliancy(initialSuffixes), + cexHandler, + closingStrategy); + } + + @Override + protected MooreMachine exposeInternalHypothesis() { + return internalHyp; + } + + @Override + protected O stateProperty(ObservationTable> table, Row stateRow) { + Word word = table.cellContents(stateRow, 0); + return word.getSymbol(0); + } + + @Override + protected Void transitionProperty(ObservationTable> table, Row stateRow, int inputIdx) { + return null; + } + + @Override + protected SuffixOutput> hypothesisOutput() { + return internalHyp; + } +} \ No newline at end of file diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/LStarMooreUtil.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/LStarMooreUtil.java new file mode 100644 index 0000000000..3a58905a40 --- /dev/null +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/lstar/moore/LStarMooreUtil.java @@ -0,0 +1,41 @@ +/* Copyright (C) 2013-2022 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.lstar.moore; + +import java.util.ArrayList; +import java.util.List; + +import net.automatalib.words.Word; + +public final class LStarMooreUtil { + + private LStarMooreUtil() { + // prevent instantiation + } + + public static List> ensureSuffixCompliancy(List> suffixes) { + List> compSuffixes = new ArrayList<>(); + compSuffixes.add(Word.epsilon()); + for (Word suff : suffixes) { + if (!suff.isEmpty()) { + compSuffixes.add(suff); + } + } + + return compSuffixes; + } + +} \ No newline at end of file diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliMoore.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliMoore.java new file mode 100644 index 0000000000..d74b2a8686 --- /dev/null +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/malerpnueli/MalerPnueliMoore.java @@ -0,0 +1,44 @@ +/* Copyright (C) 2013-2022 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.malerpnueli; + +import java.util.Collections; +import java.util.List; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.closing.ClosingStrategies; +import de.learnlib.algorithms.lstar.closing.ClosingStrategy; +import de.learnlib.algorithms.lstar.moore.ExtensibleLStarMoore; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +public class MalerPnueliMoore extends ExtensibleLStarMoore { + + public MalerPnueliMoore(Alphabet alphabet, MembershipOracle> oracle) { + this(alphabet, oracle, Collections.emptyList(), ClosingStrategies.CLOSE_FIRST); + } + + @GenerateBuilder(defaults = BuilderDefaults.class) + public MalerPnueliMoore(Alphabet alphabet, + MembershipOracle> oracle, + List> initialSuffixes, + ClosingStrategy> closingStrategy) { + super(alphabet, oracle, initialSuffixes, ObservationTableCEXHandlers.MALER_PNUELI, closingStrategy); + } + +} diff --git a/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireMoore.java b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireMoore.java new file mode 100644 index 0000000000..d3c9d89b51 --- /dev/null +++ b/algorithms/active/lstar/src/main/java/de/learnlib/algorithms/rivestschapire/RivestSchapireMoore.java @@ -0,0 +1,44 @@ +/* Copyright (C) 2013-2022 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.rivestschapire; + +import java.util.Collections; +import java.util.List; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.closing.ClosingStrategies; +import de.learnlib.algorithms.lstar.closing.ClosingStrategy; +import de.learnlib.algorithms.lstar.moore.ExtensibleLStarMoore; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +public class RivestSchapireMoore extends ExtensibleLStarMoore { + + public RivestSchapireMoore(Alphabet alphabet, MembershipOracle> oracle) { + this(alphabet, oracle, Collections.emptyList(), ClosingStrategies.CLOSE_FIRST); + } + + @GenerateBuilder(defaults = BuilderDefaults.class) + public RivestSchapireMoore(Alphabet alphabet, + MembershipOracle> oracle, + List> initialSuffixes, + ClosingStrategy> closingStrategy) { + super(alphabet, oracle, initialSuffixes, ObservationTableCEXHandlers.RIVEST_SCHAPIRE, closingStrategy); + } + +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMooreGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMooreGrowingAlphabetTest.java new file mode 100644 index 0000000000..23c76b0f9f --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMooreGrowingAlphabetTest.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2013-2022 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.lstar; + +import java.util.Collections; + +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.closing.ClosingStrategies; +import de.learnlib.algorithms.lstar.moore.ExtensibleLStarMoore; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.AbstractGrowingAlphabetMooreTest; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class ExtensibleLStarMooreGrowingAlphabetTest + extends AbstractGrowingAlphabetMooreTest> { + + @Override + protected ExtensibleLStarMoore getLearner(MembershipOracle> oracle, + Alphabet alphabet) { + return new ExtensibleLStarMoore<>(alphabet, + oracle, + Collections.emptyList(), + ObservationTableCEXHandlers.FIND_LINEAR_REVERSE, + ClosingStrategies.CLOSE_SHORTEST); + } +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMooreResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMooreResumableLearnerTest.java new file mode 100644 index 0000000000..a156577f3e --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/ExtensibleLStarMooreResumableLearnerTest.java @@ -0,0 +1,54 @@ +/* Copyright (C) 2013-2022 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.lstar; + +import java.util.Random; + +import de.learnlib.algorithms.lstar.moore.ExtensibleLStarMoore; +import de.learnlib.algorithms.lstar.moore.ExtensibleLStarMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.AbstractResumableLearnerMooreTest; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.automata.transducers.impl.compact.CompactMoore; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; + +/** + * @author frohme + */ +public class ExtensibleLStarMooreResumableLearnerTest + extends AbstractResumableLearnerMooreTest, AutomatonLStarState, CompactMoore, Integer>> { + + @Override + protected ExtensibleLStarMoore getLearner(final MembershipOracle> oracle, + final Alphabet alphabet) { + return new ExtensibleLStarMooreBuilder().withAlphabet(alphabet) + .withOracle(oracle) + .create(); + } + + @Override + protected int getRounds() { + return 2; + } + + @Override + protected MooreMachine getTarget(final Alphabet alphabet) { + return RandomAutomata.randomMoore(new Random(42), 100, alphabet, Alphabets.characters('a', 'd')); + } +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMooreGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMooreGrowingAlphabetTest.java new file mode 100644 index 0000000000..235e38505f --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMooreGrowingAlphabetTest.java @@ -0,0 +1,35 @@ +/* Copyright (C) 2013-2022 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.lstar; + +import de.learnlib.algorithms.malerpnueli.MalerPnueliMoore; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.AbstractGrowingAlphabetMooreTest; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class MalerPnueliMooreGrowingAlphabetTest + extends AbstractGrowingAlphabetMooreTest> { + + @Override + protected MalerPnueliMoore getLearner(MembershipOracle> oracle, + Alphabet alphabet) { + return new MalerPnueliMoore<>(alphabet, oracle); + } +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMooreResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMooreResumableLearnerTest.java new file mode 100644 index 0000000000..7ad5fa70df --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/MalerPnueliMooreResumableLearnerTest.java @@ -0,0 +1,40 @@ +/* Copyright (C) 2013-2022 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.lstar; + +import de.learnlib.algorithms.lstar.moore.ExtensibleLStarMoore; +import de.learnlib.algorithms.malerpnueli.MalerPnueliMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class MalerPnueliMooreResumableLearnerTest extends ExtensibleLStarMooreResumableLearnerTest { + + @Override + protected ExtensibleLStarMoore getLearner(final MembershipOracle> oracle, + final Alphabet alphabet) { + + return new MalerPnueliMooreBuilder().withAlphabet(alphabet).withOracle(oracle).create(); + } + + @Override + protected int getRounds() { + return 1; + } +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMooreGrowingAlphabetTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMooreGrowingAlphabetTest.java new file mode 100644 index 0000000000..bf5b3c7d51 --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMooreGrowingAlphabetTest.java @@ -0,0 +1,35 @@ +/* Copyright (C) 2013-2022 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.lstar; + +import de.learnlib.algorithms.rivestschapire.RivestSchapireMoore; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.AbstractGrowingAlphabetMooreTest; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class RivestSchapireMooreGrowingAlphabetTest + extends AbstractGrowingAlphabetMooreTest> { + + @Override + protected RivestSchapireMoore getLearner(MembershipOracle> oracle, + Alphabet alphabet) { + return new RivestSchapireMoore<>(alphabet, oracle); + } +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMooreResumableLearnerTest.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMooreResumableLearnerTest.java new file mode 100644 index 0000000000..39c0759d00 --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/RivestSchapireMooreResumableLearnerTest.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2013-2022 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.lstar; + +import de.learnlib.algorithms.lstar.moore.ExtensibleLStarMoore; +import de.learnlib.algorithms.rivestschapire.RivestSchapireMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class RivestSchapireMooreResumableLearnerTest extends ExtensibleLStarMooreResumableLearnerTest { + + @Override + protected ExtensibleLStarMoore getLearner(final MembershipOracle> oracle, + final Alphabet alphabet) { + + return new RivestSchapireMooreBuilder().withAlphabet(alphabet) + .withOracle(oracle) + .create(); + } + + @Override + protected int getRounds() { + return 3; + } + +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ClassicLStarMooreIT.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ClassicLStarMooreIT.java new file mode 100644 index 0000000000..f4bb52604d --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ClassicLStarMooreIT.java @@ -0,0 +1,50 @@ +/* Copyright (C) 2013-2022 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.lstar.it; + +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandler; +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.closing.ClosingStrategies; +import de.learnlib.algorithms.lstar.closing.ClosingStrategy; +import de.learnlib.algorithms.lstar.moore.ClassicLStarMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.it.learner.AbstractMooreSymLearnerIT; +import de.learnlib.testsupport.it.learner.LearnerVariantList.MooreSymLearnerVariantList; +import net.automatalib.words.Alphabet; + +public class ClassicLStarMooreIT extends AbstractMooreSymLearnerIT { + + @Override + protected void addLearnerVariants(Alphabet alphabet, + MembershipOracle mqOracle, + MooreSymLearnerVariantList variants) { + + ClassicLStarMooreBuilder builder = new ClassicLStarMooreBuilder<>(); + builder.setAlphabet(alphabet); + builder.setOracle(mqOracle); + + for (ObservationTableCEXHandler handler : ObservationTableCEXHandlers.values()) { + builder.setCexHandler(handler); + for (ClosingStrategy closingStrategy : ClosingStrategies.values()) { + builder.setClosingStrategy(closingStrategy); + + String variantName = "cexHandler=" + handler + ",closingStrategy=" + closingStrategy; + variants.addLearnerVariant(variantName, builder.create()); + } + } + } + +} diff --git a/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarMooreIT.java b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarMooreIT.java new file mode 100644 index 0000000000..ce30d8ba21 --- /dev/null +++ b/algorithms/active/lstar/src/test/java/de/learnlib/algorithms/lstar/it/ExtensibleLStarMooreIT.java @@ -0,0 +1,54 @@ +/* Copyright (C) 2013-2022 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.lstar.it; + +import java.util.Arrays; + +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandler; +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.closing.ClosingStrategies; +import de.learnlib.algorithms.lstar.closing.ClosingStrategy; +import de.learnlib.algorithms.lstar.moore.ExtensibleLStarMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; +import de.learnlib.testsupport.it.learner.AbstractMooreLearnerIT; +import de.learnlib.testsupport.it.learner.LearnerVariantList.MooreLearnerVariantList; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +public class ExtensibleLStarMooreIT extends AbstractMooreLearnerIT { + + @Override + protected void addLearnerVariants(Alphabet alphabet, + MooreMembershipOracle mqOracle, + MooreLearnerVariantList variants) { + ExtensibleLStarMooreBuilder builder = new ExtensibleLStarMooreBuilder<>(); + builder.setAlphabet(alphabet); + builder.setOracle(mqOracle); + + builder.setInitialPrefixes(Arrays.asList(Word.epsilon(), Word.fromLetter(alphabet.getSymbol(0)))); + + for (ObservationTableCEXHandler> handler : ObservationTableCEXHandlers.values()) { + builder.setCexHandler(handler); + for (ClosingStrategy> closingStrategy : ClosingStrategies.values()) { + builder.setClosingStrategy(closingStrategy); + + String variantName = "cexHandler=" + handler + ",closingStrategy=" + closingStrategy; + variants.addLearnerVariant(variantName, builder.create()); + } + } + } + +} \ No newline at end of file diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java index fcae6f5283..aaf8c75541 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTHypothesis.java @@ -35,22 +35,29 @@ /** * Hypothesis DFA for the {@link AbstractTTTLearner TTT algorithm}. * + * @param + * state class type * @param * input symbol type + * @param + * output domain type + * @param + * transition type * * @author Malte Isberner */ -public abstract class AbstractTTTHypothesis implements DeterministicAutomaton, I, T>, - FiniteAlphabetAutomaton, I, T>, - DeterministicAutomaton.FullIntAbstraction, - SupportsGrowingAlphabet { +public abstract class AbstractTTTHypothesis, I, D, T> + implements DeterministicAutomaton, + FiniteAlphabetAutomaton, + DeterministicAutomaton.FullIntAbstraction, + SupportsGrowingAlphabet { - protected final List> states = new ArrayList<>(); + protected final List states = new ArrayList<>(); private final Alphabet alphabet; private int alphabetSize; - private TTTState initialState; + private S initialState; /** * Constructor. @@ -64,27 +71,27 @@ public AbstractTTTHypothesis(Alphabet alphabet) { } @Override - public TTTState getInitialState() { + public S getInitialState() { return initialState; } @Override public T getTransition(int stateId, int symIdx) { - TTTState state = states.get(stateId); + S state = states.get(stateId); TTTTransition trans = getInternalTransition(state, symIdx); return mapTransition(trans); } @Override - public T getTransition(TTTState state, I input) { + public T getTransition(S 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. + * 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 @@ -110,7 +117,7 @@ public TTTTransition getInternalTransition(TTTState state, int input * * @return the initial state of this newly initialized automaton */ - public TTTState initialize() { + public S initialize() { assert !isInitialized(); initialState = createState(null); @@ -126,8 +133,8 @@ public boolean isInitialized() { return initialState != null; } - public TTTState createState(TTTTransition parent) { - TTTState state = newState(alphabet.size(), parent, states.size()); + public S createState(TTTTransition parent) { + S state = newState(alphabet.size(), parent, states.size()); states.add(state); if (parent != null) { parent.makeTree(state); @@ -135,9 +142,7 @@ public TTTState createState(TTTTransition parent) { return state; } - protected TTTState newState(int alphabetSize, TTTTransition parent, int id) { - return new TTTState<>(alphabetSize, parent, id); - } + protected abstract S newState(int alphabetSize, TTTTransition parent, int id); @Override public Alphabet getInputAlphabet() { @@ -192,7 +197,7 @@ public void addAlphabetSymbol(I symbol) { } @Override - public Collection> getStates() { + public Collection getStates() { return Collections.unmodifiableList(states); } @@ -216,7 +221,7 @@ public class GraphView implements Graph, TTTEdge> { @Override public Collection> getNodes() { - return states; + return Collections.unmodifiableList(states); } @Override diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java index 776454273b..ba9bf47507 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/AbstractTTTLearner.java @@ -74,12 +74,12 @@ public abstract class AbstractTTTLearner * discriminators at its root. */ protected final BlockList blockList = new BlockList<>(); - protected AbstractTTTHypothesis hypothesis; + protected AbstractTTTHypothesis hypothesis; protected BaseTTTDiscriminationTree dtree; protected AbstractTTTLearner(Alphabet alphabet, MembershipOracle oracle, - AbstractTTTHypothesis hypothesis, + AbstractTTTHypothesis hypothesis, BaseTTTDiscriminationTree dtree, AcexAnalyzer analyzer) { this.alphabet = alphabet; @@ -745,7 +745,7 @@ private void createNewState(AbstractBaseDTNode newNode) { protected abstract D computeHypothesisOutput(TTTState state, Word suffix); - public AbstractTTTHypothesis getHypothesisDS() { + public AbstractTTTHypothesis getHypothesisDS() { return hypothesis; } @@ -951,8 +951,7 @@ public void addAlphabetSymbol(I symbol) { // check if we already have information about the symbol (then the transition is defined) so we don't post // redundant queries - if (this.hypothesis.getInitialState() != null && - this.hypothesis.getSuccessor(this.hypothesis.getInitialState(), symbol) == null) { + if (this.hypothesis.getInitialState() != null && this.hypothesis.getState(Word.fromLetter(symbol)) == null) { final int newSymbolIdx = this.alphabet.getSymbolIndex(symbol); diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java index 7400663a92..f308838c1a 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/base/TTTLearnerState.java @@ -28,17 +28,17 @@ */ public class TTTLearnerState { - private final AbstractTTTHypothesis hypothesis; + private final AbstractTTTHypothesis hypothesis; private final BaseTTTDiscriminationTree discriminationTree; - TTTLearnerState(final AbstractTTTHypothesis hypothesis, + TTTLearnerState(final AbstractTTTHypothesis hypothesis, final BaseTTTDiscriminationTree discriminationTree) { this.hypothesis = hypothesis; this.discriminationTree = discriminationTree; } - AbstractTTTHypothesis getHypothesis() { + AbstractTTTHypothesis getHypothesis() { return hypothesis; } diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java index 59fea4c24e..679e5e68e1 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/dfa/TTTHypothesisDFA.java @@ -16,38 +16,36 @@ package de.learnlib.algorithms.ttt.dfa; import de.learnlib.algorithms.ttt.base.AbstractTTTHypothesis; -import de.learnlib.algorithms.ttt.base.TTTState; import de.learnlib.algorithms.ttt.base.TTTTransition; import net.automatalib.automata.UniversalDeterministicAutomaton; +import net.automatalib.automata.UniversalDeterministicAutomaton.FullIntAbstraction; import net.automatalib.automata.fsa.DFA; import net.automatalib.words.Alphabet; -public class TTTHypothesisDFA extends AbstractTTTHypothesis> - implements DFA, I>, - UniversalDeterministicAutomaton.FullIntAbstraction, Boolean, Void> { +public class TTTHypothesisDFA extends AbstractTTTHypothesis, I, Boolean, TTTStateDFA> + implements DFA, I>, FullIntAbstraction, Boolean, Void> { public TTTHypothesisDFA(Alphabet alphabet) { super(alphabet); } @Override - public TTTState getSuccessor(TTTState transition) { + public TTTStateDFA getSuccessor(TTTStateDFA transition) { return transition; } @Override - protected TTTState mapTransition(TTTTransition internalTransition) { - return internalTransition.getTarget(); + protected TTTStateDFA mapTransition(TTTTransition internalTransition) { + return (TTTStateDFA) internalTransition.getTarget(); } @Override - protected TTTState newState(int alphabetSize, TTTTransition parent, int id) { + protected TTTStateDFA newState(int alphabetSize, TTTTransition parent, int id) { return new TTTStateDFA<>(numInputs(), parent, id); } @Override - public UniversalDeterministicAutomaton.FullIntAbstraction, Boolean, Void> fullIntAbstraction( - Alphabet alphabet) { + public UniversalDeterministicAutomaton.FullIntAbstraction, Boolean, Void> fullIntAbstraction(Alphabet alphabet) { if (alphabet.equals(getInputAlphabet())) { return this; } @@ -60,15 +58,12 @@ public Boolean getStateProperty(int state) { } @Override - public boolean isAccepting(TTTState state) { - if (!(state instanceof TTTStateDFA)) { - throw new IllegalArgumentException("State is not an expected DFA state, but " + state); - } - return ((TTTStateDFA) state).accepting; + public boolean isAccepting(TTTStateDFA state) { + return state.accepting; } @Override - public Void getTransitionProperty(TTTState transition) { + public Void getTransitionProperty(TTTStateDFA transition) { return null; } } diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java index 35a80f926c..3c4b77d056 100644 --- a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/mealy/TTTHypothesisMealy.java @@ -19,13 +19,15 @@ import de.learnlib.algorithms.ttt.base.TTTState; import de.learnlib.algorithms.ttt.base.TTTTransition; import net.automatalib.automata.UniversalDeterministicAutomaton; +import net.automatalib.automata.UniversalDeterministicAutomaton.FullIntAbstraction; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -public class TTTHypothesisMealy extends AbstractTTTHypothesis, TTTTransitionMealy> implements - MealyMachine>, I, TTTTransitionMealy, O>, - UniversalDeterministicAutomaton.FullIntAbstraction, Void, O> { +public class TTTHypothesisMealy + extends AbstractTTTHypothesis>, I, Word, TTTTransitionMealy> implements + MealyMachine>, I, TTTTransitionMealy, O>, + FullIntAbstraction, Void, O> { public TTTHypothesisMealy(Alphabet alphabet) { super(alphabet); @@ -41,6 +43,11 @@ protected TTTTransitionMealy mapTransition(TTTTransition> inter return (TTTTransitionMealy) internalTransition; } + @Override + protected TTTState> newState(int alphabetSize, TTTTransition> parent, int id) { + return new TTTState<>(alphabetSize, parent, id); + } + @Override public UniversalDeterministicAutomaton.FullIntAbstraction, Void, O> fullIntAbstraction( Alphabet alphabet) { diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTDTNodeMoore.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTDTNodeMoore.java new file mode 100644 index 0000000000..7393f922ab --- /dev/null +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTDTNodeMoore.java @@ -0,0 +1,55 @@ +/* Copyright (C) 2013-2022 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.moore; + +import java.util.HashMap; +import java.util.Map; + +import de.learnlib.algorithms.ttt.base.AbstractBaseDTNode; +import de.learnlib.algorithms.ttt.base.TTTState; +import net.automatalib.automata.transducers.MooreMachine; + +/** + * A {@link MooreMachine}-based specialization of the DT node. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author bayram + * @author frohme + */ +public class TTTDTNodeMoore extends AbstractBaseDTNode { + + public TTTDTNodeMoore() { + this(null, null); + } + + public TTTDTNodeMoore(AbstractBaseDTNode parent, D parentEdgeLabel) { + super(parent, parentEdgeLabel); + } + + @Override + protected Map> createChildMap() { + return new HashMap<>(); + } + + @Override + protected AbstractBaseDTNode createChild(D outcome, TTTState data) { + return new TTTDTNodeMoore<>(this, outcome); + } +} \ No newline at end of file diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTHypothesisMoore.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTHypothesisMoore.java new file mode 100644 index 0000000000..a279b32cca --- /dev/null +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTHypothesisMoore.java @@ -0,0 +1,91 @@ +/* Copyright (C) 2013-2022 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.moore; + +import de.learnlib.algorithms.ttt.base.AbstractTTTHypothesis; +import de.learnlib.algorithms.ttt.base.TTTTransition; +import net.automatalib.automata.UniversalDeterministicAutomaton; +import net.automatalib.automata.UniversalDeterministicAutomaton.FullIntAbstraction; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * A {@link MooreMachine}-based specialization of the TTT hypothesis. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author bayram + * @author frohme + */ +public class TTTHypothesisMoore + extends AbstractTTTHypothesis, I, Word, TTTStateMoore> + implements MooreMachine, I, TTTStateMoore, O>, + FullIntAbstraction, O, Void> { + + /** + * Constructor. + * + * @param alphabet + * the input alphabet + */ + public TTTHypothesisMoore(Alphabet alphabet) { + super(alphabet); + } + + @Override + protected TTTStateMoore mapTransition(TTTTransition> internalTransition) { + return (TTTStateMoore) internalTransition.getTarget(); + } + + @Override + public O getStateProperty(int state) { + TTTStateMoore mooreState = states.get(state); + return mooreState.getOutput(); + + } + + @Override + protected TTTStateMoore newState(int alphabetSize, TTTTransition> parent, int id) { + return new TTTStateMoore<>(alphabetSize, parent, id); + } + + @Override + public UniversalDeterministicAutomaton.FullIntAbstraction, O, Void> fullIntAbstraction(Alphabet alphabet) { + if (alphabet.equals(getInputAlphabet())) { + return this; + } + return MooreMachine.super.fullIntAbstraction(alphabet); + } + + @Override + public O getStateOutput(TTTStateMoore state) { + return state.getOutput(); + } + + @Override + public TTTStateMoore getSuccessor(TTTStateMoore transition) { + return transition; + } + + @Override + public Void getTransitionProperty(TTTStateMoore state) { + return null; + } +} \ No newline at end of file diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTLearnerMoore.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTLearnerMoore.java new file mode 100644 index 0000000000..11e1f51dc6 --- /dev/null +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTLearnerMoore.java @@ -0,0 +1,133 @@ +/* Copyright (C) 2013-2022 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.moore; + +import com.github.misberner.buildergen.annotations.GenerateBuilder; +import de.learnlib.acex.AcexAnalyzer; +import de.learnlib.algorithms.ttt.base.AbstractBaseDTNode; +import de.learnlib.algorithms.ttt.base.AbstractTTTLearner; +import de.learnlib.algorithms.ttt.base.BaseTTTDiscriminationTree; +import de.learnlib.algorithms.ttt.base.OutputInconsistency; +import de.learnlib.algorithms.ttt.base.TTTState; +import de.learnlib.algorithms.ttt.base.TTTTransition; +import de.learnlib.api.algorithm.LearningAlgorithm.MooreLearner; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.counterexamples.acex.MooreOutInconsPrefixTransformAcex; +import de.learnlib.counterexamples.acex.OutInconsPrefixTransformAcex; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; + +/** + * A {@link MooreMachine}-based specialization of the TTT learner. + * + * @param + * input symbol type + * @param + * output symbols type + * + * @author bayram + * @author frohme + */ +public class TTTLearnerMoore extends AbstractTTTLearner, I, Word> + implements MooreLearner { + + @GenerateBuilder(defaults = AbstractTTTLearner.BuilderDefaults.class) + public TTTLearnerMoore(Alphabet alphabet, MembershipOracle> oracle, AcexAnalyzer analyzer) { + super(alphabet, + oracle, + new TTTHypothesisMoore<>(alphabet), + new BaseTTTDiscriminationTree<>(oracle, TTTDTNodeMoore::new), + analyzer); + + dtree.getRoot().split(Word.epsilon(), oracle.answerQuery(Word.epsilon())); + } + + @Override + protected Word succEffect(Word effect) { + return effect.subWord(1); + } + + @Override + protected Word predictSuccOutcome(TTTTransition> trans, + AbstractBaseDTNode> succSeparator) { + TTTStateMoore curr = (TTTStateMoore) trans.getSource(); + return succSeparator.subtreeLabel(trans.getDTTarget()).prepend(curr.getOutput()); + } + + @Override + protected void initializeState(TTTState> state) { + super.initializeState(state); + + TTTStateMoore mooreState = (TTTStateMoore) state; + O output = dtree.getRoot().subtreeLabel(mooreState.getDTLeaf()).firstSymbol(); + assert output != null; + mooreState.setOutput(output); + } + + @Override + protected OutInconsPrefixTransformAcex> deriveAcex(OutputInconsistency> outIncons) { + TTTState> source = outIncons.srcState; + Word suffix = outIncons.suffix; + + OutInconsPrefixTransformAcex> acex = new MooreOutInconsPrefixTransformAcex<>(suffix, + oracle, + w -> getDeterministicState( + source, + w).getAccessSequence()); + + acex.setEffect(0, outIncons.targetOut); + Word lastHypOut = computeHypothesisOutput(getAnySuccessor(source, suffix), Word.epsilon()); + acex.setEffect(suffix.length(), lastHypOut); + + return acex; + } + + @Override + protected Word computeHypothesisOutput(TTTState> state, Word suffix) { + + TTTStateMoore curr = (TTTStateMoore) state; + + WordBuilder wb = new WordBuilder<>(suffix.length()); + + wb.append(curr.output); + if (suffix.length() == 0) { + + return wb.toWord(); + } + for (I sym : suffix) { + curr = (TTTStateMoore) getAnySuccessor(curr, sym); + wb.append(curr.output); + + } + return wb.toWord(); + + } + + @Override + protected AbstractBaseDTNode> createNewNode(AbstractBaseDTNode> parent, + Word parentOutput) { + return new TTTDTNodeMoore<>(parent, parentOutput); + } + + @Override + @SuppressWarnings("unchecked") // parent class uses the same instance that we pass in the constructor + public TTTHypothesisMoore getHypothesisModel() { + return (TTTHypothesisMoore) hypothesis; + } + +} \ No newline at end of file diff --git a/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTStateMoore.java b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTStateMoore.java new file mode 100644 index 0000000000..fa19c55cf5 --- /dev/null +++ b/algorithms/active/ttt/src/main/java/de/learnlib/algorithms/ttt/moore/TTTStateMoore.java @@ -0,0 +1,49 @@ +/* Copyright (C) 2013-2022 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.moore; + +import de.learnlib.algorithms.ttt.base.TTTState; +import de.learnlib.algorithms.ttt.base.TTTTransition; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Word; + +/** + * A {@link MooreMachine}-specific state of the {@link TTTHypothesisMoore} class. + * + * @param + * input symbol type + * @param + * output symbols type + * + * @author bayram + * @author frohme + */ +public class TTTStateMoore extends TTTState> { + + O output; + + public TTTStateMoore(int initialAlphabetSize, TTTTransition> parentTransition, int id) { + super(initialAlphabetSize, parentTransition, id); + } + + public O getOutput() { + return output; + } + + public void setOutput(O output) { + this.output = output; + } +} \ No newline at end of file diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMooreGrowingAlphabetTest.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMooreGrowingAlphabetTest.java new file mode 100644 index 0000000000..d46d25a986 --- /dev/null +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMooreGrowingAlphabetTest.java @@ -0,0 +1,36 @@ +/* Copyright (C) 2013-2022 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; + +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.algorithms.ttt.moore.TTTLearnerMoore; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.AbstractGrowingAlphabetMooreTest; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class TTTLearnerMooreGrowingAlphabetTest + extends AbstractGrowingAlphabetMooreTest> { + + @Override + protected TTTLearnerMoore getLearner(MembershipOracle> oracle, + Alphabet alphabet) { + return new TTTLearnerMoore<>(alphabet, oracle, AcexAnalyzers.LINEAR_FWD); + } +} diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMooreResumableLearnerTest.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMooreResumableLearnerTest.java new file mode 100644 index 0000000000..e6eea00cd1 --- /dev/null +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/TTTLearnerMooreResumableLearnerTest.java @@ -0,0 +1,44 @@ +/* Copyright (C) 2013-2022 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; + +import de.learnlib.algorithms.ttt.base.TTTLearnerState; +import de.learnlib.algorithms.ttt.moore.TTTLearnerMoore; +import de.learnlib.algorithms.ttt.moore.TTTLearnerMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.AbstractResumableLearnerMooreTest; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * @author frohme + */ +public class TTTLearnerMooreResumableLearnerTest + extends AbstractResumableLearnerMooreTest, TTTLearnerState>> { + + @Override + protected TTTLearnerMoore getLearner(final MembershipOracle> oracle, + final Alphabet alphabet) { + + return new TTTLearnerMooreBuilder().withAlphabet(alphabet).withOracle(oracle).create(); + } + + @Override + protected int getRounds() { + return 6; + } + +} diff --git a/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/moore/it/TTTLearnerMooreIT.java b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/moore/it/TTTLearnerMooreIT.java new file mode 100644 index 0000000000..0b6ab4dd47 --- /dev/null +++ b/algorithms/active/ttt/src/test/java/de/learnlib/algorithms/ttt/moore/it/TTTLearnerMooreIT.java @@ -0,0 +1,45 @@ +/* Copyright (C) 2013-2022 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.moore.it; + +import de.learnlib.acex.analyzers.AbstractNamedAcexAnalyzer; +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.algorithms.ttt.moore.TTTLearnerMooreBuilder; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; +import de.learnlib.testsupport.it.learner.AbstractMooreLearnerIT; +import de.learnlib.testsupport.it.learner.LearnerVariantList.MooreLearnerVariantList; +import net.automatalib.words.Alphabet; +import org.testng.annotations.Test; + +@Test +public class TTTLearnerMooreIT extends AbstractMooreLearnerIT { + + @Override + protected void addLearnerVariants(Alphabet alphabet, + MooreMembershipOracle mqOracle, + MooreLearnerVariantList variants) { + + TTTLearnerMooreBuilder builder = new TTTLearnerMooreBuilder<>(); + builder.setAlphabet(alphabet); + builder.setOracle(mqOracle); + + for (AbstractNamedAcexAnalyzer analyzer : AcexAnalyzers.getAllAnalyzers()) { + builder.setAnalyzer(analyzer); + variants.addLearnerVariant("analyzer=" + analyzer, builder.create()); + } + } + +} \ No newline at end of file diff --git a/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java b/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java index 9299738746..47830593a2 100644 --- a/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java +++ b/api/src/main/java/de/learnlib/api/algorithm/LearningAlgorithm.java @@ -19,6 +19,7 @@ import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.words.Word; /** @@ -76,4 +77,6 @@ public interface LearningAlgorithm { interface DFALearner extends LearningAlgorithm, I, Boolean> {} interface MealyLearner extends LearningAlgorithm, I, Word> {} + + interface MooreLearner extends LearningAlgorithm, I, Word> {} } diff --git a/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java b/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java index 49fba63d87..7a813b1551 100644 --- a/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/EquivalenceOracle.java @@ -20,6 +20,7 @@ import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; @@ -84,4 +85,6 @@ interface DFAEquivalenceOracle extends EquivalenceOracle, I, Boolea */ interface MealyEquivalenceOracle extends EquivalenceOracle, I, Word> {} + interface MooreEquivalenceOracle extends EquivalenceOracle, I, Word> {} + } diff --git a/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java b/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java index ded8c7ea31..3e322c6e3f 100644 --- a/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/MembershipOracle.java @@ -98,4 +98,6 @@ interface DFAMembershipOracle extends MembershipOracle {} */ interface MealyMembershipOracle extends MembershipOracle> {} + interface MooreMembershipOracle extends MembershipOracle> {} + } diff --git a/api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java b/api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java index 3611927e7a..0748e28bce 100644 --- a/api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java +++ b/api/src/main/java/de/learnlib/api/oracle/SingleQueryOracle.java @@ -54,4 +54,6 @@ interface SingleQueryOracleDFA extends SingleQueryOracle, DFAMemb interface SingleQueryOracleMealy extends SingleQueryOracle>, MealyMembershipOracle {} + interface SingleQueryOracleMoore extends SingleQueryOracle>, MooreMembershipOracle {} + } diff --git a/build-parent/pom.xml b/build-parent/pom.xml index be8055b3c3..9bb3a89dd4 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -60,10 +60,12 @@ limitations under the License. de/learnlib/filter/statistic/**/DFA*.class de/learnlib/filter/statistic/**/Mealy*.class + de/learnlib/filter/statistic/**/Moore*.class de/learnlib/oracle/emptiness/DFA*.class de/learnlib/oracle/emptiness/Mealy*.class de/learnlib/oracle/equivalence/DFA*.class de/learnlib/oracle/equivalence/Mealy*.class + de/learnlib/oracle/equivalence/Moore*.class de/learnlib/oracle/property/DFA*Chain.class de/learnlib/oracle/property/Mealy*Chain.class diff --git a/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/MooreOutInconsPrefixTransformAcex.java b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/MooreOutInconsPrefixTransformAcex.java new file mode 100644 index 0000000000..f9b9f5fac1 --- /dev/null +++ b/commons/counterexamples/src/main/java/de/learnlib/counterexamples/acex/MooreOutInconsPrefixTransformAcex.java @@ -0,0 +1,36 @@ +/* Copyright (C) 2013-2022 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.counterexamples.acex; + +import java.util.function.Function; + +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.words.Word; + +public class MooreOutInconsPrefixTransformAcex extends OutInconsPrefixTransformAcex> { + + public MooreOutInconsPrefixTransformAcex(Word suffix, + MembershipOracle> oracle, + Function, Word> asTransform) { + super(suffix, suffix.length() + 1, oracle, asTransform); + } + + @Override + public boolean checkEffects(Word eff1, Word eff2) { + return eff2.isSuffixOf(eff1); + } + +} \ No newline at end of file diff --git a/commons/util/src/main/java/de/learnlib/util/Experiment.java b/commons/util/src/main/java/de/learnlib/util/Experiment.java index bc0a6b8238..f6ed4bda76 100644 --- a/commons/util/src/main/java/de/learnlib/util/Experiment.java +++ b/commons/util/src/main/java/de/learnlib/util/Experiment.java @@ -23,6 +23,7 @@ import de.learnlib.util.statistics.SimpleProfiler; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; @@ -178,4 +179,15 @@ public MealyExperiment(LearningAlgorithm, I, } } + + public static class MooreExperiment extends Experiment> { + + public MooreExperiment(LearningAlgorithm, I, Word> learningAlgorithm, + EquivalenceOracle, I, Word> equivalenceAlgorithm, + Alphabet inputs) { + super(learningAlgorithm, equivalenceAlgorithm, inputs); + } + + } + } diff --git a/commons/util/src/main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java b/commons/util/src/main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java index a820883353..1640d3274b 100644 --- a/commons/util/src/main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java +++ b/commons/util/src/main/java/de/learnlib/util/mealy/MealyLearnerWrapper.java @@ -16,12 +16,12 @@ package de.learnlib.util.mealy; import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.Word; -final class MealyLearnerWrapper, I, O> - implements LearningAlgorithm.MealyLearner { +final class MealyLearnerWrapper, I, O> implements MealyLearner { private final LearningAlgorithm learner; diff --git a/commons/util/src/main/java/de/learnlib/util/mealy/MealyUtil.java b/commons/util/src/main/java/de/learnlib/util/mealy/MealyUtil.java index e656431e24..376440ec9e 100644 --- a/commons/util/src/main/java/de/learnlib/util/mealy/MealyUtil.java +++ b/commons/util/src/main/java/de/learnlib/util/mealy/MealyUtil.java @@ -19,6 +19,7 @@ import java.util.Objects; import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.transducers.MealyMachine; @@ -71,7 +72,7 @@ private static int doFindMismatch(MealyMachine hypothes while (inIt.hasNext() && outIt.hasNext()) { final T trans = hypothesis.getTransition(state, inIt.next()); - if (trans== null) { + if (trans == null) { return NO_MISMATCH; } final O ceOut = outIt.next(); @@ -116,8 +117,7 @@ private static int doFindMismatch(MealyMachine hypothes return new DefaultQuery<>(cePrefix, ceSuffix.prefix(mismatchIdx + 1), ceOut.getSymbol(mismatchIdx)); } - public static , I, O> LearningAlgorithm.MealyLearner wrapSymbolLearner( - LearningAlgorithm learner) { + public static , I, O> MealyLearner wrapSymbolLearner(LearningAlgorithm learner) { return new MealyLearnerWrapper<>(learner); } diff --git a/commons/util/src/main/java/de/learnlib/util/moore/MooreLearnerWrapper.java b/commons/util/src/main/java/de/learnlib/util/moore/MooreLearnerWrapper.java new file mode 100644 index 0000000000..4541a70dad --- /dev/null +++ b/commons/util/src/main/java/de/learnlib/util/moore/MooreLearnerWrapper.java @@ -0,0 +1,50 @@ +/* Copyright (C) 2013-2022 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.util.moore; + +import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.algorithm.LearningAlgorithm.MooreLearner; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Word; + +final class MooreLearnerWrapper, I, O> implements MooreLearner { + + private final LearningAlgorithm learner; + + MooreLearnerWrapper(LearningAlgorithm learner) { + this.learner = learner; + } + + @Override + public void startLearning() { + learner.startLearning(); + } + + @Override + public boolean refineHypothesis(DefaultQuery> ceQuery) { + M hyp = learner.getHypothesisModel(); + DefaultQuery reducedQry = MooreUtil.reduceCounterExample(hyp, ceQuery); + + return reducedQry != null && learner.refineHypothesis(reducedQry); + } + + @Override + public M getHypothesisModel() { + return learner.getHypothesisModel(); + } + +} diff --git a/commons/util/src/main/java/de/learnlib/util/moore/MooreUtil.java b/commons/util/src/main/java/de/learnlib/util/moore/MooreUtil.java new file mode 100644 index 0000000000..9382914afa --- /dev/null +++ b/commons/util/src/main/java/de/learnlib/util/moore/MooreUtil.java @@ -0,0 +1,80 @@ +/* Copyright (C) 2013-2022 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.util.moore; + +import java.util.Objects; + +import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.algorithm.LearningAlgorithm.MooreLearner; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Word; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Utility class helping to unify various approaches to actively learning Moore machines. + * + * @author frohme + */ +public final class MooreUtil { + + public static final int NO_MISMATCH = -1; + + private MooreUtil() { + // prevent instantiation + } + + public static int findMismatch(Word out1, Word out2) { + int len = out1.length(); + assert len == out2.length(); + + for (int i = 0; i < len; i++) { + O sym1 = out1.getSymbol(i); + O sym2 = out2.getSymbol(i); + + if (!Objects.equals(sym1, sym2)) { + return i; + } + } + + return NO_MISMATCH; + } + + public static @Nullable DefaultQuery reduceCounterExample(MooreMachine hypothesis, + DefaultQuery> ceQuery) { + Word cePrefix = ceQuery.getPrefix(), ceSuffix = ceQuery.getSuffix(); + Word hypOut = hypothesis.computeSuffixOutput(cePrefix, ceSuffix); + Word ceOut = ceQuery.getOutput(); + assert ceOut.length() == hypOut.length(); + + int mismatchIdx = findMismatch(hypOut, ceOut); + if (mismatchIdx == NO_MISMATCH) { + return null; + } + + return new DefaultQuery<>(cePrefix, ceSuffix.prefix(mismatchIdx), ceOut.getSymbol(mismatchIdx)); + } + + public static , I, O> MooreLearner wrapSymbolLearner(LearningAlgorithm learner) { + return new MooreLearnerWrapper<>(learner); + } + + public static MembershipOracle wrapWordOracle(MembershipOracle> oracle) { + return new SymbolOracleWrapper<>(oracle); + } + +} diff --git a/commons/util/src/main/java/de/learnlib/util/moore/SymbolOracleWrapper.java b/commons/util/src/main/java/de/learnlib/util/moore/SymbolOracleWrapper.java new file mode 100644 index 0000000000..47424a12d2 --- /dev/null +++ b/commons/util/src/main/java/de/learnlib/util/moore/SymbolOracleWrapper.java @@ -0,0 +1,92 @@ +/* Copyright (C) 2013-2022 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.util.moore; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.Query; +import net.automatalib.words.Word; + +/** + * Word-to-Symbol-Oracle adapter. + *

+ * Wraps an oracle which uses {@link Word}s as its output to an oracle which only yields the last symbol of each + * output. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +final class SymbolOracleWrapper implements MembershipOracle { + + private final MembershipOracle> wordOracle; + + /** + * Constructor. + * + * @param wordOracle + * the {@link MembershipOracle} returning output words. + */ + SymbolOracleWrapper(MembershipOracle> wordOracle) { + this.wordOracle = wordOracle; + } + + @Override + public void processQueries(Collection> queries) { + List> lsQueries = new ArrayList<>(queries.size()); + for (Query qry : queries) { + lsQueries.add(new LastSymbolQuery<>(qry)); + } + + wordOracle.processQueries(lsQueries); + } + + private static final class LastSymbolQuery extends Query> { + + private final Query originalQuery; + + LastSymbolQuery(Query originalQuery) { + this.originalQuery = originalQuery; + } + + @Override + public void answer(Word output) { + assert !output.isEmpty(); + originalQuery.answer(output.lastSymbol()); + } + + @Override + public Word getPrefix() { + return originalQuery.getPrefix(); + } + + @Override + public Word getSuffix() { + return originalQuery.getSuffix(); + } + + @Override + public String toString() { + return originalQuery.toString(); + } + } +} diff --git a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDTNode.java b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDTNode.java index a655a957ea..6014e6236b 100644 --- a/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDTNode.java +++ b/datastructures/discrimination-tree/src/main/java/de/learnlib/datastructure/discriminationtree/model/AbstractDTNode.java @@ -88,6 +88,19 @@ public SplitResult split(DSCR discriminator, O oldOut, O newOut, D newData) { return new SplitResult(nodeOld, nodeNew); } + public N split(DSCR discriminator, O out) { + assert this.isLeaf(); + + this.children = createChildMap(); + + final N nodeOld = addChild(out, this.data); + + this.data = null; + this.discriminator = discriminator; + + return nodeOld; + } + public boolean isLeaf() { return children == null; } diff --git a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/OTLearner.java b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/OTLearner.java index 7721792e94..88e7c2a17d 100644 --- a/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/OTLearner.java +++ b/datastructures/observation-table/src/main/java/de/learnlib/datastructure/observationtable/OTLearner.java @@ -18,6 +18,7 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.words.Word; public interface OTLearner extends LearningAlgorithm, ObservationTableFeature { @@ -25,4 +26,6 @@ public interface OTLearner extends LearningAlgorithm, Observat interface OTLearnerDFA extends DFALearner, OTLearner, I, Boolean> {} interface OTLearnerMealy extends MealyLearner, OTLearner, I, Word> {} + + interface OTLearnerMoore extends MooreLearner, OTLearner, I, Word> {} } diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java index e86983868b..b633411a44 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java @@ -21,9 +21,11 @@ import com.google.common.collect.Streams; import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; import de.learnlib.buildtool.refinement.annotation.Interface; @@ -31,6 +33,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.commons.util.collections.CollectionsUtil; import net.automatalib.words.Word; @@ -63,6 +66,15 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreCompleteExplorationEQOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class CompleteExplorationEQOracle, I, D> extends AbstractTestWordEQOracle { private final int minDepth; diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EQOracleChain.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EQOracleChain.java index 6c8f6c1641..13779a07c6 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EQOracleChain.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/EQOracleChain.java @@ -23,6 +23,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; @@ -30,6 +31,7 @@ import de.learnlib.buildtool.refinement.annotation.Map; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; @@ -51,6 +53,15 @@ to = MealyEquivalenceOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreEQOracleChain", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = EquivalenceOracle.class, + to = MooreEquivalenceOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class EQOracleChain implements EquivalenceOracle { private final List> oracles; diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java index 1faa59dcc7..51d54b3a23 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java @@ -21,9 +21,11 @@ import com.google.common.collect.Streams; import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; import de.learnlib.buildtool.refinement.annotation.Interface; @@ -32,6 +34,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.util.automata.conformance.IncrementalWMethodTestsIterator; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -54,6 +57,15 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreIncrementalWMethodEQOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class IncrementalWMethodEQOracle & Output, I, D> extends AbstractTestWordEQOracle { diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java index d078df322b..aa10e7e7f5 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java @@ -23,9 +23,11 @@ import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; import de.learnlib.buildtool.refinement.annotation.Interface; @@ -34,6 +36,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.cover.Covers; import net.automatalib.words.Word; @@ -80,6 +83,15 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreRandomWMethodEQOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class RandomWMethodEQOracle & Output, I, D> extends AbstractTestWordEQOracle { diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java index 177c65e640..fc0bad43e3 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java @@ -22,9 +22,11 @@ import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; import de.learnlib.buildtool.refinement.annotation.Interface; @@ -32,6 +34,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.commons.util.collections.CollectionsUtil; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; @@ -57,6 +60,15 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreRandomWordsEQOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class RandomWordsEQOracle, I, D> extends AbstractTestWordEQOracle { private final Random random; diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java index 318053a810..5f521947c4 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java @@ -23,9 +23,11 @@ import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; import de.learnlib.buildtool.refinement.annotation.Interface; @@ -34,6 +36,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.commons.util.mappings.MutableMapping; import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.cover.Covers; @@ -81,6 +84,15 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreRandomWpMethodEQOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class RandomWpMethodEQOracle & Output, I, D> extends AbstractTestWordEQOracle { diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java index c5b96a169f..d01b2be3dc 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/SimulatorEQOracle.java @@ -20,6 +20,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.query.DefaultQuery; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; @@ -29,6 +30,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.util.automata.Automata; import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; @@ -51,6 +53,15 @@ to = MealyMachine.class, withGenerics = {"?", "I", "?", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreSimulatorEQOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = UniversalDeterministicAutomaton.class, + to = MooreMachine.class, + withGenerics = {"?", "I", "?", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class SimulatorEQOracle, I, D> implements EquivalenceOracle { diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java index c7335d7a89..5e7baa2a0b 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java @@ -21,9 +21,11 @@ import com.google.common.collect.Streams; import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; import de.learnlib.buildtool.refinement.annotation.Interface; @@ -32,6 +34,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.util.automata.conformance.WMethodTestsIterator; import net.automatalib.words.Word; @@ -67,6 +70,15 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreWMethodEQOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class WMethodEQOracle & Output, I, D> extends AbstractTestWordEQOracle { diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java index 1e1968f3e2..c0615299b1 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WpMethodEQOracle.java @@ -21,9 +21,11 @@ import com.google.common.collect.Streams; import de.learnlib.api.oracle.EquivalenceOracle.DFAEquivalenceOracle; import de.learnlib.api.oracle.EquivalenceOracle.MealyEquivalenceOracle; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; import de.learnlib.buildtool.refinement.annotation.Interface; @@ -32,6 +34,7 @@ import net.automatalib.automata.concepts.Output; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.util.automata.conformance.WpMethodTestsIterator; import net.automatalib.words.Word; @@ -67,6 +70,15 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyEquivalenceOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreWpMethodEQOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic(clazz = MooreMachine.class, generics = {"?", "I", "?", "O"}), + @Generic("I"), + @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreEquivalenceOracle.class, generics = {"I", "O"})) public class WpMethodEQOracle & Output, I, D> extends AbstractTestWordEQOracle { diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterOracle.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterOracle.java index beb0dfe0a1..fd7353d1dd 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterOracle.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/CounterOracle.java @@ -21,6 +21,7 @@ import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.api.statistic.StatisticOracle; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; @@ -49,6 +50,13 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyMembershipOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreCounterOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic("I"), @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreMembershipOracle.class, generics = {"I", "O"})) public class CounterOracle implements StatisticOracle { private final Counter counter; diff --git a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/JointCounterOracle.java b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/JointCounterOracle.java index ff07d733e4..08409f9d39 100644 --- a/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/JointCounterOracle.java +++ b/oracles/filters/statistics/src/main/java/de/learnlib/filter/statistic/oracle/JointCounterOracle.java @@ -21,6 +21,7 @@ import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.oracle.MembershipOracle.DFAMembershipOracle; import de.learnlib.api.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; import de.learnlib.api.query.Query; import de.learnlib.buildtool.refinement.annotation.GenerateRefinement; import de.learnlib.buildtool.refinement.annotation.Generic; @@ -53,6 +54,13 @@ to = MealyMembershipOracle.class, withGenerics = {"I", "O"}), interfaces = @Interface(clazz = MealyMembershipOracle.class, generics = {"I", "O"})) +@GenerateRefinement(name = "MooreJointCounterOracle", + generics = {"I", "O"}, + parentGenerics = {@Generic("I"), @Generic(clazz = Word.class, generics = "O")}, + parameterMapping = @Map(from = MembershipOracle.class, + to = MooreMembershipOracle.class, + withGenerics = {"I", "O"}), + interfaces = @Interface(clazz = MooreMembershipOracle.class, generics = {"I", "O"})) public class JointCounterOracle implements MembershipOracle { private final MembershipOracle delegate; diff --git a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOracle.java b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOracle.java index 94255170c8..8b890d0ba8 100644 --- a/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOracle.java +++ b/oracles/membership-oracles/src/main/java/de/learnlib/oracle/membership/SimulatorOracle.java @@ -23,6 +23,7 @@ import net.automatalib.automata.concepts.SuffixOutput; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.words.Word; /** @@ -78,4 +79,12 @@ public MealySimulatorOracle(MealyMachine mealy) { } } + public static class MooreSimulatorOracle extends SimulatorOracle> + implements SingleQueryOracleMoore { + + public MooreSimulatorOracle(MooreMachine moore) { + super(moore); + } + } + } diff --git a/pom.xml b/pom.xml index 625720a8d6..edeeed2b7d 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,14 @@ limitations under the License. Developer + + Mohamad Bayram + TU Dortmund, Chair for Programming Systems + http://ls5-www.cs.tu-dortmund.de/ + + Developer (Graduate) + + Jeroen Meijer j.j.g.meijer@utwente.nl diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMooreTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMooreTest.java new file mode 100644 index 0000000000..2c76ed589b --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractGrowingAlphabetMooreTest.java @@ -0,0 +1,69 @@ +/* Copyright (C) 2013-2022 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.testsupport; + +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.function.Consumer; + +import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.oracle.QueryAnswerer; +import net.automatalib.SupportsGrowingAlphabet; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; + +/** + * @author frohme + */ +public abstract class AbstractGrowingAlphabetMooreTest & LearningAlgorithm, Character, Word>> + extends AbstractGrowingAlphabetTest, MembershipOracle>, Character, Word> { + + @Override + protected Alphabet getInitialAlphabet() { + return Alphabets.characters('0', '4'); + } + + @Override + protected Collection getAlphabetExtensions() { + return Alphabets.characters('5', '9'); + } + + @Override + protected MooreMachine getTarget(Alphabet alphabet) { + return RandomAutomata.randomMoore(new Random(RANDOM_SEED), + DEFAULT_AUTOMATON_SIZE, + alphabet, + Alphabets.characters('a', 'f')); + } + + @Override + protected MembershipOracle> getOracle(MooreMachine target) { + return ((QueryAnswerer>) target::computeSuffixOutput).asOracle(); + } + + @Override + protected MembershipOracle> getCachedOracle(Alphabet alphabet, + MembershipOracle> source, + List> symbolListener) { + // TODO: implement Moore caches + return source; + } +} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMooreTest.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMooreTest.java new file mode 100644 index 0000000000..61d5c6aae0 --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/AbstractResumableLearnerMooreTest.java @@ -0,0 +1,62 @@ +/* Copyright (C) 2013-2022 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.testsupport; + +import java.util.Random; + +import de.learnlib.api.Resumable; +import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.oracle.EquivalenceOracle.MooreEquivalenceOracle; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.oracle.QueryAnswerer; +import de.learnlib.oracle.equivalence.MooreSimulatorEQOracle; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; + +/** + * @author frohme + */ +public abstract class AbstractResumableLearnerMooreTest & LearningAlgorithm, Character, Word>, T> + extends AbstractResumableLearnerTest, MembershipOracle>, Character, Word, T> { + + private static final int AUTOMATON_SIZE = 20; + + @Override + protected Alphabet getInitialAlphabet() { + return Alphabets.characters('1', '4'); + } + + @Override + protected MooreMachine getTarget(Alphabet alphabet) { + return RandomAutomata.randomMoore(new Random(RANDOM_SEED), + AUTOMATON_SIZE, + alphabet, + Alphabets.characters('a', 'd')); + } + + @Override + protected MembershipOracle> getOracle(MooreMachine target) { + return ((QueryAnswerer>) target::computeSuffixOutput).asOracle(); + } + + @Override + protected MooreEquivalenceOracle getEquivalenceOracle(MooreMachine target) { + return new MooreSimulatorEQOracle<>(target); + } +} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java index b2f448b1b4..140e486d34 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMealySymLearnerIT.java @@ -37,7 +37,7 @@ *

* Mealy machine learning algorithms tested by this integration test are expected to assume membership queries yield * only the last symbol of the output word. If the learning algorithm expects the full output word for the suffix part - * of the query, use {@link AbstractMealySymLearnerIT}. + * of the query, use {@link AbstractMealyLearnerIT}. * * @author Malte Isberner */ diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMooreLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMooreLearnerIT.java new file mode 100644 index 0000000000..fe045c6f4e --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMooreLearnerIT.java @@ -0,0 +1,82 @@ +/* Copyright (C) 2013-2022 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.testsupport.it.learner; + +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; +import de.learnlib.examples.LearningExample.MooreLearningExample; +import de.learnlib.examples.LearningExamples; +import de.learnlib.oracle.equivalence.SimulatorEQOracle; +import de.learnlib.oracle.membership.SimulatorOracle.MooreSimulatorOracle; +import de.learnlib.testsupport.it.learner.LearnerVariantList.MooreLearnerVariantList; +import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.MooreLearnerVariantListImpl; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.testng.annotations.Factory; + +/** + * Abstract integration test for Moore machine learning algorithms. + *

+ * Moore machine learning algorithms tested by this integration test are expected to assume membership queries yield the + * full output word corresponding to the suffix part of the query. + * + * @author frohme + */ +public abstract class AbstractMooreLearnerIT { + + @Factory + public Object[] createExampleITCases() { + final List> examples = LearningExamples.createMooreExamples(); + final List> result = new ArrayList<>(examples.size()); + + for (MooreLearningExample example : examples) { + result.addAll(createAllVariantsITCase(example)); + } + + return result.toArray(); + } + + private List, MooreMachine>> createAllVariantsITCase( + MooreLearningExample example) { + + final Alphabet alphabet = example.getAlphabet(); + final MooreMembershipOracle mqOracle = new MooreSimulatorOracle<>(example.getReferenceAutomaton()); + final MooreLearnerVariantListImpl variants = new MooreLearnerVariantListImpl<>(); + addLearnerVariants(alphabet, mqOracle, variants); + + return LearnerITUtil.createExampleITCases(example, + variants, + new SimulatorEQOracle<>(example.getReferenceAutomaton())); + } + + /** + * Adds, for a given setup, all the variants of the Mealy machine learner to be tested to the specified + * {@link LearnerVariantList variant list}. + * + * @param alphabet + * the input alphabet + * @param mqOracle + * the membership oracle + * @param variants + * list to add the learner variants to + */ + protected abstract void addLearnerVariants(Alphabet alphabet, + MooreMembershipOracle mqOracle, + MooreLearnerVariantList variants); +} \ No newline at end of file diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMooreSymLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMooreSymLearnerIT.java new file mode 100644 index 0000000000..feeda080d6 --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractMooreSymLearnerIT.java @@ -0,0 +1,85 @@ +/* Copyright (C) 2013-2022 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.testsupport.it.learner; + +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.oracle.MembershipOracle.MooreMembershipOracle; +import de.learnlib.examples.LearningExample.MooreLearningExample; +import de.learnlib.examples.LearningExamples; +import de.learnlib.oracle.equivalence.SimulatorEQOracle; +import de.learnlib.oracle.membership.SimulatorOracle.MooreSimulatorOracle; +import de.learnlib.testsupport.it.learner.LearnerVariantList.MooreSymLearnerVariantList; +import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.MooreSymLearnerVariantListImpl; +import de.learnlib.util.moore.MooreUtil; +import net.automatalib.automata.transducers.MooreMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; +import org.testng.annotations.Factory; + +/** + * Abstract integration test for Moore machine learning algorithms. + *

+ * Mealy machine learning algorithms tested by this integration test are expected to assume membership queries yield + * only the last symbol of the output word. If the learning algorithm expects the full output word for the suffix part + * of the query, use {@link AbstractMooreLearnerIT}. + * + * @author frohme + */ +public abstract class AbstractMooreSymLearnerIT { + + @Factory + public Object[] createExampleITCases() { + final List> examples = LearningExamples.createMooreExamples(); + final List> result = new ArrayList<>(examples.size()); + + for (MooreLearningExample example : examples) { + result.addAll(createAllVariantsITCase(example)); + } + + return result.toArray(); + } + + private List, MooreMachine>> createAllVariantsITCase( + MooreLearningExample example) { + + final Alphabet alphabet = example.getAlphabet(); + final MooreMembershipOracle mqOracle = new MooreSimulatorOracle<>(example.getReferenceAutomaton()); + final MooreSymLearnerVariantListImpl variants = new MooreSymLearnerVariantListImpl<>(); + addLearnerVariants(alphabet, MooreUtil.wrapWordOracle(mqOracle), variants); + + return LearnerITUtil.createExampleITCases(example, + variants.getMooreLearnerVariants(), + new SimulatorEQOracle<>(example.getReferenceAutomaton())); + } + + /** + * Adds, for a given setup, all the variants of the Mealy machine learner to be tested to the specified + * {@link LearnerVariantList variant list}. + * + * @param alphabet + * the input alphabet + * @param mqOracle + * the membership oracle + * @param variants + * list to add the learner variants to + */ + protected abstract void addLearnerVariants(Alphabet alphabet, + MembershipOracle mqOracle, + MooreSymLearnerVariantList variants); +} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantList.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantList.java index d13379cc35..91408d9907 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantList.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantList.java @@ -19,6 +19,7 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.spa.SPA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Word; @@ -74,6 +75,10 @@ interface MealyLearnerVariantList extends LearnerVariantList extends LearnerVariantList, I, O> {} + interface MooreLearnerVariantList extends LearnerVariantList, I, Word> {} + + interface MooreSymLearnerVariantList extends LearnerVariantList, I, O> {} + interface OneSEVPALearnerVariantList extends LearnerVariantList, I, Boolean> {} interface SPALearnerVariantList extends LearnerVariantList, I, Boolean> {} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantListImpl.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantListImpl.java index a19f6ff7f0..bcb2a947eb 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantListImpl.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerVariantListImpl.java @@ -20,9 +20,11 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import de.learnlib.util.mealy.MealyUtil; +import de.learnlib.util.moore.MooreUtil; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.spa.SPA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Word; @@ -52,6 +54,10 @@ public static class MealyLearnerVariantListImpl extends LearnerVariantListImpl, I, Word> implements MealyLearnerVariantList {} + public static class MooreLearnerVariantListImpl + extends LearnerVariantListImpl, I, Word> + implements MooreLearnerVariantList {} + public static class OneSEVPALearnerVariantListImpl extends LearnerVariantListImpl, I, Boolean> implements OneSEVPALearnerVariantList {} @@ -78,7 +84,28 @@ public void addLearnerVariant(String name, int maxRounds) { mealyLearnerVariants.addLearnerVariant(name, MealyUtil.wrapSymbolLearner(learner), maxRounds); } + } + + public static class MooreSymLearnerVariantListImpl implements MooreSymLearnerVariantList { + + private final MooreLearnerVariantListImpl mooreLearnerVariants = new MooreLearnerVariantListImpl<>(); + + public MooreLearnerVariantListImpl getMooreLearnerVariants() { + return mooreLearnerVariants; + } + @Override + public void addLearnerVariant(String name, + LearningAlgorithm, I, O> learner) { + addLearnerVariant(name, learner, -1); + } + + @Override + public void addLearnerVariant(String name, + LearningAlgorithm, I, O> learner, + int maxRounds) { + mooreLearnerVariants.addLearnerVariant(name, MooreUtil.wrapSymbolLearner(learner), maxRounds); + } } } diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/DefaultLearningExample.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/DefaultLearningExample.java index 6f4d1cf2a6..a5f333e49e 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/DefaultLearningExample.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/DefaultLearningExample.java @@ -21,6 +21,7 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.spa.SPA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.transducers.SubsequentialTransducer; import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Alphabet; @@ -86,6 +87,18 @@ public DefaultMealyLearningExample(Alphabet alphabet, MealyMachine + extends DefaultLearningExample, MooreMachine> implements MooreLearningExample { + + public & InputAlphabetHolder> DefaultMooreLearningExample(A automaton) { + this(automaton.getInputAlphabet(), automaton); + } + + public DefaultMooreLearningExample(Alphabet alphabet, MooreMachine referenceAutomaton) { + super(alphabet, referenceAutomaton); + } + } + public static class DefaultSSTLearningExample extends DefaultLearningExample, SubsequentialTransducer> implements SSTLearningExample { diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExample.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExample.java index 96b4f019ce..8df545221a 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExample.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExample.java @@ -19,6 +19,7 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.spa.SPA; import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.transducers.StateLocalInputMealyMachine; import net.automatalib.automata.transducers.SubsequentialTransducer; import net.automatalib.automata.vpda.OneSEVPA; @@ -39,6 +40,8 @@ interface DFALearningExample extends UniversalDeterministicLearningExample extends UniversalDeterministicLearningExample> {} + interface MooreLearningExample extends UniversalDeterministicLearningExample> {} + interface SSTLearningExample extends UniversalDeterministicLearningExample> {} diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java index a499a4a03a..5c25778797 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/LearningExamples.java @@ -23,6 +23,7 @@ import de.learnlib.examples.LearningExample.DFALearningExample; import de.learnlib.examples.LearningExample.MealyLearningExample; +import de.learnlib.examples.LearningExample.MooreLearningExample; import de.learnlib.examples.LearningExample.OneSEVPALearningExample; import de.learnlib.examples.LearningExample.SPALearningExample; import de.learnlib.examples.LearningExample.SSTLearningExample; @@ -34,6 +35,7 @@ import de.learnlib.examples.mealy.ExampleCoffeeMachine; import de.learnlib.examples.mealy.ExampleGrid; import de.learnlib.examples.mealy.ExampleRandomMealy; +import de.learnlib.examples.mealy.ExampleRandomMoore; import de.learnlib.examples.mealy.ExampleRandomStateLocalInputMealy; import de.learnlib.examples.mealy.ExampleShahbazGroz; import de.learnlib.examples.mealy.ExampleStack; @@ -96,6 +98,13 @@ public static List> createDFAExamples() { ExampleTinyMealy.createExample()); } + public static List> createMooreExamples() { + return Collections.singletonList(ExampleRandomMoore.createExample(new Random(RANDOM_SEED), + RANDOM_ALPHABET, + RANDOM_SIZE, + RANDOM_MEALY_OUTPUTS)); + } + public static List> createSLIMealyExamples() { return Collections.singletonList(ExampleRandomStateLocalInputMealy.createExample(new Random(RANDOM_SEED), RANDOM_ALPHABET, diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleRandomMoore.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleRandomMoore.java new file mode 100644 index 0000000000..1ecba1f208 --- /dev/null +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleRandomMoore.java @@ -0,0 +1,52 @@ +/* Copyright (C) 2013-2022 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.examples.mealy; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Random; + +import de.learnlib.examples.DefaultLearningExample.DefaultMooreLearningExample; +import net.automatalib.automata.transducers.impl.compact.CompactMoore; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.Alphabet; + +public class ExampleRandomMoore extends DefaultMooreLearningExample { + + @SafeVarargs + public ExampleRandomMoore(Alphabet alphabet, int size, O... outputs) { + this(new Random(), alphabet, size, outputs); + } + + @SafeVarargs + public ExampleRandomMoore(Random random, Alphabet alphabet, int size, O... outputs) { + super(RandomAutomata.randomDeterministic(random, + size, + alphabet, + Arrays.asList(outputs), + Collections.emptyList(), + new CompactMoore<>(alphabet))); + } + + @SafeVarargs + public static ExampleRandomMoore createExample(Random random, + Alphabet alphabet, + int size, + O... outputs) { + return new ExampleRandomMoore<>(random, alphabet, size, outputs); + } + +} \ No newline at end of file