From 76a948983341c49d5c4464936cb4af85951bb9c9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 13 Jul 2023 16:58:42 +0200 Subject: [PATCH 01/15] initial import of SBAs and SPMMs --- algorithms/active/spa/pom.xml | 5 + .../de/learnlib/algorithms/sba/ATManager.java | 39 +++ .../algorithms/sba/AlphabetMapper.java | 47 +++ .../algorithms/sba/MappedStackSBA.java | 190 +++++++++++ .../sba/ProceduralMembershipOracle.java | 124 +++++++ .../learnlib/algorithms/sba/SBALearner.java | 313 +++++++++++++++++ .../algorithms/sba/SymbolWrapper.java | 53 +++ .../sba/manager/DefaultATManager.java | 92 +++++ .../sba/manager/OptimizingATManager.java | 240 +++++++++++++ .../learnlib/algorithms/spa/SPALearner.java | 6 +- .../learnlib/algorithms/spmm/ATManager.java | 41 +++ .../algorithms/spmm/MappedStackSPMM.java | 223 ++++++++++++ .../spmm/ProceduralMembershipOracle.java | 161 +++++++++ .../learnlib/algorithms/spmm/SPMMLearner.java | 323 ++++++++++++++++++ .../DiscriminationTreeMealyAdapter.java | 45 +++ .../adapter/KearnsVaziraniMealyAdapter.java | 53 +++ .../spmm/adapter/LStarBaseMealyAdapter.java | 69 ++++ .../adapter/RivestSchapireMealyAdapter.java | 53 +++ .../spmm/adapter/TTTMealyAdapter.java | 50 +++ .../spmm/manager/DefaultATManager.java | 99 ++++++ .../spmm/manager/OptimizingATManager.java | 256 ++++++++++++++ .../algorithms/sba/ATManagerTest.java | 62 ++++ .../de/learnlib/algorithms/sba/SBAIT.java | 80 +++++ .../de/learnlib/algorithms/spa/SPAIT.java | 2 +- .../algorithms/spmm/ATManagerTest.java | 68 ++++ .../de/learnlib/algorithms/spmm/SPMMIT.java | 92 +++++ .../equivalence/sba/SimulatorEQOracle.java | 54 +++ .../equivalence/spmm/SimulatorEQOracle.java | 55 +++ .../spa/WMethodSPAEQOracleTest.java | 2 +- .../spa/WpMethodSPAEQOracleTest.java | 2 +- .../it/learner/AbstractSBALearnerIT.java | 76 +++++ .../it/learner/AbstractSPMMLearnerIT.java | 80 +++++ .../testsupport/it/learner/LearnerITUtil.java | 38 +++ .../it/learner/LearnerVariantList.java | 10 +- .../it/learner/LearnerVariantListImpl.java | 8 + .../it/learner/SBALearnerITCase.java | 41 +++ .../it/learner/SPMMLearnerITCase.java | 41 +++ .../examples/DefaultLearningExample.java | 46 +++ .../de/learnlib/examples/LearningExample.java | 17 + .../learnlib/examples/LearningExamples.java | 33 +- .../examples/sba/ExampleRandomSBA.java | 37 ++ .../examples/spa/ExampleRandomSPA.java | 2 +- .../examples/spmm/ExampleRandomSPMM.java | 38 +++ 43 files changed, 3352 insertions(+), 14 deletions(-) create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ATManager.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/AlphabetMapper.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappedStackSBA.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ProceduralMembershipOracle.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SymbolWrapper.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/DefaultATManager.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/OptimizingATManager.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ATManager.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappedStackSPMM.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ProceduralMembershipOracle.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/DiscriminationTreeMealyAdapter.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/KearnsVaziraniMealyAdapter.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/LStarBaseMealyAdapter.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/RivestSchapireMealyAdapter.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/TTTMealyAdapter.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/DefaultATManager.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/OptimizingATManager.java create mode 100644 algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/ATManagerTest.java create mode 100644 algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/SBAIT.java create mode 100644 algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/ATManagerTest.java create mode 100644 algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/SPMMIT.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java create mode 100644 test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java create mode 100644 test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java create mode 100644 test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SBALearnerITCase.java create mode 100644 test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPMMLearnerITCase.java create mode 100644 test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExampleRandomSBA.java create mode 100644 test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExampleRandomSPMM.java diff --git a/algorithms/active/spa/pom.xml b/algorithms/active/spa/pom.xml index b9163181ca..5dc97d050b 100644 --- a/algorithms/active/spa/pom.xml +++ b/algorithms/active/spa/pom.xml @@ -100,6 +100,11 @@ limitations under the License. buildergen + + org.checkerframework + checker-qual + + de.learnlib diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ATManager.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ATManager.java new file mode 100644 index 0000000000..f1c692e3cd --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ATManager.java @@ -0,0 +1,39 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import de.learnlib.api.AccessSequenceTransformer; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.commons.util.Pair; +import net.automatalib.words.Word; + +public interface ATManager { + + Word getAccessSequence(I procedure); + + Word getTerminatingSequence(I procedure); + + Pair, Set> scanPositiveCounterexample(Word counterexample); + + Set scanRefinedProcedures(Map>> procedures, + Map>> providers, + Collection> inputs); + +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/AlphabetMapper.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/AlphabetMapper.java new file mode 100644 index 0000000000..9ca4d379ef --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/AlphabetMapper.java @@ -0,0 +1,47 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import java.util.Arrays; +import java.util.Collection; + +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.words.SPAAlphabet; + +public class AlphabetMapper implements Mapping> { + + private final SPAAlphabet source; + private final SymbolWrapper[] target; + + @SuppressWarnings("unchecked") + public AlphabetMapper(SPAAlphabet source) { + this.source = source; + this.target = new SymbolWrapper[source.size()]; + } + + public void set(I symbol, SymbolWrapper representative) { + this.target[source.getSymbolIndex(symbol)] = representative; + } + + @Override + public SymbolWrapper get(I symbol) { + return this.target[source.getSymbolIndex(symbol)]; + } + + public Collection> values() { + return Arrays.asList(this.target); + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappedStackSBA.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappedStackSBA.java new file mode 100644 index 0000000000..ced4d3265e --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappedStackSBA.java @@ -0,0 +1,190 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; + +import com.google.common.collect.Maps; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.sba.SBA; +import net.automatalib.automata.spa.StackSPAState; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.SPAAlphabet; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A stack-based implementation for the (instrumented) semantics of a System of Procedural Automata. + * + * @param + * hypotheses state type + * @param + * input symbol type + * + * @author frohme + */ +public class MappedStackSBA + implements SBA, S>, I>, SimpleDTS, S>, I> { + + private final SPAAlphabet alphabet; + private final I initialCall; + private final Map>> procedures; + private final Mapping> mapping; + + // cast is fine, because we make sure to only query states belonging to the respective procedures + @SuppressWarnings("unchecked") + public MappedStackSBA(SPAAlphabet alphabet, + I initialCall, + Map>> procedures, + Mapping> mapping) { + this.alphabet = alphabet; + this.initialCall = initialCall; + this.procedures = (Map>>) procedures; + this.mapping = mapping; + } + + @Override + public StackSPAState, S> getTransition(StackSPAState, S> state, I i) { + if (state.isSink() || state.isTerm()) { + return StackSPAState.sink(); + } else if (alphabet.isInternalSymbol(i)) { + if (state.isInit()) { + return StackSPAState.sink(); + } + + final SymbolWrapper input = mapping.get(i); + final DFA> model = state.getProcedure(); + final S next = model.getTransition(state.getCurrentState(), input); + + // undefined internal transition + if (next == null || !model.isAccepting(next)) { + return StackSPAState.sink(); + } + + return state.updateState(next); + } else if (alphabet.isCallSymbol(i)) { + if (state.isInit() && !Objects.equals(this.initialCall, i)) { + return StackSPAState.sink(); + } + + final DFA> model = this.procedures.get(i); + + if (model == null) { + return StackSPAState.sink(); + } + + final S next = model.getInitialState(); + + if (next == null) { + return StackSPAState.sink(); + } + + // store the procedural successor in the stack so that we don't need to look it up on return symbols + final StackSPAState, S> returnState; + if (state.isInit()) { + returnState = StackSPAState.term(); + } else { + final SymbolWrapper input = mapping.get(i); + final DFA> p = state.getProcedure(); + final S succ = p.getSuccessor(state.getCurrentState(), input); + if (succ == null || !p.isAccepting(succ)) { + return StackSPAState.sink(); + } + returnState = state.updateState(succ); + } + + return returnState.push(model, next); + } else if (alphabet.isReturnSymbol(i)) { + if (state.isInit()) { + return StackSPAState.sink(); + } + + // if we returned the state before, we checked that a procedure is available + final DFA> model = state.getProcedure(); + final S succ = model.getSuccessor(state.getCurrentState(), mapping.get(i)); + + // cannot return, reject word + if (succ == null || !model.isAccepting(succ)) { + return StackSPAState.sink(); + } + + return state.pop(); + } else { + return StackSPAState.sink(); + } + } + + @Override + public boolean isAccepting(StackSPAState, S> state) { + return !state.isSink() && + (state.isInit() || state.isTerm() || state.getProcedure().isAccepting(state.getCurrentState())); + } + + @Override + public StackSPAState, S> getInitialState() { + return StackSPAState.init(); + } + + @Override + public I getInitialProcedure() { + return initialCall; + } + + @Override + public SPAAlphabet getInputAlphabet() { + return this.alphabet; + } + + @Override + public Map> getProcedures() { + return Maps.transformValues(this.procedures, DFAView::new); + } + + private class DFAView implements DFA { + + private final DFA> delegate; + + DFAView(DFA> delegate) { + this.delegate = delegate; + } + + @Override + public Collection getStates() { + return delegate.getStates(); + } + + @Override + public @Nullable S2 getTransition(S2 s, I i) { + final SymbolWrapper w = mapping.get(i); + if (w == null) { + return null; + } + return delegate.getTransition(s, w); + } + + @Override + public boolean isAccepting(S2 s) { + return delegate.isAccepting(s); + } + + @Override + public @Nullable S2 getInitialState() { + return delegate.getInitialState(); + } + } +} \ No newline at end of file diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ProceduralMembershipOracle.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ProceduralMembershipOracle.java new file mode 100644 index 0000000000..126637b421 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ProceduralMembershipOracle.java @@ -0,0 +1,124 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.Query; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; + +public class ProceduralMembershipOracle implements MembershipOracle, Boolean> { + + private final SPAAlphabet alphabet; + private final MembershipOracle delegate; + private final I procedure; + private final ATManager atManager; + + public ProceduralMembershipOracle(SPAAlphabet alphabet, + MembershipOracle delegate, + I procedure, + ATManager atManager) { + this.alphabet = alphabet; + this.delegate = delegate; + this.procedure = procedure; + this.atManager = atManager; + } + + @Override + public void processQueries(Collection, Boolean>> collection) { + final List> transformedQueries = new ArrayList<>(collection.size()); + + for (final Query, Boolean> q : collection) { + if (isWellDefined(q)) { + transformedQueries.add(new TransformedQuery(q)); + } else { + q.answer(false); + } + } + + this.delegate.processQueries(transformedQueries); + } + + private boolean isWellDefined(Query, Boolean> q) { + final Iterator> iter = q.getInput().iterator(); + + while (iter.hasNext()) { + final SymbolWrapper wrapper = iter.next(); + final I sym = wrapper.getDelegate(); + if (alphabet.isReturnSymbol(sym) || alphabet.isCallSymbol(sym) && !wrapper.isTerminating()) { + return !iter.hasNext(); + } + } + + return true; + } + + private Word transformLocalQuery(Word> query) { + final WordBuilder builder = new WordBuilder<>(); + builder.append(atManager.getAccessSequence(this.procedure)); + + final Iterator> iter = query.iterator(); + while (iter.hasNext()) { + final SymbolWrapper w = iter.next(); + final I i = w.getDelegate(); + builder.append(i); + if (alphabet.isCallSymbol(i) && iter.hasNext()) { + assert w.isTerminating(); + builder.append(atManager.getTerminatingSequence(i)); + builder.append(alphabet.getReturnSymbol()); + } + } + + return builder.toWord(); + } + + private class TransformedQuery extends Query { + + private final Query, Boolean> originalQuery; + private final Word transformedQuery; + + TransformedQuery(Query, Boolean> originalQuery) { + this.originalQuery = originalQuery; + this.transformedQuery = transformLocalQuery(originalQuery.getInput()); + } + + @Override + public void answer(Boolean output) { + originalQuery.answer(output); + } + + @Override + public Word getPrefix() { + return Word.epsilon(); + } + + @Override + public Word getSuffix() { + return this.transformedQuery; + } + + @Override + public Word getInput() { + return this.transformedQuery; + } + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java new file mode 100644 index 0000000000..9cf81f3c8a --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java @@ -0,0 +1,313 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Maps; +import de.learnlib.algorithms.sba.manager.OptimizingATManager; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.algorithm.LearnerConstructor; +import de.learnlib.api.algorithm.LearningAlgorithm; +import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.DefaultQuery; +import de.learnlib.util.MQUtil; +import net.automatalib.SupportsGrowingAlphabet; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.sba.EmptySBA; +import net.automatalib.automata.sba.SBA; +import net.automatalib.commons.util.Pair; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.util.automata.Automata; +import net.automatalib.util.automata.sba.SBAUtil; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.VPDAlphabet.SymbolType; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; +import net.automatalib.words.impl.GrowingMapAlphabet; + +public class SBALearner> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> + implements LearningAlgorithm, I, Boolean> { + + private final SPAAlphabet alphabet; + private final MembershipOracle oracle; + private final Mapping, Boolean>> learnerConstructors; + private final ATManager atManager; + + private final Map subLearners; + private I initialCallSymbol; + + private final AlphabetMapper mapper; + + public SBALearner(final SPAAlphabet alphabet, + final MembershipOracle oracle, + final LearnerConstructor, Boolean> learnerConstructor) { + this(alphabet, oracle, (i) -> learnerConstructor, new OptimizingATManager<>(alphabet)); + } + + public SBALearner(final SPAAlphabet alphabet, + final MembershipOracle oracle, + final Mapping, Boolean>> learnerConstructors, + final ATManager atManager) { + this.alphabet = alphabet; + this.oracle = oracle; + this.learnerConstructors = learnerConstructors; + this.atManager = atManager; + + this.subLearners = Maps.newHashMapWithExpectedSize(this.alphabet.getNumCalls()); + this.mapper = new AlphabetMapper<>(alphabet); + + for (I i : this.alphabet.getCallAlphabet()) { + final SymbolWrapper wrapper = new SymbolWrapper<>(i, false, SymbolType.CALL); + this.mapper.set(i, wrapper); + } + for (I i : this.alphabet.getInternalAlphabet()) { + final SymbolWrapper wrapper = new SymbolWrapper<>(i, false, SymbolType.INTERNAL); + this.mapper.set(i, wrapper); + } + + final SymbolWrapper wrapper = new SymbolWrapper<>(this.alphabet.getReturnSymbol(), false, SymbolType.RETURN); + this.mapper.set(this.alphabet.getReturnSymbol(), wrapper); + } + + @Override + public void startLearning() { + // do nothing, as we have to wait for evidence that the potential main procedure actually terminates + } + + @Override + public boolean refineHypothesis(DefaultQuery defaultQuery) { + + boolean changed = this.extractUsefulInformationFromCounterExample(defaultQuery); + + while (refineHypothesisInternal(defaultQuery)) { + changed = true; + } + + ensureCallAndReturnClosure(); + + assert SBAUtil.isValid(this.getHypothesisModel()); + + return changed; + } + + private boolean refineHypothesisInternal(DefaultQuery defaultQuery) { + + final SBA hypothesis = this.getHypothesisModel(); + + if (!MQUtil.isCounterexample(defaultQuery, hypothesis)) { + return false; + } + + final Word input = defaultQuery.getInput(); + final int mismatchIdx = detectMismatchingIdx(hypothesis, input, defaultQuery.getOutput()); + + // extract local ce + final int callIdx = this.alphabet.findCallIndex(input, mismatchIdx); + final I procedure = input.getSymbol(callIdx); + + final Word localTrace = this.alphabet.project(input.subWord(callIdx + 1, mismatchIdx), 0) + .append(input.getSymbol(mismatchIdx)); + final DefaultQuery, Boolean> localCE = constructLocalCE(localTrace, defaultQuery.getOutput()); + + boolean localRefinement = this.subLearners.get(procedure).refineHypothesis(localCE); + assert localRefinement; + + return true; + } + + @Override + public SBA getHypothesisModel() { + + if (this.subLearners.isEmpty()) { + return new EmptySBA<>(this.alphabet); + } + + return new MappedStackSBA<>(alphabet, initialCallSymbol, getSubModels(), mapper); + } + + private boolean extractUsefulInformationFromCounterExample(DefaultQuery defaultQuery) { + + if (!defaultQuery.getOutput()) { + return false; + } + + boolean update = false; + final Word input = defaultQuery.getInput(); + + // positive CEs should always be rooted at the main procedure + this.initialCallSymbol = input.firstSymbol(); + + final Pair, Set> newSeqs = atManager.scanPositiveCounterexample(input); + final Set newCalls = newSeqs.getFirst(); + final Set newTerms = newSeqs.getSecond(); + + for (I call : newTerms) { + final SymbolWrapper sym = new SymbolWrapper<>(call, true, SymbolType.CALL); + this.mapper.set(call, sym); + for (L learner : this.subLearners.values()) { + learner.addAlphabetSymbol(sym); + update = true; + } + } + + for (I sym : newCalls) { + update = true; + final L newLearner = learnerConstructors.get(sym) + .constructLearner(new GrowingMapAlphabet<>(this.mapper.values()), + new ProceduralMembershipOracle<>(alphabet, + oracle, + sym, + atManager)); + + newLearner.startLearning(); + + // add new learner here, so that we have an AccessSequenceTransformer available when scanning for shorter ts + this.subLearners.put(sym, newLearner); + + // try to find a shorter terminating sequence for 'sym' before procedure is added to other hypotheses + final Set newTS = + this.atManager.scanRefinedProcedures(Collections.singletonMap(sym, newLearner.getHypothesisModel()), + subLearners, + mapper.values()); + + for (I call : newTS) { + final SymbolWrapper wrapper = new SymbolWrapper<>(call, true, SymbolType.CALL); + this.mapper.set(call, wrapper); + for (L learner : this.subLearners.values()) { + learner.addAlphabetSymbol(wrapper); + } + } + } + + return update; + } + + private Map>> getSubModels() { + final Map>> subModels = Maps.newHashMapWithExpectedSize(this.subLearners.size()); + + for (final Map.Entry entry : this.subLearners.entrySet()) { + subModels.put(entry.getKey(), entry.getValue().getHypothesisModel()); + } + + return subModels; + } + + private int detectMismatchingIdx(SBA sba, Word input, boolean output) { + + if (output) { + S stateIter = sba.getInitialState(); + int idx = 0; + + for (I i : input) { + final S succ = sba.getSuccessor(stateIter, i); + + if (succ == null || !sba.isAccepting(succ)) { + return idx; + } + stateIter = succ; + idx++; + } + } else { + int lower = 0; + int upper = input.size() - 1; + int result = input.size(); + + while (upper - lower > -1) { + int mid = lower + (upper - lower) / 2; + boolean answer = this.oracle.answerQuery(input.prefix(mid)); + if (answer) { + lower = mid + 1; + } else { + result = mid; + upper = mid - 1; + } + } + + return result - 1; + } + + throw new IllegalStateException("Could not properly analyze CE"); + } + + private DefaultQuery, Boolean> constructLocalCE(Word input, boolean output) { + + final WordBuilder> wb = new WordBuilder<>(input.length()); + for (I i : input) { + wb.append(mapper.get(i)); + } + + return new DefaultQuery<>(wb.toWord(), output); + } + + private void ensureCallAndReturnClosure() { + + final Set> nonContinuableSymbols = new HashSet<>(); + nonContinuableSymbols.add(mapper.get(alphabet.getReturnSymbol())); + for (I i : alphabet.getCallAlphabet()) { + final SymbolWrapper mapped = mapper.get(i); + if (!mapped.isTerminating()) { + nonContinuableSymbols.add(mapped); + } + } + + for (L learner : this.subLearners.values()) { + boolean stable = false; + + while (!stable) { + stable = ensureCallAndReturnClosure(learner.getHypothesisModel(), nonContinuableSymbols, learner); + } + } + } + + private boolean ensureCallAndReturnClosure(DFA> hyp, + Collection> nonContinuableSymbols, + L learner) { + + final Set>> cover = new HashSet<>(); + for (Word> sc : Automata.stateCover(hyp, mapper.values())) { + cover.add(learner.transformAccessSequence(sc)); + } + + for (Word> cov : cover) { + final S state = hyp.getState(cov); + + for (SymbolWrapper i : nonContinuableSymbols) { + final S succ = hyp.getSuccessor(state, i); + + for (SymbolWrapper next : mapper.values()) { + + if (hyp.isAccepting(hyp.getSuccessor(succ, next))) { // closure is violated + + final DefaultQuery, Boolean> ce = + new DefaultQuery<>(cov.append(i).append(next), false); + final boolean refined = learner.refineHypothesis(ce); + + assert refined; + return false; + } + } + } + } + + return true; + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SymbolWrapper.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SymbolWrapper.java new file mode 100644 index 0000000000..2e62bfe668 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SymbolWrapper.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import java.util.Objects; + +import net.automatalib.words.VPDAlphabet.SymbolType; + +public class SymbolWrapper { + + private final I delegate; + private final boolean isTerminating; + private final SymbolType type; + + public SymbolWrapper(I delegate, boolean isTerminating, SymbolType type) { + this.delegate = delegate; + this.isTerminating = isTerminating; + this.type = type; + } + + public I getDelegate() { + return delegate; + } + + public boolean isTerminating() { + return isTerminating; + } + + public SymbolType getType() { + return type; + } + + @Override + public String toString() { + if (type == SymbolType.CALL) { + return String.valueOf(delegate) + '(' + isTerminating + ')'; + } + return Objects.toString(delegate); + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/DefaultATManager.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/DefaultATManager.java new file mode 100644 index 0000000000..55993e8e58 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/DefaultATManager.java @@ -0,0 +1,92 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba.manager; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import de.learnlib.algorithms.sba.ATManager; +import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.api.AccessSequenceTransformer; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.commons.util.Pair; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.Word; + +public class DefaultATManager implements ATManager { + + private final Map> accessSequences; + private final Map> terminatingSequences; + + private final SPAAlphabet alphabet; + + public DefaultATManager(final SPAAlphabet alphabet) { + this.alphabet = alphabet; + + this.accessSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); + this.terminatingSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); + } + + @Override + public Word getAccessSequence(I procedure) { + assert this.accessSequences.containsKey(procedure); + return this.accessSequences.get(procedure); + } + + @Override + public Word getTerminatingSequence(I procedure) { + assert this.terminatingSequences.containsKey(procedure); + return this.terminatingSequences.get(procedure); + } + + @Override + public Pair, Set> scanPositiveCounterexample(Word input) { + final Set newCalls = Sets.newHashSetWithExpectedSize(alphabet.getNumCalls() - accessSequences.size()); + final Set newTerms = Sets.newHashSetWithExpectedSize(alphabet.getNumCalls() - terminatingSequences.size()); + + for (int i = 0; i < input.size(); i++) { + final I sym = input.getSymbol(i); + + if (this.alphabet.isCallSymbol(sym)) { + + if (!this.accessSequences.containsKey(sym)) { + this.accessSequences.put(sym, input.prefix(i + 1)); + newCalls.add(sym); + } + + final int returnIdx = this.alphabet.findReturnIndex(input, i + 1); + + if (returnIdx > 0 && !this.terminatingSequences.containsKey(sym)) { + this.terminatingSequences.put(sym, input.subWord(i + 1, returnIdx)); + newTerms.add(sym); + } + } + } + + return Pair.of(newCalls, newTerms); + } + + @Override + public Set scanRefinedProcedures(Map>> procedures, + Map>> providers, + Collection> inputs) { + return Collections.emptySet(); + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/OptimizingATManager.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/OptimizingATManager.java new file mode 100644 index 0000000000..3a0c0c8b6c --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/OptimizingATManager.java @@ -0,0 +1,240 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba.manager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import de.learnlib.algorithms.sba.ATManager; +import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.api.AccessSequenceTransformer; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.commons.util.Pair; +import net.automatalib.util.automata.cover.Covers; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.VPDAlphabet.SymbolType; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; + +public class OptimizingATManager implements ATManager { + + private final Map> accessSequences; + private final Map> terminatingSequences; + + private final SPAAlphabet alphabet; + + public OptimizingATManager(final SPAAlphabet alphabet) { + this.alphabet = alphabet; + + this.accessSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); + this.terminatingSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); + } + + @Override + public Word getAccessSequence(I procedure) { + assert this.accessSequences.containsKey(procedure); + return this.accessSequences.get(procedure); + } + + @Override + public Word getTerminatingSequence(I procedure) { + assert this.terminatingSequences.containsKey(procedure); + return this.terminatingSequences.get(procedure); + } + + @Override + public Pair, Set> scanPositiveCounterexample(Word counterexample) { + final Set newCalls = + Sets.newHashSetWithExpectedSize(this.alphabet.getNumCalls() - this.accessSequences.size()); + final Set newTerms = + Sets.newHashSetWithExpectedSize(this.alphabet.getNumCalls() - this.terminatingSequences.size()); + + this.extractPotentialTerminatingSequences(counterexample, newTerms); + this.extractPotentialAccessSequences(counterexample, newCalls); + + return Pair.of(newCalls, newTerms); + } + + @Override + public Set scanRefinedProcedures(Map>> procedures, + Map>> providers, + Collection> inputs) { + + final Set newTS = new HashSet<>(); + if (!procedures.isEmpty()) { + + final SymbolWrapper returnSymbol = inputs.stream() + .filter(i -> i.getType() == SymbolType.RETURN) + .findAny() + .orElseThrow(IllegalArgumentException::new); + boolean foundImprovements = false; + boolean stable = false; + + while (!stable) { + stable = true; + for (Map.Entry>> entry : procedures.entrySet()) { + final I i = entry.getKey(); + final DFA> automaton = entry.getValue(); + final Word currentTS = terminatingSequences.get(i); + assert providers.containsKey(i); + final Word hypTS = getShortestHypothesisTS(automaton, providers.get(i), inputs, returnSymbol); + + if (hypTS != null && (currentTS == null || hypTS.size() < currentTS.size())) { + + if (currentTS == null) { + newTS.add(i); + } + + terminatingSequences.put(i, hypTS); + stable = false; + foundImprovements = true; + } + } + } + + if (foundImprovements) { + optimizeSequences(this.accessSequences); + optimizeSequences(this.terminatingSequences); + } + } + + return newTS; + } + + private Word getShortestHypothesisTS(DFA> hyp, + AccessSequenceTransformer> asTransformer, + Collection> inputs, + SymbolWrapper returnSymbol) { + final Iterator>> iter = Covers.stateCoverIterator(hyp, inputs); + Word result = null; + + while (iter.hasNext()) { + final Word> cover = iter.next(); + final Word> as = asTransformer.transformAccessSequence(cover); + if (hyp.accepts(as.append(returnSymbol))) { + final Word ts = + this.alphabet.expand(as.transform(SymbolWrapper::getDelegate), terminatingSequences::get); + if (result == null || result.size() > ts.size()) { + result = ts; + } + + } + } + + return result; + } + + private void optimizeSequences(final Map> sequences) { + for (final Map.Entry> entry : sequences.entrySet()) { + final Word currentSequence = entry.getValue(); + final Word minimized = minifyWellMatched(currentSequence); + + if (minimized.size() < currentSequence.size()) { + sequences.put(entry.getKey(), minimized); + } + } + } + + private void extractPotentialTerminatingSequences(Word input, Set newProcedures) { + for (int i = 0; i < input.size(); i++) { + final I sym = input.getSymbol(i); + + if (this.alphabet.isCallSymbol(sym)) { + + final int returnIdx = this.alphabet.findReturnIndex(input, i + 1); + + if (returnIdx > 0) { + final Word potentialTermSeq = input.subWord(i + 1, returnIdx); + final Word currentTermSeq = this.terminatingSequences.get(sym); + + if (currentTermSeq == null) { + newProcedures.add(sym); + this.terminatingSequences.put(sym, potentialTermSeq); + } else if (potentialTermSeq.size() < currentTermSeq.size()) { + this.terminatingSequences.put(sym, potentialTermSeq); + } + } + } + } + } + + private void extractPotentialAccessSequences(Word input, Set newCalls) { + + final List asBuilder = new ArrayList<>(input.size()); + + for (int i = 0; i < input.size(); i++) { + + final I sym = input.getSymbol(i); + + asBuilder.add(sym); + + if (this.alphabet.isCallSymbol(sym)) { + + final Word currentAccSeq = this.accessSequences.get(sym); + + if (currentAccSeq == null) { + newCalls.add(sym); + this.accessSequences.put(sym, Word.fromList(asBuilder)); + } else if (asBuilder.size() < currentAccSeq.size()) { + this.accessSequences.put(sym, Word.fromList(asBuilder)); + } + } else if (this.alphabet.isReturnSymbol(sym)) { + // update asBuilder + final int callIdx = alphabet.findCallIndex(asBuilder, asBuilder.size() - 1); + final I procedure = asBuilder.get(callIdx); + asBuilder.subList(callIdx + 1, asBuilder.size()).clear(); + asBuilder.addAll(terminatingSequences.get(procedure).asList()); + asBuilder.add(alphabet.getReturnSymbol()); + } + } + } + + @SuppressWarnings("PMD.AvoidReassigningLoopVariables") // we want to skip ahead here + private Word minifyWellMatched(Word input) { + + if (input.isEmpty()) { + return Word.epsilon(); + } + + final WordBuilder wb = new WordBuilder<>(input.size()); + + for (int i = 0; i < input.size(); i++) { + + final I sym = input.getSymbol(i); + + wb.append(sym); + + if (this.alphabet.isCallSymbol(sym)) { + final int returnIdx = this.alphabet.findReturnIndex(input, i + 1); + + if (returnIdx > -1) { + wb.append(terminatingSequences.get(sym)); + wb.append(alphabet.getReturnSymbol()); + i = returnIdx; // next loop iteration starts _after_ the return symbol + } + } + } + + return wb.toWord(); + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/SPALearner.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/SPALearner.java index 6f65b546e2..e5fa2f7e34 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/SPALearner.java +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/SPALearner.java @@ -136,7 +136,7 @@ private boolean refineHypothesisInternal(DefaultQuery defaultQuery) final int callIdx = this.alphabet.findCallIndex(input, returnIdx); final I procedure = input.getSymbol(callIdx); - final Word localTrace = this.alphabet.normalize(input.subWord(callIdx + 1, returnIdx), 0); + final Word localTrace = this.alphabet.project(input.subWord(callIdx + 1, returnIdx), 0); final DefaultQuery localCE = new DefaultQuery<>(localTrace, defaultQuery.getOutput()); localRefinement |= this.subLearners.get(procedure).refineHypothesis(localCE); @@ -283,7 +283,7 @@ private boolean acceptsDecomposition(Predicate> system, Word while (idx > 0) { final int callIdx = this.alphabet.findCallIndex(input, idx); final I callSymbol = input.getSymbol(callIdx); - final Word normalized = this.alphabet.normalize(input.subWord(callIdx + 1, idx), 0); + final Word normalized = this.alphabet.project(input.subWord(callIdx + 1, idx), 0); final Word expanded = this.alphabet.expand(normalized, this.atrManager::getTerminatingSequence); wordStack.push(expanded.prepend(callSymbol)); @@ -321,7 +321,7 @@ private boolean checkSingleTerminatingSequence(Word input, Map> if (this.alphabet.isCallSymbol(sym)) { final int returnIdx = this.alphabet.findReturnIndex(input, i + 1); - final Word projectedRun = this.alphabet.normalize(input.subWord(i + 1, returnIdx), 0); + final Word projectedRun = this.alphabet.project(input.subWord(i + 1, returnIdx), 0); // whenever we extract a terminating sequence, we can also instantiate a learner. // Therefore the existence of the hypothesis is guaranteed. @SuppressWarnings("assignment.type.incompatible") diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ATManager.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ATManager.java new file mode 100644 index 0000000000..1c77af1836 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ATManager.java @@ -0,0 +1,41 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.commons.util.Pair; +import net.automatalib.words.Word; + +public interface ATManager { + + Word getAccessSequence(I procedure); + + Word getTerminatingSequence(I procedure); + + Pair, Set> scanCounterexample(DefaultQuery> counterexample); + + Set scanRefinedProcedures(Map, ?, O>> procedures, + Map>> providers, + Collection> inputs); + +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappedStackSPMM.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappedStackSPMM.java new file mode 100644 index 0000000000..23539443f4 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappedStackSPMM.java @@ -0,0 +1,223 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; + +import com.google.common.collect.Maps; +import de.learnlib.algorithms.sba.SymbolWrapper; +import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.spmm.StackSPMMState; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.impl.MealyTransition; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A stack-based implementation for the (instrumented) semantics of a System of Procedural Automata. + * + * @param + * hypotheses state type + * @param + * input symbol type + * + * @author frohme + */ +public class MappedStackSPMM + implements SPMM, T, O>, I, MealyTransition, T, O>, O>, O> { + + private final SPAAlphabet inputAlphabet; + private final SPAOutputAlphabet outputAlphabet; + + private final I initialCall; + private final O initialOutput; + private final Map, T, O>> procedures; + private final Mapping> mapping; + + @SuppressWarnings("unchecked") + public MappedStackSPMM(SPAAlphabet inputAlphabet, + SPAOutputAlphabet outputAlphabet, + I initialCall, + O initialOutput, + Map, ? extends T, O>> procedures, + Mapping> mapping) { + this.inputAlphabet = inputAlphabet; + this.outputAlphabet = outputAlphabet; + this.initialCall = initialCall; + this.initialOutput = initialOutput; + this.procedures = (Map, T, O>>) procedures; + this.mapping = mapping; + } + + @Override + public MealyTransition, T, O>, O> getTransition(StackSPMMState, T, O> state, + I i) { + if (state.isSink() || state.isTerm()) { + return sink(); + } else if (inputAlphabet.isInternalSymbol(i)) { + if (state.isInit()) { + return sink(); + } + + final SymbolWrapper input = mapping.get(i); + final MealyMachine, T, O> model = state.getProcedure(); + final T t = model.getTransition(state.getCurrentState(), input); + + if (t == null || outputAlphabet.isErrorSymbol(model.getTransitionOutput(t))) { + return sink(); + } + + final S succ = model.getSuccessor(t); + final StackSPMMState, T, O> next = state.updateState(succ); + + return new MealyTransition<>(next, model.getTransitionOutput(t)); + } else if (inputAlphabet.isCallSymbol(i)) { + if (state.isInit() && !Objects.equals(this.initialCall, i)) { + return sink(); + } + + final MealyMachine, T, O> model = this.procedures.get(i); + + if (model == null) { + return sink(); + } + + final S next = model.getInitialState(); + + if (next == null) { + return sink(); + } + + // store the procedural successor in the stack so that we don't need to look it up on return symbols + final StackSPMMState, T, O> returnState; + final O output; + if (state.isInit()) { + returnState = StackSPMMState.term(); + output = initialOutput; + } else { + final SymbolWrapper input = mapping.get(i); + final MealyMachine, T, O> p = state.getProcedure(); + final T t = p.getTransition(state.getCurrentState(), input); + + if (t == null || outputAlphabet.isErrorSymbol(p.getTransitionOutput(t))) { + return sink(); + } + returnState = state.updateState(p.getSuccessor(t)); + output = p.getTransitionOutput(t); + } + + return new MealyTransition<>(returnState.push(model, next), output); + } else if (inputAlphabet.isReturnSymbol(i)) { + if (state.isInit()) { + return sink(); + } + + // if we returned the state before, we checked that a procedure is available + final MealyMachine, T, O> model = state.getProcedure(); + final T t = model.getTransition(state.getCurrentState(), mapping.get(i)); + + if (t == null || outputAlphabet.isErrorSymbol(model.getTransitionOutput(t))) { + return sink(); + } + + return new MealyTransition<>(state.pop(), model.getTransitionOutput(t)); + } else { + return sink(); + } + } + + @Override + public StackSPMMState, T, O> getInitialState() { + return StackSPMMState.init(); + } + + @Override + public I getInitialProcedure() { + return initialCall; + } + + @Override + public SPAAlphabet getInputAlphabet() { + return this.inputAlphabet; + } + + @Override + public SPAOutputAlphabet getOutputAlphabet() { + return this.outputAlphabet; + } + + @Override + public O getTransitionOutput(MealyTransition, T, O>, O> transition) { + return transition.getOutput(); + } + + @Override + public StackSPMMState, T, O> getSuccessor(MealyTransition, T, O>, O> transition) { + return transition.getSuccessor(); + } + + private MealyTransition, T, O>, O> sink() { + return new MealyTransition<>(StackSPMMState.sink(), outputAlphabet.getErrorSymbol()); + } + + @Override + public Map> getProcedures() { + return Maps.transformValues(this.procedures, MealyView::new); + } + + private class MealyView implements MealyMachine { + + private final MealyMachine, T2, O> delegate; + + MealyView(MealyMachine, T2, O> delegate) { + this.delegate = delegate; + } + + @Override + public Collection getStates() { + return this.delegate.getStates(); + } + + @Override + public O getTransitionOutput(T2 t2) { + return this.delegate.getTransitionOutput(t2); + } + + @Override + public @Nullable T2 getTransition(S2 s2, I i) { + final SymbolWrapper w = mapping.get(i); + if (w == null) { + return null; + } + return delegate.getTransition(s2, w); + } + + @Override + public S2 getSuccessor(T2 t2) { + return this.delegate.getSuccessor(t2); + } + + @Override + public @Nullable S2 getInitialState() { + return this.delegate.getInitialState(); + } + } + +} \ No newline at end of file diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ProceduralMembershipOracle.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ProceduralMembershipOracle.java new file mode 100644 index 0000000000..e50e93000a --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ProceduralMembershipOracle.java @@ -0,0 +1,161 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.api.query.Query; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; + +public class ProceduralMembershipOracle implements MembershipOracle, Word> { + + private final SPAAlphabet alphabet; + private final MembershipOracle> delegate; + private final I procedure; + private final O errorSymbol; + private final ATManager atManager; + + public ProceduralMembershipOracle(SPAAlphabet alphabet, + MembershipOracle> delegate, + I procedure, + O errorSymbol, + ATManager atManager) { + this.alphabet = alphabet; + this.delegate = delegate; + this.procedure = procedure; + this.errorSymbol = errorSymbol; + this.atManager = atManager; + } + + @Override + public void processQueries(Collection, Word>> collection) { + final List>> transformedQueries = new ArrayList<>(collection.size()); + + for (final Query, Word> q : collection) { + if (hasErrorInPrefix(q.getPrefix())) { + q.answer(Word.fromList(Collections.nCopies(q.getSuffix().length(), errorSymbol))); + } else { + transformedQueries.add(new TransformedQuery(q)); + } + } + + this.delegate.processQueries(transformedQueries); + } + + private Word transformPrefix(Word> query) { + final WordBuilder builder = new WordBuilder<>(); + builder.append(atManager.getAccessSequence(this.procedure)); + + for (final SymbolWrapper wrapper : query) { + final I i = wrapper.getDelegate(); + if (alphabet.isInternalSymbol(i)) { + builder.append(i); + } else if (alphabet.isCallSymbol(i)) { + builder.append(i); + builder.append(atManager.getTerminatingSequence(i)); + builder.append(alphabet.getReturnSymbol()); + } else { // return symbol + throw new IllegalStateException("Prefixes should not contain return symbol"); + } + } + + return builder.toWord(); + } + + private Word transformSuffix(Word> query, BitSet indices) { + final WordBuilder builder = new WordBuilder<>(); + + for (final SymbolWrapper wrapper : query) { + final I i = wrapper.getDelegate(); + indices.set(builder.size()); + if (alphabet.isInternalSymbol(i)) { + builder.append(i); + } else if (alphabet.isCallSymbol(i)) { + builder.append(i); + if (wrapper.isTerminating()) { + builder.append(atManager.getTerminatingSequence(i)); + builder.append(alphabet.getReturnSymbol()); + } else { + return builder.toWord(); + } + } else { // return symbol + builder.append(i); + return builder.toWord(); + } + } + + return builder.toWord(); + } + + private boolean hasErrorInPrefix(Word> prefix) { + + for (SymbolWrapper wrapper : prefix) { + final I i = wrapper.getDelegate(); + if (alphabet.isReturnSymbol(i) || alphabet.isCallSymbol(i) && !wrapper.isTerminating()) { + return true; + } + } + + return false; + } + + private class TransformedQuery extends Query> { + + private final Query, Word> originalQuery; + private final Word transformedPrefix; + private final Word transformedSuffix; + private final BitSet outputIndices; + + TransformedQuery(Query, Word> originalQuery) { + this.originalQuery = originalQuery; + this.outputIndices = new BitSet(); + + this.transformedPrefix = transformPrefix(originalQuery.getPrefix()); + this.transformedSuffix = transformSuffix(originalQuery.getSuffix(), outputIndices); + } + + @Override + public void answer(Word output) { + final List out = outputIndices.stream().mapToObj(output::getSymbol).collect(Collectors.toList()); + + // fill up with skipped symbols + for (int i = out.size(); i < originalQuery.getSuffix().size(); i++) { + out.add(errorSymbol); + } + + this.originalQuery.answer(Word.fromList(out)); + } + + @Override + public Word getPrefix() { + return this.transformedPrefix; + } + + @Override + public Word getSuffix() { + return this.transformedSuffix; + } + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java new file mode 100644 index 0000000000..08bfb9ccac --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java @@ -0,0 +1,323 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import com.google.common.collect.Maps; +import de.learnlib.algorithms.sba.AlphabetMapper; +import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.spmm.manager.OptimizingATManager; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.algorithm.LearnerConstructor; +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 de.learnlib.util.MQUtil; +import net.automatalib.SupportsGrowingAlphabet; +import net.automatalib.automata.spmm.EmptySPMM; +import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.commons.util.Pair; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.util.automata.Automata; +import net.automatalib.util.automata.spmm.SPMMUtil; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.VPDAlphabet.SymbolType; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; +import net.automatalib.words.impl.GrowingMapAlphabet; + +public class SPMMLearner, O> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> + implements LearningAlgorithm, I, Word> { + + private final SPAAlphabet inputAlphabet; + private final SPAOutputAlphabet outputAlphabet; + private final MembershipOracle> oracle; + private final Mapping, Word>> learnerConstructors; + private final ATManager atManager; + + private final Map learners; + private I initialCallSymbol; + private O initialOutputSymbol; + + private final AlphabetMapper mapper; + + public SPMMLearner(SPAAlphabet inputAlphabet, + SPAOutputAlphabet outputAlphabet, + MembershipOracle> oracle, + LearnerConstructor, Word> learnerConstructor) { + this(inputAlphabet, + outputAlphabet, + oracle, + (i) -> learnerConstructor, + new OptimizingATManager<>(inputAlphabet, outputAlphabet)); + } + + public SPMMLearner(SPAAlphabet inputAlphabet, + SPAOutputAlphabet outputAlphabet, + MembershipOracle> oracle, + Mapping, Word>> learnerConstructors, + ATManager atManager) { + this.inputAlphabet = inputAlphabet; + this.outputAlphabet = outputAlphabet; + this.oracle = oracle; + this.learnerConstructors = learnerConstructors; + this.atManager = atManager; + + this.learners = Maps.newHashMapWithExpectedSize(this.inputAlphabet.getNumCalls()); + this.mapper = new AlphabetMapper<>(inputAlphabet); + + for (I i : this.inputAlphabet.getCallAlphabet()) { + final SymbolWrapper wrapper = new SymbolWrapper<>(i, false, SymbolType.CALL); + this.mapper.set(i, wrapper); + } + for (I i : this.inputAlphabet.getInternalAlphabet()) { + final SymbolWrapper wrapper = new SymbolWrapper<>(i, false, SymbolType.INTERNAL); + this.mapper.set(i, wrapper); + } + + final SymbolWrapper wrapper = + new SymbolWrapper<>(this.inputAlphabet.getReturnSymbol(), false, SymbolType.RETURN); + this.mapper.set(this.inputAlphabet.getReturnSymbol(), wrapper); + } + + @Override + public void startLearning() { + // do nothing, as we have to wait for evidence that the potential main procedure actually terminates + } + + @Override + public boolean refineHypothesis(DefaultQuery> defaultQuery) { + + boolean changed = this.extractUsefulInformationFromCounterExample(defaultQuery); + + while (refineHypothesisInternal(defaultQuery)) { + changed = true; + } + + ensureReturnClosure(); + + assert SPMMUtil.isValid(getHypothesisModel()); + + return changed; + } + + private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) { + + final SPMM hypothesis = this.getHypothesisModel(); + + if (!MQUtil.isCounterexample(defaultQuery, hypothesis)) { + return false; + } + + final Word input = defaultQuery.getInput(); + final Word output = defaultQuery.getOutput(); + + final int mismatchIdx = detectMismatchingIdx(hypothesis, input, output); + + // extract local ce + final int callIdx = inputAlphabet.findCallIndex(input, mismatchIdx); + final I procedure = input.getSymbol(callIdx); + + final Pair, Word> localTraces = inputAlphabet.project(input.subWord(callIdx + 1, mismatchIdx + 1), + output.subWord(callIdx + 1, mismatchIdx + 1), + 0); + final DefaultQuery, Word> localCE = + constructLocalCE(localTraces.getFirst(), localTraces.getSecond()); + final boolean localRefinement = this.learners.get(procedure).refineHypothesis(localCE); + + if (!localRefinement) { + throw new AssertionError(); + } + + return true; + } + + @Override + public SPMM getHypothesisModel() { + + if (this.learners.isEmpty()) { + return new EmptySPMM<>(this.inputAlphabet, outputAlphabet); + } + + return new MappedStackSPMM<>(inputAlphabet, + outputAlphabet, + initialCallSymbol, + initialOutputSymbol, + getSubModels(), + mapper); + } + + private boolean extractUsefulInformationFromCounterExample(DefaultQuery> defaultQuery) { + + final Word input = defaultQuery.getInput(); + final Word output = defaultQuery.getOutput(); + + // CEs should always be rooted at the main procedure + this.initialCallSymbol = input.firstSymbol(); + this.initialOutputSymbol = output.firstSymbol(); + + final Pair, Set> newSeqs = atManager.scanCounterexample(defaultQuery); + final Set newCalls = newSeqs.getFirst(); + final Set newTerms = newSeqs.getSecond(); + + boolean update = false; + + for (I call : newTerms) { + final SymbolWrapper sym = new SymbolWrapper<>(call, true, SymbolType.CALL); + this.mapper.set(call, sym); + for (L learner : this.learners.values()) { + learner.addAlphabetSymbol(sym); + update = true; + } + } + + for (I sym : newCalls) { + update = true; + final L newLearner = learnerConstructors.get(sym) + .constructLearner(new GrowingMapAlphabet<>(this.mapper.values()), + new ProceduralMembershipOracle<>(inputAlphabet, + oracle, + sym, + outputAlphabet.getErrorSymbol(), + atManager)); + + newLearner.startLearning(); + + // add new learner here, so that we have an AccessSequenceTransformer available when scanning for shorter ts + this.learners.put(sym, newLearner); + + // try to find a shorter terminating sequence for 'sym' before procedure is added to other hypotheses + final Set newTS = + this.atManager.scanRefinedProcedures(Collections.singletonMap(sym, newLearner.getHypothesisModel()), + learners, + mapper.values()); + + for (I call : newTS) { + final SymbolWrapper wrapper = new SymbolWrapper<>(call, true, SymbolType.CALL); + this.mapper.set(call, wrapper); + for (L learner : this.learners.values()) { + learner.addAlphabetSymbol(wrapper); + } + } + } + + return update; + } + + private Map, ?, O>> getSubModels() { + final Map, ?, O>> subModels = + Maps.newHashMapWithExpectedSize(this.learners.size()); + + for (final Map.Entry entry : this.learners.entrySet()) { + subModels.put(entry.getKey(), entry.getValue().getHypothesisModel()); + } + + return subModels; + } + + private DefaultQuery, Word> constructLocalCE(Word input, Word output) { + + final WordBuilder> wb = new WordBuilder<>(input.length()); + for (I i : input) { + wb.append(mapper.get(i)); + } + + return new DefaultQuery<>(wb.toWord(), output); + } + + private void ensureReturnClosure() { + for (L learner : this.learners.values()) { + boolean stable = false; + + while (!stable) { + stable = ensureReturnClosure(learner.getHypothesisModel(), mapper.values(), learner); + } + } + } + + private boolean ensureReturnClosure(MealyMachine, T, O> hyp, + Collection> inputs, + L learner) { + + final Set>> cover = new HashSet<>(); + for (Word> sc : Automata.stateCover(hyp, inputs)) { + cover.add(learner.transformAccessSequence(sc)); + } + + for (Word> cov : cover) { + final S state = hyp.getState(cov); + + for (SymbolWrapper i : inputs) { + if (i.getType() == SymbolType.RETURN) { + + final S succ = hyp.getSuccessor(state, i); + + for (SymbolWrapper next : inputs) { + final O succOut = hyp.getOutput(succ, next); + + if (!outputAlphabet.isErrorSymbol(succOut)) { // error closure is violated + // TODO split prefix/suffix? Issue with learners? + final Word> lp = cov.append(i); + final DefaultQuery, Word> ce = new DefaultQuery<>(Word.epsilon(), + lp.append(next), + hyp.computeOutput(lp) + .append(outputAlphabet.getErrorSymbol())); + final boolean refined = learner.refineHypothesis(ce); + assert refined; + return false; + } + } + } + } + } + + return true; + } + + private int detectMismatchingIdx(SPMM spmm, Word input, Word output) { + + final Iterator inIter = input.iterator(); + final Iterator outIter = output.iterator(); + + S stateIter = spmm.getInitialState(); + int idx = 0; + + while (inIter.hasNext() && outIter.hasNext()) { + final I i = inIter.next(); + final O o = outIter.next(); + + T t = spmm.getTransition(stateIter, i); + + if (t == null || !Objects.equals(o, spmm.getTransitionOutput(t))) { + return idx; + } + stateIter = spmm.getSuccessor(t); + idx++; + } + + return -1; + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/DiscriminationTreeMealyAdapter.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/DiscriminationTreeMealyAdapter.java new file mode 100644 index 0000000000..3ecc07aa80 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/DiscriminationTreeMealyAdapter.java @@ -0,0 +1,45 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm.adapter; + +import de.learnlib.algorithms.discriminationtree.mealy.DTLearnerMealy; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.counterexamples.LocalSuffixFinders; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * Adapter for using {@link DTLearnerMealy} as a sub-procedural learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +public class DiscriminationTreeMealyAdapter extends DTLearnerMealy implements AccessSequenceTransformer { + + public DiscriminationTreeMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + super(alphabet, oracle, LocalSuffixFinders.RIVEST_SCHAPIRE, true); + } + + @Override + public Word transformAccessSequence(Word word) { + return super.getHypothesisDS().transformAccessSequence(word); + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/KearnsVaziraniMealyAdapter.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/KearnsVaziraniMealyAdapter.java new file mode 100644 index 0000000000..d96d7cc8e7 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/KearnsVaziraniMealyAdapter.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm.adapter; + +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.algorithms.kv.mealy.KearnsVaziraniMealy; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * Adapter for using {@link KearnsVaziraniMealy} as a sub-procedural learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +public class KearnsVaziraniMealyAdapter extends KearnsVaziraniMealy + implements AccessSequenceTransformer { + + public KearnsVaziraniMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + super(alphabet, oracle, false, AcexAnalyzers.LINEAR_FWD); + } + + @Override + public Word transformAccessSequence(Word word) { + final int reachedState = getStateId(super.getHypothesisModel(), word); + return super.stateInfos.get(reachedState).accessSequence; + } + + private int getStateId(MealyMachine mealyMachine, Word word) { + final S s = mealyMachine.getState(word); + return mealyMachine.stateIDs().getStateId(s); + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/LStarBaseMealyAdapter.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/LStarBaseMealyAdapter.java new file mode 100644 index 0000000000..1146dfec57 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/LStarBaseMealyAdapter.java @@ -0,0 +1,69 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm.adapter; + +import java.util.Collections; +import java.util.Objects; + +import de.learnlib.algorithms.lstar.ce.ObservationTableCEXHandlers; +import de.learnlib.algorithms.lstar.closing.ClosingStrategies; +import de.learnlib.algorithms.lstar.mealy.ExtensibleLStarMealy; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.datastructure.observationtable.ObservationTable; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * Adapter for using {@link ExtensibleLStarMealy} as a sub-procedural learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +public class LStarBaseMealyAdapter extends ExtensibleLStarMealy implements AccessSequenceTransformer { + + public LStarBaseMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + super(alphabet, + oracle, + Collections.singletonList(Word.epsilon()), + ObservationTableCEXHandlers.CLASSIC_LSTAR, + ClosingStrategies.CLOSE_FIRST); + } + + @Override + public Word transformAccessSequence(Word word) { + final MealyMachine hypothesis = super.getHypothesisModel(); + final ObservationTable> observationTable = super.getObservationTable(); + + final Object reachedState = hypothesis.getState(word); + + for (final Word shortPrefix : observationTable.getShortPrefixes()) { + final Object reachedSPState = hypothesis.getState(shortPrefix); + + if (Objects.equals(reachedState, reachedSPState)) { + return shortPrefix; + } + } + + throw new IllegalStateException("This should not have happened"); + } + +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/RivestSchapireMealyAdapter.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/RivestSchapireMealyAdapter.java new file mode 100644 index 0000000000..23758cb418 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/RivestSchapireMealyAdapter.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm.adapter; + +import java.util.Objects; + +import de.learnlib.algorithms.rivestschapire.RivestSchapireMealy; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.datastructure.observationtable.ObservationTable; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +public class RivestSchapireMealyAdapter extends RivestSchapireMealy + implements AccessSequenceTransformer { + + public RivestSchapireMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + super(alphabet, oracle); + } + + @Override + public Word transformAccessSequence(Word word) { + final MealyMachine hypothesis = super.getHypothesisModel(); + final ObservationTable> observationTable = super.getObservationTable(); + + final Object reachedState = hypothesis.getState(word); + + for (final Word shortPrefix : observationTable.getShortPrefixes()) { + final Object reachedSPState = hypothesis.getState(shortPrefix); + + if (Objects.equals(reachedState, reachedSPState)) { + return shortPrefix; + } + } + + throw new IllegalStateException("This should not have happened"); + } + +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/TTTMealyAdapter.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/TTTMealyAdapter.java new file mode 100644 index 0000000000..16081d1ce9 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/TTTMealyAdapter.java @@ -0,0 +1,50 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm.adapter; + +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.algorithms.ttt.base.TTTState; +import de.learnlib.algorithms.ttt.mealy.TTTLearnerMealy; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * Adapter for using {@link TTTLearnerMealy} as a sub-procedural learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +public class TTTMealyAdapter extends TTTLearnerMealy implements AccessSequenceTransformer { + + public TTTMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + super(alphabet, oracle, AcexAnalyzers.BINARY_SEARCH_BWD); + } + + @Override + public Word transformAccessSequence(Word word) { + final TTTState> s = super.getHypothesisDS().getState(word); + // we should only query defined paths + assert s != null; + return s.getAccessSequence(); + } + +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/DefaultATManager.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/DefaultATManager.java new file mode 100644 index 0000000000..a53fcc030c --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/DefaultATManager.java @@ -0,0 +1,99 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm.manager; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.spmm.ATManager; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.commons.util.Pair; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.Word; + +public class DefaultATManager implements ATManager { + + private final Map> accessSequences; + private final Map> terminatingSequences; + + private final SPAAlphabet inputAlphabet; + private final SPAOutputAlphabet outputAlphabet; + + public DefaultATManager(final SPAAlphabet inputAlphabet, final SPAOutputAlphabet outputAlphabet) { + this.inputAlphabet = inputAlphabet; + this.outputAlphabet = outputAlphabet; + + this.accessSequences = Maps.newHashMapWithExpectedSize(inputAlphabet.getNumCalls()); + this.terminatingSequences = Maps.newHashMapWithExpectedSize(inputAlphabet.getNumCalls()); + } + + @Override + public Word getAccessSequence(I procedure) { + return this.accessSequences.get(procedure); + } + + @Override + public Word getTerminatingSequence(I procedure) { + return this.terminatingSequences.get(procedure); + } + + @Override + public Pair, Set> scanCounterexample(DefaultQuery> counterexample) { + final Set newCalls = Sets.newHashSetWithExpectedSize(inputAlphabet.getNumCalls() - accessSequences.size()); + final Set newTerms = + Sets.newHashSetWithExpectedSize(inputAlphabet.getNumCalls() - terminatingSequences.size()); + + final Word input = counterexample.getInput(); + final Word output = counterexample.getOutput(); + + for (int i = 0; i < input.size(); i++) { + final I sym = input.getSymbol(i); + + if (this.inputAlphabet.isCallSymbol(sym)) { + + if (!this.accessSequences.containsKey(sym)) { + this.accessSequences.put(sym, input.prefix(i + 1)); + newCalls.add(sym); + } + + final int returnIdx = inputAlphabet.findReturnIndex(input, i + 1); + + if (returnIdx > 0 && !this.terminatingSequences.containsKey(sym) && + !this.outputAlphabet.isErrorSymbol(output.getSymbol(returnIdx))) { + this.terminatingSequences.put(sym, input.subWord(i + 1, returnIdx)); + newTerms.add(sym); + } + } + } + + return Pair.of(newCalls, newTerms); + } + + @Override + public Set scanRefinedProcedures(Map, ?, O>> procedures, + Map>> providers, + Collection> inputs) { + return Collections.emptySet(); + } +} diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/OptimizingATManager.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/OptimizingATManager.java new file mode 100644 index 0000000000..d56ef98ed7 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/OptimizingATManager.java @@ -0,0 +1,256 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm.manager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.spmm.ATManager; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.commons.util.Pair; +import net.automatalib.util.automata.cover.Covers; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.VPDAlphabet.SymbolType; +import net.automatalib.words.Word; +import net.automatalib.words.WordBuilder; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class OptimizingATManager implements ATManager { + + private final Map> accessSequences; + private final Map> terminatingSequences; + + private final SPAAlphabet inputAlphabet; + private final SPAOutputAlphabet outputAlphabet; + + public OptimizingATManager(final SPAAlphabet inputAlphabet, SPAOutputAlphabet outputAlphabet) { + this.inputAlphabet = inputAlphabet; + this.outputAlphabet = outputAlphabet; + + this.accessSequences = Maps.newHashMapWithExpectedSize(inputAlphabet.getNumCalls()); + this.terminatingSequences = Maps.newHashMapWithExpectedSize(inputAlphabet.getNumCalls()); + } + + @Override + public Word getAccessSequence(I procedure) { + return this.accessSequences.get(procedure); + } + + @Override + public Word getTerminatingSequence(I procedure) { + return this.terminatingSequences.get(procedure); + } + + @Override + public Pair, Set> scanCounterexample(DefaultQuery> counterexample) { + final Set newCalls = + Sets.newHashSetWithExpectedSize(this.inputAlphabet.getNumCalls() - this.accessSequences.size()); + final Set newTerms = + Sets.newHashSetWithExpectedSize(this.inputAlphabet.getNumCalls() - this.terminatingSequences.size()); + + this.extractPotentialTerminatingSequences(counterexample, newTerms); + this.extractPotentialAccessSequences(counterexample, newCalls); + + return Pair.of(newCalls, newTerms); + } + + @Override + public Set scanRefinedProcedures(Map, ?, O>> procedures, + Map>> providers, + Collection> inputs) { + final Set newTS = new HashSet<>(); + if (!procedures.isEmpty()) { + + final SymbolWrapper returnSymbol = inputs.stream() + .filter(i -> i.getType() == SymbolType.RETURN) + .findAny() + .orElseThrow(IllegalArgumentException::new); + boolean foundImprovements = false; + boolean stable = false; + + while (!stable) { + stable = true; + for (Entry, ?, O>> entry : procedures.entrySet()) { + final I i = entry.getKey(); + final MealyMachine, ?, O> automaton = entry.getValue(); + final Word currentTS = terminatingSequences.get(i); + assert providers.containsKey(i); + final Word hypTS = getShortestHypothesisTS(automaton, providers.get(i), inputs, returnSymbol); + + if (hypTS != null && (currentTS == null || hypTS.size() < currentTS.size())) { + + if (currentTS == null) { + newTS.add(i); + } + + terminatingSequences.put(i, hypTS); + stable = false; + foundImprovements = true; + } + } + } + + if (foundImprovements) { + optimizeSequences(this.accessSequences); + optimizeSequences(this.terminatingSequences); + } + } + + return newTS; + } + + private @Nullable Word getShortestHypothesisTS(MealyMachine, ?, O> hyp, + AccessSequenceTransformer> asTransformer, + Collection> inputs, + SymbolWrapper returnSymbol) { + final Iterator>> iter = Covers.stateCoverIterator(hyp, inputs); + Word result = null; + + while (iter.hasNext()) { + final Word> cover = iter.next(); + final Word> as = asTransformer.transformAccessSequence(cover); + final Word> asReturn = as.append(returnSymbol); + + if (!this.outputAlphabet.isErrorSymbol(hyp.computeOutput(asReturn).lastSymbol())) { + final Word ts = + this.inputAlphabet.expand(as.transform(SymbolWrapper::getDelegate), terminatingSequences::get); + if (result == null || result.size() > ts.size()) { + result = ts; + } + } + } + + return result; + } + + private void optimizeSequences(final Map> sequences) { + for (final Entry> entry : sequences.entrySet()) { + final Word currentSequence = entry.getValue(); + final Word minimized = minifyWellMatched(currentSequence); + + if (minimized.size() < currentSequence.size()) { + sequences.put(entry.getKey(), minimized); + } + } + } + + private void extractPotentialTerminatingSequences(final DefaultQuery> counterexample, + final Set newProcedures) { + + final Word input = counterexample.getInput(); + final Word output = counterexample.getOutput(); + + for (int i = 0; i < input.size(); i++) { + final I sym = input.getSymbol(i); + + if (this.inputAlphabet.isCallSymbol(sym)) { + + final int returnIdx = inputAlphabet.findReturnIndex(input, i + 1); + + if (returnIdx > 0 && !this.outputAlphabet.isErrorSymbol(output.getSymbol(returnIdx))) { + final Word potentialTermSeq = input.subWord(i + 1, returnIdx); + final Word currentTermSeq = this.terminatingSequences.get(sym); + + if (currentTermSeq == null) { + newProcedures.add(sym); + this.terminatingSequences.put(sym, potentialTermSeq); + } else if (potentialTermSeq.size() < currentTermSeq.size()) { + this.terminatingSequences.put(sym, potentialTermSeq); + } + } + } + } + } + + private void extractPotentialAccessSequences(final DefaultQuery> counterexample, final Set newCalls) { + + final Word input = counterexample.getInput(); + final Word output = counterexample.getOutput(); + final List asBuilder = new ArrayList<>(input.size()); + + for (int i = 0; i < input.size(); i++) { + + final I sym = input.getSymbol(i); + + asBuilder.add(sym); + + if (this.inputAlphabet.isCallSymbol(sym)) { + + if (this.outputAlphabet.isErrorSymbol(output.getSymbol(i))) { + return; + } + + final Word currentAccSeq = this.accessSequences.get(sym); + + if (currentAccSeq == null) { + newCalls.add(sym); + this.accessSequences.put(sym, Word.fromList(asBuilder)); + } else if (asBuilder.size() < currentAccSeq.size()) { + this.accessSequences.put(sym, Word.fromList(asBuilder)); + } + } else if (this.inputAlphabet.isReturnSymbol(sym)) { + // update asBuilder + final int callIdx = inputAlphabet.findCallIndex(asBuilder, asBuilder.size() - 1); + final I procedure = asBuilder.get(callIdx); + asBuilder.subList(callIdx + 1, asBuilder.size()).clear(); + asBuilder.addAll(terminatingSequences.get(procedure).asList()); + asBuilder.add(inputAlphabet.getReturnSymbol()); + } + } + } + + @SuppressWarnings("PMD.AvoidReassigningLoopVariables") // we want to skip ahead here + private Word minifyWellMatched(Word input) { + + if (input.isEmpty()) { + return Word.epsilon(); + } + + final WordBuilder wb = new WordBuilder<>(input.size()); + + for (int i = 0; i < input.size(); i++) { + + final I sym = input.getSymbol(i); + + wb.append(sym); + + if (this.inputAlphabet.isCallSymbol(sym)) { + final int returnIdx = inputAlphabet.findReturnIndex(input, i + 1); + + if (returnIdx > -1) { + wb.append(terminatingSequences.get(sym)); + wb.append(inputAlphabet.getReturnSymbol()); + i = returnIdx; // next loop iteration starts _after_ the return symbol + } + } + } + + return wb.toWord(); + } + +} diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/ATManagerTest.java b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/ATManagerTest.java new file mode 100644 index 0000000000..3f151fbc88 --- /dev/null +++ b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/ATManagerTest.java @@ -0,0 +1,62 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import de.learnlib.algorithms.sba.manager.DefaultATManager; +import de.learnlib.algorithms.sba.manager.OptimizingATManager; +import net.automatalib.words.Alphabet; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.DefaultSPAAlphabet; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class ATManagerTest { + + private static final SPAAlphabet ALPHABET; + + static { + final Alphabet callAlphabet = Alphabets.characters('A', 'C'); + final Alphabet internalAlphabet = Alphabets.characters('a', 'b'); + final char returnSymbol = 'R'; + + ALPHABET = new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); + } + + @DataProvider + public static Object[] atManager() { + return new Object[] {new DefaultATManager<>(ALPHABET), new OptimizingATManager<>(ALPHABET)}; + } + + @Test(dataProvider = "atManager") + public void testScanning(ATManager manager) { + + final Word word = Word.fromCharSequence("ABaRCbRR"); + + manager.scanPositiveCounterexample(word); + + Assert.assertEquals(manager.getAccessSequence('A'), Word.fromCharSequence("A")); + Assert.assertEquals(manager.getAccessSequence('B'), Word.fromCharSequence("AB")); + Assert.assertEquals(manager.getAccessSequence('C'), Word.fromCharSequence("ABaRC")); + + Assert.assertEquals(manager.getTerminatingSequence('A'), Word.fromCharSequence("BaRCbR")); + Assert.assertEquals(manager.getTerminatingSequence('B'), Word.fromCharSequence("a")); + Assert.assertEquals(manager.getTerminatingSequence('C'), Word.fromCharSequence("b")); + } + +} diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/SBAIT.java b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/SBAIT.java new file mode 100644 index 0000000000..673f879e71 --- /dev/null +++ b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/SBAIT.java @@ -0,0 +1,80 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import de.learnlib.algorithms.sba.manager.DefaultATManager; +import de.learnlib.algorithms.sba.manager.OptimizingATManager; +import de.learnlib.algorithms.spa.adapter.DiscriminationTreeAdapter; +import de.learnlib.algorithms.spa.adapter.KearnsVaziraniAdapter; +import de.learnlib.algorithms.spa.adapter.LStarBaseAdapter; +import de.learnlib.algorithms.spa.adapter.RivestSchapireAdapter; +import de.learnlib.algorithms.spa.adapter.TTTAdapter; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.algorithm.LearnerConstructor; +import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.it.learner.AbstractSBALearnerIT; +import de.learnlib.testsupport.it.learner.LearnerVariantList.SBALearnerVariantList; +import net.automatalib.SupportsGrowingAlphabet; +import net.automatalib.words.SPAAlphabet; + +public class SBAIT extends AbstractSBALearnerIT { + + @Override + protected void addLearnerVariants(SPAAlphabet alphabet, + MembershipOracle mqOracle, + SBALearnerVariantList variants) { + + final Builder builder = new Builder<>(alphabet, mqOracle, variants); + + builder.addLearnerVariant(DiscriminationTreeAdapter::new); + builder.addLearnerVariant(KearnsVaziraniAdapter::new); + builder.addLearnerVariant(LStarBaseAdapter::new); + builder.addLearnerVariant(RivestSchapireAdapter::new); + builder.addLearnerVariant(TTTAdapter::new); + } + + private static class Builder { + + private final SPAAlphabet alphabet; + private final MembershipOracle mqOracle; + private final SBALearnerVariantList variants; + private final List, ATManager>> atProviders; + + Builder(SPAAlphabet alphabet, MembershipOracle mqOracle, SBALearnerVariantList variants) { + this.alphabet = alphabet; + this.mqOracle = mqOracle; + this.variants = variants; + this.atProviders = Arrays.asList(DefaultATManager::new, OptimizingATManager::new); + } + + > & SupportsGrowingAlphabet> & AccessSequenceTransformer>> void addLearnerVariant( + LearnerConstructor, Boolean> provider) { + + for (Function, ATManager> atProvider : atProviders) { + final SBALearner learner = + new SBALearner<>(alphabet, mqOracle, (i) -> provider, atProvider.apply(alphabet)); + final String name = String.format("adapter=%s,manager=%s", provider, atProvider); + variants.addLearnerVariant(name, learner); + } + } + } + +} diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/SPAIT.java b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/SPAIT.java index 4c643e57ce..d6f3c91f72 100644 --- a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/SPAIT.java +++ b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/SPAIT.java @@ -71,7 +71,7 @@ & SupportsGrowingAlphabet & AccessSequenceTransforme for (Function, ATRManager> atrProvider : atrProviders) { final SPALearner learner = new SPALearner<>(alphabet, mqOracle, (i) -> provider, atrProvider.apply(alphabet)); - final String name = String.format("adapter=%s,provider=%s", provider, atrProvider); + final String name = String.format("adapter=%s,manager=%s", provider, atrProvider); variants.addLearnerVariant(name, learner); } } diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/ATManagerTest.java b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/ATManagerTest.java new file mode 100644 index 0000000000..4e9e4e5d41 --- /dev/null +++ b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/ATManagerTest.java @@ -0,0 +1,68 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm; + +import de.learnlib.algorithms.spmm.manager.DefaultATManager; +import de.learnlib.algorithms.spmm.manager.OptimizingATManager; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.words.Alphabet; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultSPAOutputAlphabet; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class ATManagerTest { + + private static final SPAAlphabet INPUT_ALPHABET; + private static final SPAOutputAlphabet OUTPUT_ALPHABET; + + static { + final Alphabet callAlphabet = Alphabets.characters('A', 'C'); + final Alphabet internalAlphabet = Alphabets.characters('a', 'b'); + final char returnSymbol = 'R'; + + INPUT_ALPHABET = new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); + OUTPUT_ALPHABET = new DefaultSPAOutputAlphabet<>(Alphabets.characters('x', 'z'), '✗'); + } + + @DataProvider + public static Object[] atManager() { + return new Object[] {new DefaultATManager<>(INPUT_ALPHABET, OUTPUT_ALPHABET), new OptimizingATManager<>(INPUT_ALPHABET, OUTPUT_ALPHABET)}; + } + + @Test(dataProvider = "atManager") + public void testScanning(ATManager manager) { + + final Word inputWord = Word.fromCharSequence("ABaRCbRR"); + final Word outputWord = Word.fromCharSequence("✓✓x✓✓y✓✓"); + + manager.scanCounterexample(new DefaultQuery<>(Word.epsilon(), inputWord, outputWord)); + + Assert.assertEquals(manager.getAccessSequence('A'), Word.fromCharSequence("A")); + Assert.assertEquals(manager.getAccessSequence('B'), Word.fromCharSequence("AB")); + Assert.assertEquals(manager.getAccessSequence('C'), Word.fromCharSequence("ABaRC")); + + Assert.assertEquals(manager.getTerminatingSequence('A'), Word.fromCharSequence("BaRCbR")); + Assert.assertEquals(manager.getTerminatingSequence('B'), Word.fromCharSequence("a")); + Assert.assertEquals(manager.getTerminatingSequence('C'), Word.fromCharSequence("b")); + } + +} diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/SPMMIT.java b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/SPMMIT.java new file mode 100644 index 0000000000..ea51bbceca --- /dev/null +++ b/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/SPMMIT.java @@ -0,0 +1,92 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm; + +import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; + +import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.spmm.adapter.DiscriminationTreeMealyAdapter; +import de.learnlib.algorithms.spmm.adapter.KearnsVaziraniMealyAdapter; +import de.learnlib.algorithms.spmm.adapter.LStarBaseMealyAdapter; +import de.learnlib.algorithms.spmm.adapter.RivestSchapireMealyAdapter; +import de.learnlib.algorithms.spmm.adapter.TTTMealyAdapter; +import de.learnlib.algorithms.spmm.manager.DefaultATManager; +import de.learnlib.algorithms.spmm.manager.OptimizingATManager; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.algorithm.LearnerConstructor; +import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.testsupport.it.learner.AbstractSPMMLearnerIT; +import de.learnlib.testsupport.it.learner.LearnerVariantList.SPMMLearnerVariantList; +import net.automatalib.SupportsGrowingAlphabet; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.Word; + +public class SPMMIT extends AbstractSPMMLearnerIT { + + @Override + protected void addLearnerVariants(SPAAlphabet alphabet, + SPAOutputAlphabet outputAlphabet, + MembershipOracle> mqOracle, + SPMMLearnerVariantList variants) { + + final Builder builder = new Builder<>(alphabet, outputAlphabet, mqOracle, variants); + + builder.addLearnerVariant(DiscriminationTreeMealyAdapter::new); + builder.addLearnerVariant(KearnsVaziraniMealyAdapter::new); + builder.addLearnerVariant(LStarBaseMealyAdapter::new); + builder.addLearnerVariant(RivestSchapireMealyAdapter::new); + builder.addLearnerVariant(TTTMealyAdapter::new); + } + + private static class Builder { + + private final SPAAlphabet inputAlphabet; + private final SPAOutputAlphabet outputAlphabet; + private final MembershipOracle> mqOracle; + private final SPMMLearnerVariantList variants; + private final List, SPAOutputAlphabet, ATManager>> atProviders; + + Builder(SPAAlphabet inputAlphabet, + SPAOutputAlphabet outputAlphabet, + MembershipOracle> mqOracle, + SPMMLearnerVariantList variants) { + this.inputAlphabet = inputAlphabet; + this.outputAlphabet = outputAlphabet; + this.mqOracle = mqOracle; + this.variants = variants; + this.atProviders = Arrays.asList(DefaultATManager::new, OptimizingATManager::new); + } + + , O> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> void addLearnerVariant( + LearnerConstructor, Word> provider) { + + for (BiFunction, SPAOutputAlphabet, ATManager> atProvider : atProviders) { + final SPMMLearner learner = new SPMMLearner<>(inputAlphabet, + outputAlphabet, + mqOracle, + (i) -> provider, + atProvider.apply(inputAlphabet, outputAlphabet)); + final String name = String.format("adapter=%s,manager=%s", provider, atProvider); + variants.addLearnerVariant(name, learner); + } + } + } + +} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java new file mode 100644 index 0000000000..69c424ccf2 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java @@ -0,0 +1,54 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.sba; + +import java.util.Collection; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.sba.SBA; +import net.automatalib.util.automata.Automata; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.Word; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class SimulatorEQOracle implements EquivalenceOracle, I, Boolean> { + + private final SBA sba; + + public SimulatorEQOracle(SBA sba) { + this.sba = sba; + } + + @Override + public @Nullable DefaultQuery findCounterExample(SBA hypothesis, Collection inputs) { + if (!(inputs instanceof SPAAlphabet)) { + throw new IllegalArgumentException("Inputs are not an SPA alphabet"); + } + + @SuppressWarnings("unchecked") + final SPAAlphabet alphabet = (SPAAlphabet) inputs; + + final Word sep = Automata.findSeparatingWord(sba, hypothesis, alphabet); + + if (sep == null) { + return null; + } + + return new DefaultQuery<>(sep, sba.computeOutput(sep)); + } +} + diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java new file mode 100644 index 0000000000..030fac0e40 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java @@ -0,0 +1,55 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.spmm; + +import java.util.Collection; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.spmm.SPMM; +import net.automatalib.util.automata.Automata; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.Word; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class SimulatorEQOracle implements EquivalenceOracle, I, Word> { + + private final SPMM spmm; + + public SimulatorEQOracle(SPMM spmm) { + this.spmm = spmm; + } + + @Override + public @Nullable DefaultQuery> findCounterExample(SPMM hypothesis, + Collection inputs) { + if (!(inputs instanceof SPAAlphabet)) { + throw new IllegalArgumentException("Inputs are not an SPA alphabet"); + } + + @SuppressWarnings("unchecked") + final SPAAlphabet alphabet = (SPAAlphabet) inputs; + + final Word sep = Automata.findSeparatingWord(spmm, hypothesis, alphabet); + + if (sep == null) { + return null; + } + + return new DefaultQuery<>(sep, spmm.computeOutput(sep)); + } +} + diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java index b59455fe18..bc41217423 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java @@ -39,7 +39,7 @@ public void testOracle() { final Random random = new Random(42); final SPAAlphabet alphabet = new DefaultSPAAlphabet<>(Alphabets.characters('x', 'z'), Alphabets.characters('A', 'C'), 'R'); - final SPA spa = RandomAutomata.randomRedundancyFreeSPA(random, alphabet, 4); + final SPA spa = RandomAutomata.randomSPA(random, alphabet, 4); final int lookahead = 2; final WMethodSPAEQOracle oracle = new WMethodSPAEQOracle<>(new SimulatorOracle<>(spa), lookahead); diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java index cd0d65308b..e9140ce9ff 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java @@ -39,7 +39,7 @@ public void testOracle() { final Random random = new Random(42); final SPAAlphabet alphabet = new DefaultSPAAlphabet<>(Alphabets.characters('x', 'z'), Alphabets.characters('A', 'C'), 'R'); - final SPA spa = RandomAutomata.randomRedundancyFreeSPA(random, alphabet, 4); + final SPA spa = RandomAutomata.randomSPA(random, alphabet, 4); final int lookahead = 2; final WpMethodSPAEQOracle oracle = new WpMethodSPAEQOracle<>(new SimulatorOracle<>(spa), lookahead); diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java new file mode 100644 index 0000000000..36b513f874 --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java @@ -0,0 +1,76 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.testsupport.it.learner; + +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.examples.LearningExample.SBALearningExample; +import de.learnlib.examples.LearningExamples; +import de.learnlib.oracle.equivalence.sba.SimulatorEQOracle; +import de.learnlib.oracle.membership.SimulatorOracle; +import de.learnlib.testsupport.it.learner.LearnerVariantList.SBALearnerVariantList; +import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SBALearnerVariantListImpl; +import net.automatalib.words.SPAAlphabet; +import org.testng.annotations.Factory; + +/** + * Abstract integration test for VPDA learning algorithms. + * + * @author frohme + */ +public abstract class AbstractSBALearnerIT { + + @Factory + public Object[] createExampleITCases() { + final List> examples = LearningExamples.createSBAExamples(); + final List> result = new ArrayList<>(examples.size()); + + for (SBALearningExample example : examples) { + result.addAll(createAllVariantsITCase(example)); + } + + return result.toArray(); + } + + private List> createAllVariantsITCase(SBALearningExample example) { + + final SPAAlphabet alphabet = example.getAlphabet(); + final MembershipOracle mqOracle = new SimulatorOracle<>(example.getReferenceAutomaton()); + final SBALearnerVariantListImpl variants = new SBALearnerVariantListImpl<>(); + addLearnerVariants(alphabet, mqOracle, variants); + + return LearnerITUtil.createExampleITCases(example, + variants, + new SimulatorEQOracle<>(example.getReferenceAutomaton())); + } + + /** + * Adds, for a given setup, all the variants of the DFA 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(SPAAlphabet alphabet, + MembershipOracle mqOracle, + SBALearnerVariantList variants); +} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java new file mode 100644 index 0000000000..7c4a553f2e --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java @@ -0,0 +1,80 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.testsupport.it.learner; + +import java.util.ArrayList; +import java.util.List; + +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.examples.LearningExample.SPMMLearningExample; +import de.learnlib.examples.LearningExamples; +import de.learnlib.oracle.equivalence.spmm.SimulatorEQOracle; +import de.learnlib.oracle.membership.SimulatorOracle; +import de.learnlib.testsupport.it.learner.LearnerVariantList.SPMMLearnerVariantList; +import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SPMMLearnerVariantListImpl; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.Word; +import org.testng.annotations.Factory; + +/** + * Abstract integration test for VPDA learning algorithms. + * + * @author frohme + */ +public abstract class AbstractSPMMLearnerIT { + + @Factory + public Object[] createExampleITCases() { + final List> examples = LearningExamples.createSPMMExamples(); + final List> result = new ArrayList<>(examples.size()); + + for (SPMMLearningExample example : examples) { + result.addAll(createAllVariantsITCase(example)); + } + + return result.toArray(); + } + + private List> createAllVariantsITCase(SPMMLearningExample example) { + + final MembershipOracle> mqOracle = new SimulatorOracle<>(example.getReferenceAutomaton()); + final SPMMLearnerVariantListImpl variants = new SPMMLearnerVariantListImpl<>(); + addLearnerVariants(example.getAlphabet(), example.getOutputAlphabet(), mqOracle, variants); + + return LearnerITUtil.createExampleITCases(example, + variants, + new SimulatorEQOracle<>(example.getReferenceAutomaton())); + } + + /** + * Adds, for a given setup, all the variants of the DFA learner to be tested to the specified + * {@link LearnerVariantList variant list}. + * + * @param inputAlphabet + * the input alphabet + * @param outputAlphabet + * the output alphabet + * @param mqOracle + * the membership oracle + * @param variants + * list to add the learner variants to + */ + protected abstract void addLearnerVariants(SPAAlphabet inputAlphabet, + SPAOutputAlphabet outputAlphabet, + MembershipOracle> mqOracle, + SPMMLearnerVariantList variants); +} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java index 945c6850a3..48cc076d1c 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java @@ -24,16 +24,22 @@ import de.learnlib.api.query.DefaultQuery; import de.learnlib.examples.LearningExample; import de.learnlib.examples.LearningExample.OneSEVPALearningExample; +import de.learnlib.examples.LearningExample.SBALearningExample; import de.learnlib.examples.LearningExample.SPALearningExample; +import de.learnlib.examples.LearningExample.SPMMLearningExample; import de.learnlib.examples.LearningExample.UniversalDeterministicLearningExample; import de.learnlib.examples.PassiveLearningExample; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.OneSEVPALearnerVariantListImpl; +import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SBALearnerVariantListImpl; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SPALearnerVariantListImpl; +import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SPMMLearnerVariantListImpl; import net.automatalib.automata.UniversalAutomaton; import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.FiniteRepresentation; import net.automatalib.automata.concepts.SuffixOutput; +import net.automatalib.automata.sba.SBA; import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.spmm.SPMM; import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; @@ -89,6 +95,38 @@ public static List> createExampleITCases(SPALearningExam SPALearnerITCase::new); } + /** + * Creates a list of per-example test cases for all learner variants. + * + * @return the list of test cases, one for each example + */ + public static List> createExampleITCases(SBALearningExample example, + SBALearnerVariantListImpl variants, + EquivalenceOracle, I, Boolean> eqOracle) { + // explicit generics are required for correct type-inference + return LearnerITUtil., SBALearningExample, SBALearnerITCase>createExampleITCasesInternal( + example, + variants, + eqOracle, + SBALearnerITCase::new); + } + + /** + * Creates a list of per-example test cases for all learner variants. + * + * @return the list of test cases, one for each example + */ + public static List> createExampleITCases(SPMMLearningExample example, + SPMMLearnerVariantListImpl variants, + EquivalenceOracle, I, Word> eqOracle) { + // explicit generics are required for correct type-inference + return LearnerITUtil., SPMM, SPMMLearningExample, SPMMLearnerITCase>createExampleITCasesInternal( + example, + variants, + eqOracle, + SPMMLearnerITCase::new); + } + /** * Creates a list of per-example test cases for all learner 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 07e36d6c72..142330a6c0 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 @@ -17,7 +17,9 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.sba.SBA; import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.spmm.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.vpda.OneSEVPA; @@ -79,8 +81,12 @@ interface MooreLearnerVariantList extends LearnerVariantList extends LearnerVariantList, I, O> {} - interface OneSEVPALearnerVariantList extends LearnerVariantList, I, Boolean> {} - interface SPALearnerVariantList extends LearnerVariantList, I, Boolean> {} + interface SBALearnerVariantList extends LearnerVariantList, I, Boolean> {} + + interface SPMMLearnerVariantList extends LearnerVariantList, I, Word> {} + + interface OneSEVPALearnerVariantList 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 4b62ac70b9..c1288d0010 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 @@ -22,7 +22,9 @@ import de.learnlib.util.mealy.MealyUtil; import de.learnlib.util.moore.MooreUtil; import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.sba.SBA; import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.spmm.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.vpda.OneSEVPA; @@ -64,6 +66,12 @@ public static class OneSEVPALearnerVariantListImpl extends LearnerVariantList public static class SPALearnerVariantListImpl extends LearnerVariantListImpl, I, Boolean> implements SPALearnerVariantList {} + public static class SBALearnerVariantListImpl extends LearnerVariantListImpl, I, Boolean> + implements SBALearnerVariantList {} + + public static class SPMMLearnerVariantListImpl extends LearnerVariantListImpl, I, Word> + implements SPMMLearnerVariantList {} + public static class MealySymLearnerVariantListImpl implements MealySymLearnerVariantList { private final MealyLearnerVariantListImpl mealyLearnerVariants = new MealyLearnerVariantListImpl<>(); diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SBALearnerITCase.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SBALearnerITCase.java new file mode 100644 index 0000000000..764bd36d46 --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SBALearnerITCase.java @@ -0,0 +1,41 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.testsupport.it.learner; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.examples.LearningExample.SBALearningExample; +import net.automatalib.automata.sba.SBA; +import net.automatalib.util.automata.Automata; +import net.automatalib.words.Word; + +public class SBALearnerITCase extends AbstractLearnerVariantITCase> { + + private final SBALearningExample example; + + SBALearnerITCase(LearnerVariant, I, Boolean> variant, + SBALearningExample example, + EquivalenceOracle, I, Boolean> eqOracle) { + super(variant, example, eqOracle); + this.example = example; + } + + @Override + protected Word checkEquivalence(SBA hypothesis) { + return Automata.findSeparatingWord(this.example.getReferenceAutomaton(), + hypothesis, + this.example.getAlphabet()); + } +} diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPMMLearnerITCase.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPMMLearnerITCase.java new file mode 100644 index 0000000000..38e74a4370 --- /dev/null +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPMMLearnerITCase.java @@ -0,0 +1,41 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.testsupport.it.learner; + +import de.learnlib.api.oracle.EquivalenceOracle; +import de.learnlib.examples.LearningExample.SPMMLearningExample; +import net.automatalib.automata.spmm.SPMM; +import net.automatalib.util.automata.Automata; +import net.automatalib.words.Word; + +public class SPMMLearnerITCase extends AbstractLearnerVariantITCase, SPMM> { + + private final SPMMLearningExample example; + + SPMMLearnerITCase(LearnerVariant, I, Word> variant, + SPMMLearningExample example, + EquivalenceOracle, I, Word> eqOracle) { + super(variant, example, eqOracle); + this.example = example; + } + + @Override + protected Word checkEquivalence(SPMM hypothesis) { + return Automata.findSeparatingWord(this.example.getReferenceAutomaton(), + hypothesis, + this.example.getAlphabet()); + } +} 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 aa9c8d427d..bdd3aeb3f6 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 @@ -19,13 +19,16 @@ import net.automatalib.automata.concepts.InputAlphabetHolder; import net.automatalib.automata.concepts.SuffixOutput; import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.sba.SBA; import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.spmm.SPMM; 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; import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; import net.automatalib.words.VPDAlphabet; import net.automatalib.words.Word; @@ -152,4 +155,47 @@ public SPAAlphabet getAlphabet() { } } + public static class DefaultSBALearningExample implements SBALearningExample { + + private final SBA referenceAutomaton; + + public DefaultSBALearningExample(SBA referenceAutomaton) { + this.referenceAutomaton = referenceAutomaton; + } + + @Override + public SBA getReferenceAutomaton() { + return this.referenceAutomaton; + } + + @Override + public SPAAlphabet getAlphabet() { + return this.referenceAutomaton.getInputAlphabet(); + } + } + + public static class DefaultSPMMLearningExample implements SPMMLearningExample { + + private final SPMM referenceAutomaton; + + public DefaultSPMMLearningExample(SPMM referenceAutomaton) { + this.referenceAutomaton = referenceAutomaton; + } + + @Override + public SPMM getReferenceAutomaton() { + return this.referenceAutomaton; + } + + @Override + public SPAAlphabet getAlphabet() { + return this.referenceAutomaton.getInputAlphabet(); + } + + @Override + public SPAOutputAlphabet getOutputAlphabet() { + return this.referenceAutomaton.getOutputAlphabet(); + } + } + } 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 76ebe5df4a..abdc09dcd3 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 @@ -17,7 +17,9 @@ import net.automatalib.automata.UniversalAutomaton; import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.sba.SBA; import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.spmm.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.transducers.StateLocalInputMealyMachine; @@ -25,6 +27,7 @@ import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Alphabet; import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; import net.automatalib.words.VPDAlphabet; public interface LearningExample { @@ -66,6 +69,20 @@ interface SPALearningExample extends LearningExample> { SPAAlphabet getAlphabet(); } + interface SBALearningExample extends LearningExample> { + + @Override + SPAAlphabet getAlphabet(); + } + + interface SPMMLearningExample extends LearningExample> { + + @Override + SPAAlphabet getAlphabet(); + + SPAOutputAlphabet getOutputAlphabet(); + } + interface OneSEVPALearningExample extends LearningExample> { @Override 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 db72032c7f..9911ed4997 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 @@ -25,7 +25,9 @@ import de.learnlib.examples.LearningExample.MealyLearningExample; import de.learnlib.examples.LearningExample.MooreLearningExample; import de.learnlib.examples.LearningExample.OneSEVPALearningExample; +import de.learnlib.examples.LearningExample.SBALearningExample; import de.learnlib.examples.LearningExample.SPALearningExample; +import de.learnlib.examples.LearningExample.SPMMLearningExample; import de.learnlib.examples.LearningExample.SSTLearningExample; import de.learnlib.examples.LearningExample.StateLocalInputMealyLearningExample; import de.learnlib.examples.dfa.ExampleAngluin; @@ -40,23 +42,29 @@ import de.learnlib.examples.mealy.ExampleStack; import de.learnlib.examples.mealy.ExampleTinyMealy; import de.learnlib.examples.moore.ExampleRandomMoore; +import de.learnlib.examples.sba.ExampleRandomSBA; import de.learnlib.examples.spa.ExamplePalindrome; import de.learnlib.examples.spa.ExampleRandomSPA; +import de.learnlib.examples.spmm.ExampleRandomSPMM; import de.learnlib.examples.sst.ExampleRandomSST; import de.learnlib.examples.vpda.ExampleRandomOneSEVPA; import net.automatalib.words.Alphabet; import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; import net.automatalib.words.VPDAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultSPAOutputAlphabet; import net.automatalib.words.impl.DefaultVPDAlphabet; public final class LearningExamples { private static final Alphabet RANDOM_ALPHABET = Alphabets.characters('a', 'c'); - private static final SPAAlphabet SPA_ALPHABET = + private static final SPAAlphabet SPA_INPUT_ALPHABET = new DefaultSPAAlphabet<>(Alphabets.characters('A', 'F'), Alphabets.characters('a', 'f'), 'R'); + private static final SPAOutputAlphabet SPA_OUTPUT_ALPHABET = + new DefaultSPAOutputAlphabet<>(Alphabets.characters('u', 'z'), '✗'); private static final VPDAlphabet VPD_ALPHABET = new DefaultVPDAlphabet<>(Alphabets.characters('a', 'f'), Alphabets.characters('1', '3'), Alphabets.characters('7', '9')); @@ -100,9 +108,9 @@ public static List> createDFAExamples() { public static List> createMooreExamples() { return Collections.singletonList(ExampleRandomMoore.createExample(new Random(RANDOM_SEED), - RANDOM_ALPHABET, - RANDOM_SIZE, - RANDOM_MEALY_OUTPUTS)); + RANDOM_ALPHABET, + RANDOM_SIZE, + RANDOM_MEALY_OUTPUTS)); } public static List> createSLIMealyExamples() { @@ -123,7 +131,22 @@ public static List> createDFAExamples() { public static List> createSPAExamples() { return Arrays.asList(ExamplePalindrome.createExample(), - ExampleRandomSPA.createExample(new Random(RANDOM_SEED), SPA_ALPHABET, PROCEDURE_SIZE)); + ExampleRandomSPA.createExample(new Random(RANDOM_SEED), + SPA_INPUT_ALPHABET, + PROCEDURE_SIZE)); + } + + public static List> createSBAExamples() { + return Collections.singletonList(ExampleRandomSBA.createExample(new Random(RANDOM_SEED), + SPA_INPUT_ALPHABET, + PROCEDURE_SIZE)); + } + + public static List> createSPMMExamples() { + return Collections.singletonList(ExampleRandomSPMM.createExample(new Random(RANDOM_SEED), + SPA_INPUT_ALPHABET, + SPA_OUTPUT_ALPHABET, + PROCEDURE_SIZE)); } public static List> createOneSEVPAExamples() { diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExampleRandomSBA.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExampleRandomSBA.java new file mode 100644 index 0000000000..c16b363628 --- /dev/null +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExampleRandomSBA.java @@ -0,0 +1,37 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.sba; + +import java.util.Random; + +import de.learnlib.examples.DefaultLearningExample.DefaultSBALearningExample; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.SPAAlphabet; + +public class ExampleRandomSBA extends DefaultSBALearningExample { + + public ExampleRandomSBA(SPAAlphabet alphabet, int size) { + this(new Random(), alphabet, size); + } + + public ExampleRandomSBA(Random random, SPAAlphabet alphabet, int size) { + super(RandomAutomata.randomSBA(random, alphabet, size)); + } + + public static ExampleRandomSBA createExample(Random random, SPAAlphabet alphabet, int size) { + return new ExampleRandomSBA<>(random, alphabet, size); + } +} diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExampleRandomSPA.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExampleRandomSPA.java index 8bf8cf65e0..b0ab449691 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExampleRandomSPA.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExampleRandomSPA.java @@ -28,7 +28,7 @@ public ExampleRandomSPA(SPAAlphabet alphabet, int size) { } public ExampleRandomSPA(Random random, SPAAlphabet alphabet, int size) { - super(RandomAutomata.randomSPA(random, alphabet, size, true)); + super(RandomAutomata.randomSPA(random, alphabet, size)); } public static ExampleRandomSPA createExample(Random random, SPAAlphabet alphabet, int size) { diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExampleRandomSPMM.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExampleRandomSPMM.java new file mode 100644 index 0000000000..585ff5f04b --- /dev/null +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExampleRandomSPMM.java @@ -0,0 +1,38 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.spmm; + +import java.util.Random; + +import de.learnlib.examples.DefaultLearningExample.DefaultSPMMLearningExample; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; + +public class ExampleRandomSPMM extends DefaultSPMMLearningExample { + + public ExampleRandomSPMM(SPAAlphabet inputAlphabet, SPAOutputAlphabet outputAlphabet, int size) { + this(new Random(), inputAlphabet, outputAlphabet, size); + } + + public ExampleRandomSPMM(Random random, SPAAlphabet inputAlphabet, SPAOutputAlphabet outputAlphabet, int size) { + super(RandomAutomata.randomSPMM(random, inputAlphabet, outputAlphabet, size)); + } + + public static ExampleRandomSPMM createExample(Random random, SPAAlphabet inputAlphabet, SPAOutputAlphabet outputAlphabet, int size) { + return new ExampleRandomSPMM<>(random, inputAlphabet, outputAlphabet, size); + } +} From c5e3849d6f52e969d80149fefde13b9f48d50f82 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 14 Jul 2023 00:49:19 +0200 Subject: [PATCH 02/15] cleanups / refactorings --- .../algorithms/sba/MappedStackSBA.java | 190 --------------- .../learnlib/algorithms/sba/MappingSBA.java | 124 ++++++++++ .../learnlib/algorithms/sba/SBALearner.java | 35 ++- .../algorithms/spmm/MappedStackSPMM.java | 223 ------------------ .../learnlib/algorithms/spmm/MappingSPMM.java | 146 ++++++++++++ .../learnlib/algorithms/spmm/SPMMLearner.java | 40 +++- 6 files changed, 336 insertions(+), 422 deletions(-) delete mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappedStackSBA.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappingSBA.java delete mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappedStackSPMM.java create mode 100644 algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappingSPMM.java diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappedStackSBA.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappedStackSBA.java deleted file mode 100644 index ced4d3265e..0000000000 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappedStackSBA.java +++ /dev/null @@ -1,190 +0,0 @@ -/* Copyright (C) 2013-2023 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.algorithms.sba; - -import java.util.Collection; -import java.util.Map; -import java.util.Objects; - -import com.google.common.collect.Maps; -import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.sba.SBA; -import net.automatalib.automata.spa.StackSPAState; -import net.automatalib.commons.util.mappings.Mapping; -import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.SPAAlphabet; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * A stack-based implementation for the (instrumented) semantics of a System of Procedural Automata. - * - * @param - * hypotheses state type - * @param - * input symbol type - * - * @author frohme - */ -public class MappedStackSBA - implements SBA, S>, I>, SimpleDTS, S>, I> { - - private final SPAAlphabet alphabet; - private final I initialCall; - private final Map>> procedures; - private final Mapping> mapping; - - // cast is fine, because we make sure to only query states belonging to the respective procedures - @SuppressWarnings("unchecked") - public MappedStackSBA(SPAAlphabet alphabet, - I initialCall, - Map>> procedures, - Mapping> mapping) { - this.alphabet = alphabet; - this.initialCall = initialCall; - this.procedures = (Map>>) procedures; - this.mapping = mapping; - } - - @Override - public StackSPAState, S> getTransition(StackSPAState, S> state, I i) { - if (state.isSink() || state.isTerm()) { - return StackSPAState.sink(); - } else if (alphabet.isInternalSymbol(i)) { - if (state.isInit()) { - return StackSPAState.sink(); - } - - final SymbolWrapper input = mapping.get(i); - final DFA> model = state.getProcedure(); - final S next = model.getTransition(state.getCurrentState(), input); - - // undefined internal transition - if (next == null || !model.isAccepting(next)) { - return StackSPAState.sink(); - } - - return state.updateState(next); - } else if (alphabet.isCallSymbol(i)) { - if (state.isInit() && !Objects.equals(this.initialCall, i)) { - return StackSPAState.sink(); - } - - final DFA> model = this.procedures.get(i); - - if (model == null) { - return StackSPAState.sink(); - } - - final S next = model.getInitialState(); - - if (next == null) { - return StackSPAState.sink(); - } - - // store the procedural successor in the stack so that we don't need to look it up on return symbols - final StackSPAState, S> returnState; - if (state.isInit()) { - returnState = StackSPAState.term(); - } else { - final SymbolWrapper input = mapping.get(i); - final DFA> p = state.getProcedure(); - final S succ = p.getSuccessor(state.getCurrentState(), input); - if (succ == null || !p.isAccepting(succ)) { - return StackSPAState.sink(); - } - returnState = state.updateState(succ); - } - - return returnState.push(model, next); - } else if (alphabet.isReturnSymbol(i)) { - if (state.isInit()) { - return StackSPAState.sink(); - } - - // if we returned the state before, we checked that a procedure is available - final DFA> model = state.getProcedure(); - final S succ = model.getSuccessor(state.getCurrentState(), mapping.get(i)); - - // cannot return, reject word - if (succ == null || !model.isAccepting(succ)) { - return StackSPAState.sink(); - } - - return state.pop(); - } else { - return StackSPAState.sink(); - } - } - - @Override - public boolean isAccepting(StackSPAState, S> state) { - return !state.isSink() && - (state.isInit() || state.isTerm() || state.getProcedure().isAccepting(state.getCurrentState())); - } - - @Override - public StackSPAState, S> getInitialState() { - return StackSPAState.init(); - } - - @Override - public I getInitialProcedure() { - return initialCall; - } - - @Override - public SPAAlphabet getInputAlphabet() { - return this.alphabet; - } - - @Override - public Map> getProcedures() { - return Maps.transformValues(this.procedures, DFAView::new); - } - - private class DFAView implements DFA { - - private final DFA> delegate; - - DFAView(DFA> delegate) { - this.delegate = delegate; - } - - @Override - public Collection getStates() { - return delegate.getStates(); - } - - @Override - public @Nullable S2 getTransition(S2 s, I i) { - final SymbolWrapper w = mapping.get(i); - if (w == null) { - return null; - } - return delegate.getTransition(s, w); - } - - @Override - public boolean isAccepting(S2 s) { - return delegate.isAccepting(s); - } - - @Override - public @Nullable S2 getInitialState() { - return delegate.getInitialState(); - } - } -} \ No newline at end of file diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappingSBA.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappingSBA.java new file mode 100644 index 0000000000..24bf5c99a6 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappingSBA.java @@ -0,0 +1,124 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.sba; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import com.google.common.collect.Maps; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.sba.SBA; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.ts.simple.SimpleDTS; +import net.automatalib.words.SPAAlphabet; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A stack-based implementation for the (instrumented) semantics of a System of Procedural Automata. + * + * @param + * hypotheses state type + * @param + * input symbol type + * + * @author frohme + */ +class MappingSBA implements SBA, SimpleDTS { + + private final SPAAlphabet alphabet; + private final Mapping> mapping; + private final SBA> delegate; + + private final Map> procedures; + + MappingSBA(SPAAlphabet alphabet, Mapping> mapping, SBA> delegate) { + this.alphabet = alphabet; + this.mapping = mapping; + this.delegate = delegate; + + final Map, DFA>> p = delegate.getProcedures(); + this.procedures = Maps.newHashMapWithExpectedSize(p.size()); + + for (Entry, DFA>> e : p.entrySet()) { + procedures.put(e.getKey().getDelegate(), new DFAView<>(e.getValue())); + } + } + + @Override + public S getTransition(S state, I i) { + return this.delegate.getTransition(state, this.mapping.get(i)); + } + + @Override + public boolean isAccepting(S state) { + return this.delegate.isAccepting(state); + } + + @Override + public S getInitialState() { + return this.delegate.getInitialState(); + } + + @Override + public @Nullable I getInitialProcedure() { + final SymbolWrapper init = this.delegate.getInitialProcedure(); + return init == null ? null : init.getDelegate(); + } + + @Override + public SPAAlphabet getInputAlphabet() { + return this.alphabet; + } + + @Override + public Map> getProcedures() { + return this.procedures; + } + + private class DFAView implements DFA { + + private final DFA> delegate; + + DFAView(DFA> delegate) { + this.delegate = delegate; + } + + @Override + public Collection getStates() { + return delegate.getStates(); + } + + @Override + public @Nullable S2 getTransition(S2 s, I i) { + final SymbolWrapper w = mapping.get(i); + if (w == null) { + return null; + } + return delegate.getTransition(s, w); + } + + @Override + public boolean isAccepting(S2 s) { + return delegate.isAccepting(s); + } + + @Override + public @Nullable S2 getInitialState() { + return delegate.getInitialState(); + } + } +} \ No newline at end of file diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java index 9cf81f3c8a..aabbdc85af 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java @@ -34,14 +34,17 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.sba.EmptySBA; import net.automatalib.automata.sba.SBA; +import net.automatalib.automata.sba.StackSBA; import net.automatalib.commons.util.Pair; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.sba.SBAUtil; +import net.automatalib.words.Alphabet; import net.automatalib.words.SPAAlphabet; import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; +import net.automatalib.words.impl.DefaultSPAAlphabet; import net.automatalib.words.impl.GrowingMapAlphabet; public class SBALearner> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> @@ -124,8 +127,8 @@ private boolean refineHypothesisInternal(DefaultQuery defaultQuery) final int callIdx = this.alphabet.findCallIndex(input, mismatchIdx); final I procedure = input.getSymbol(callIdx); - final Word localTrace = this.alphabet.project(input.subWord(callIdx + 1, mismatchIdx), 0) - .append(input.getSymbol(mismatchIdx)); + final Word localTrace = + this.alphabet.project(input.subWord(callIdx + 1, mismatchIdx), 0).append(input.getSymbol(mismatchIdx)); final DefaultQuery, Boolean> localCE = constructLocalCE(localTrace, defaultQuery.getOutput()); boolean localRefinement = this.subLearners.get(procedure).refineHypothesis(localCE); @@ -141,7 +144,33 @@ public SBA getHypothesisModel() { return new EmptySBA<>(this.alphabet); } - return new MappedStackSBA<>(alphabet, initialCallSymbol, getSubModels(), mapper); + final Map>> procedures = getSubModels(); + final Alphabet> internalAlphabet = new GrowingMapAlphabet<>(); + final Alphabet> callAlphabet = new GrowingMapAlphabet<>(); + final Map, DFA>> mappedProcedures = + Maps.newHashMapWithExpectedSize(procedures.size()); + + for (I i : this.alphabet) { + final SymbolWrapper mappedI = this.mapper.get(i); + + if (this.alphabet.isCallSymbol(i)) { + callAlphabet.add(mappedI); + final DFA> p = procedures.get(i); + if (p != null) { + mappedProcedures.put(mappedI, p); + } + } else if (alphabet.isInternalSymbol(i)) { + internalAlphabet.add(mappedI); + } + } + + final SPAAlphabet> mappedAlphabet = + new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, this.mapper.get(alphabet.getReturnSymbol())); + + final StackSBA> delegate = + new StackSBA<>(mappedAlphabet, this.mapper.get(initialCallSymbol), mappedProcedures); + + return new MappingSBA<>(alphabet, mapper, delegate); } private boolean extractUsefulInformationFromCounterExample(DefaultQuery defaultQuery) { diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappedStackSPMM.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappedStackSPMM.java deleted file mode 100644 index 23539443f4..0000000000 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappedStackSPMM.java +++ /dev/null @@ -1,223 +0,0 @@ -/* Copyright (C) 2013-2023 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.algorithms.spmm; - -import java.util.Collection; -import java.util.Map; -import java.util.Objects; - -import com.google.common.collect.Maps; -import de.learnlib.algorithms.sba.SymbolWrapper; -import net.automatalib.automata.spmm.SPMM; -import net.automatalib.automata.spmm.StackSPMMState; -import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.automata.transducers.impl.MealyTransition; -import net.automatalib.commons.util.mappings.Mapping; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * A stack-based implementation for the (instrumented) semantics of a System of Procedural Automata. - * - * @param - * hypotheses state type - * @param - * input symbol type - * - * @author frohme - */ -public class MappedStackSPMM - implements SPMM, T, O>, I, MealyTransition, T, O>, O>, O> { - - private final SPAAlphabet inputAlphabet; - private final SPAOutputAlphabet outputAlphabet; - - private final I initialCall; - private final O initialOutput; - private final Map, T, O>> procedures; - private final Mapping> mapping; - - @SuppressWarnings("unchecked") - public MappedStackSPMM(SPAAlphabet inputAlphabet, - SPAOutputAlphabet outputAlphabet, - I initialCall, - O initialOutput, - Map, ? extends T, O>> procedures, - Mapping> mapping) { - this.inputAlphabet = inputAlphabet; - this.outputAlphabet = outputAlphabet; - this.initialCall = initialCall; - this.initialOutput = initialOutput; - this.procedures = (Map, T, O>>) procedures; - this.mapping = mapping; - } - - @Override - public MealyTransition, T, O>, O> getTransition(StackSPMMState, T, O> state, - I i) { - if (state.isSink() || state.isTerm()) { - return sink(); - } else if (inputAlphabet.isInternalSymbol(i)) { - if (state.isInit()) { - return sink(); - } - - final SymbolWrapper input = mapping.get(i); - final MealyMachine, T, O> model = state.getProcedure(); - final T t = model.getTransition(state.getCurrentState(), input); - - if (t == null || outputAlphabet.isErrorSymbol(model.getTransitionOutput(t))) { - return sink(); - } - - final S succ = model.getSuccessor(t); - final StackSPMMState, T, O> next = state.updateState(succ); - - return new MealyTransition<>(next, model.getTransitionOutput(t)); - } else if (inputAlphabet.isCallSymbol(i)) { - if (state.isInit() && !Objects.equals(this.initialCall, i)) { - return sink(); - } - - final MealyMachine, T, O> model = this.procedures.get(i); - - if (model == null) { - return sink(); - } - - final S next = model.getInitialState(); - - if (next == null) { - return sink(); - } - - // store the procedural successor in the stack so that we don't need to look it up on return symbols - final StackSPMMState, T, O> returnState; - final O output; - if (state.isInit()) { - returnState = StackSPMMState.term(); - output = initialOutput; - } else { - final SymbolWrapper input = mapping.get(i); - final MealyMachine, T, O> p = state.getProcedure(); - final T t = p.getTransition(state.getCurrentState(), input); - - if (t == null || outputAlphabet.isErrorSymbol(p.getTransitionOutput(t))) { - return sink(); - } - returnState = state.updateState(p.getSuccessor(t)); - output = p.getTransitionOutput(t); - } - - return new MealyTransition<>(returnState.push(model, next), output); - } else if (inputAlphabet.isReturnSymbol(i)) { - if (state.isInit()) { - return sink(); - } - - // if we returned the state before, we checked that a procedure is available - final MealyMachine, T, O> model = state.getProcedure(); - final T t = model.getTransition(state.getCurrentState(), mapping.get(i)); - - if (t == null || outputAlphabet.isErrorSymbol(model.getTransitionOutput(t))) { - return sink(); - } - - return new MealyTransition<>(state.pop(), model.getTransitionOutput(t)); - } else { - return sink(); - } - } - - @Override - public StackSPMMState, T, O> getInitialState() { - return StackSPMMState.init(); - } - - @Override - public I getInitialProcedure() { - return initialCall; - } - - @Override - public SPAAlphabet getInputAlphabet() { - return this.inputAlphabet; - } - - @Override - public SPAOutputAlphabet getOutputAlphabet() { - return this.outputAlphabet; - } - - @Override - public O getTransitionOutput(MealyTransition, T, O>, O> transition) { - return transition.getOutput(); - } - - @Override - public StackSPMMState, T, O> getSuccessor(MealyTransition, T, O>, O> transition) { - return transition.getSuccessor(); - } - - private MealyTransition, T, O>, O> sink() { - return new MealyTransition<>(StackSPMMState.sink(), outputAlphabet.getErrorSymbol()); - } - - @Override - public Map> getProcedures() { - return Maps.transformValues(this.procedures, MealyView::new); - } - - private class MealyView implements MealyMachine { - - private final MealyMachine, T2, O> delegate; - - MealyView(MealyMachine, T2, O> delegate) { - this.delegate = delegate; - } - - @Override - public Collection getStates() { - return this.delegate.getStates(); - } - - @Override - public O getTransitionOutput(T2 t2) { - return this.delegate.getTransitionOutput(t2); - } - - @Override - public @Nullable T2 getTransition(S2 s2, I i) { - final SymbolWrapper w = mapping.get(i); - if (w == null) { - return null; - } - return delegate.getTransition(s2, w); - } - - @Override - public S2 getSuccessor(T2 t2) { - return this.delegate.getSuccessor(t2); - } - - @Override - public @Nullable S2 getInitialState() { - return this.delegate.getInitialState(); - } - } - -} \ No newline at end of file diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappingSPMM.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappingSPMM.java new file mode 100644 index 0000000000..944ef79441 --- /dev/null +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappingSPMM.java @@ -0,0 +1,146 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.spmm; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import com.google.common.collect.Maps; +import de.learnlib.algorithms.sba.SymbolWrapper; +import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.commons.util.mappings.Mapping; +import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.SPAOutputAlphabet; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * A stack-based implementation for the (instrumented) semantics of a System of Procedural Automata. + * + * @param + * hypotheses state type + * @param + * input symbol type + * + * @author frohme + */ +class MappingSPMM implements SPMM { + + private final SPAAlphabet inputAlphabet; + private final SPAOutputAlphabet outputAlphabet; + private final Mapping> mapping; + private final SPMM, T, O> delegate; + + private final Map> procedures; + + MappingSPMM(SPAAlphabet inputAlphabet, + SPAOutputAlphabet outputAlphabet, + Mapping> mapping, + SPMM, T, O> delegate) { + this.inputAlphabet = inputAlphabet; + this.outputAlphabet = outputAlphabet; + this.mapping = mapping; + this.delegate = delegate; + + final Map, MealyMachine, ?, O>> p = delegate.getProcedures(); + this.procedures = Maps.newHashMapWithExpectedSize(p.size()); + + for (Entry, MealyMachine, ?, O>> e : p.entrySet()) { + procedures.put(e.getKey().getDelegate(), new MealyView<>(e.getValue())); + } + } + + @Override + public T getTransition(S state, I i) { + return this.delegate.getTransition(state, this.mapping.get(i)); + } + + @Override + public S getInitialState() { + return this.delegate.getInitialState(); + } + + @Override + public @Nullable I getInitialProcedure() { + final SymbolWrapper init = this.delegate.getInitialProcedure(); + return init == null ? null : init.getDelegate(); + } + + @Override + public SPAAlphabet getInputAlphabet() { + return this.inputAlphabet; + } + + @Override + public SPAOutputAlphabet getOutputAlphabet() { + return this.outputAlphabet; + } + + @Override + public O getTransitionOutput(T transition) { + return this.delegate.getTransitionOutput(transition); + } + + @Override + public S getSuccessor(T transition) { + return this.delegate.getSuccessor(transition); + } + + @Override + public Map> getProcedures() { + return this.procedures; + } + + private class MealyView implements MealyMachine { + + private final MealyMachine, T2, O> delegate; + + MealyView(MealyMachine, T2, O> delegate) { + this.delegate = delegate; + } + + @Override + public Collection getStates() { + return this.delegate.getStates(); + } + + @Override + public O getTransitionOutput(T2 t2) { + return this.delegate.getTransitionOutput(t2); + } + + @Override + public @Nullable T2 getTransition(S2 s2, I i) { + final SymbolWrapper w = mapping.get(i); + if (w == null) { + return null; + } + return delegate.getTransition(s2, w); + } + + @Override + public S2 getSuccessor(T2 t2) { + return this.delegate.getSuccessor(t2); + } + + @Override + public @Nullable S2 getInitialState() { + return this.delegate.getInitialState(); + } + } + +} \ No newline at end of file diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java index 08bfb9ccac..818c9b608c 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java +++ b/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java @@ -37,16 +37,19 @@ import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.spmm.EmptySPMM; import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.spmm.StackSPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.util.automata.Automata; import net.automatalib.util.automata.spmm.SPMMUtil; +import net.automatalib.words.Alphabet; import net.automatalib.words.SPAAlphabet; import net.automatalib.words.SPAOutputAlphabet; import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; +import net.automatalib.words.impl.DefaultSPAAlphabet; import net.automatalib.words.impl.GrowingMapAlphabet; public class SPMMLearner, O> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> @@ -162,12 +165,37 @@ private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) return new EmptySPMM<>(this.inputAlphabet, outputAlphabet); } - return new MappedStackSPMM<>(inputAlphabet, - outputAlphabet, - initialCallSymbol, - initialOutputSymbol, - getSubModels(), - mapper); + final Map, ?, O>> procedures = getSubModels(); + final Alphabet> internalAlphabet = new GrowingMapAlphabet<>(); + final Alphabet> callAlphabet = new GrowingMapAlphabet<>(); + final Map, MealyMachine, ?, O>> mappedProcedures = + Maps.newHashMapWithExpectedSize(procedures.size()); + + for (I i : this.inputAlphabet) { + final SymbolWrapper mappedI = this.mapper.get(i); + + if (this.inputAlphabet.isCallSymbol(i)) { + callAlphabet.add(mappedI); + final MealyMachine, ?, O> p = procedures.get(i); + if (p != null) { + mappedProcedures.put(mappedI, p); + } + } else if (inputAlphabet.isInternalSymbol(i)) { + internalAlphabet.add(mappedI); + } + } + + final SPAAlphabet> mappedAlphabet = new DefaultSPAAlphabet<>(internalAlphabet, + callAlphabet, + this.mapper.get(inputAlphabet.getReturnSymbol())); + + final StackSPMM, ?, O> delegate = new StackSPMM<>(mappedAlphabet, + outputAlphabet, + this.mapper.get(initialCallSymbol), + initialOutputSymbol, + mappedProcedures); + + return new MappingSPMM<>(inputAlphabet, outputAlphabet, mapper, delegate); } private boolean extractUsefulInformationFromCounterExample(DefaultQuery> defaultQuery) { From 4ec8b94d05268b721d7d3b7933f64cfc80f298db Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 14 Jul 2023 11:17:27 +0200 Subject: [PATCH 03/15] refactorings --- CHANGELOG.md | 2 +- README.md | 2 +- algorithms/active/pom.xml | 2 +- algorithms/active/{spa => procedural}/pom.xml | 6 ++-- .../procedural}/AlphabetMapper.java | 2 +- .../algorithms/procedural}/SymbolWrapper.java | 2 +- .../dfa/DiscriminationTreeAdapterDFA.java} | 6 ++-- .../dfa/KearnsVaziraniAdapterDFA.java} | 6 ++-- .../adapter/dfa/LStarBaseAdapterDFA.java} | 6 ++-- .../dfa/RivestSchapireAdapterDFA.java} | 6 ++-- .../adapter/dfa/TTTAdapterDFA.java} | 6 ++-- .../DiscriminationTreeAdapterMealy.java} | 6 ++-- .../mealy/KearnsVaziraniAdapterMealy.java} | 6 ++-- .../adapter/mealy/LStarBaseAdapterMealy.java} | 6 ++-- .../mealy/RivestSchapireAdapterMealy.java} | 16 +++++++++-- .../adapter/mealy/TTTAdapterMealy.java} | 6 ++-- .../algorithms/procedural}/sba/ATManager.java | 3 +- .../procedural}/sba/MappingSBA.java | 3 +- .../sba/ProceduralMembershipOracle.java | 13 +++++---- .../procedural}/sba/SBALearner.java | 6 ++-- .../sba/manager/DefaultATManager.java | 6 ++-- .../sba/manager/OptimizingATManager.java | 21 ++++++++------ .../procedural}/spa/ATRManager.java | 2 +- .../spa/ProceduralMembershipOracle.java | 2 +- .../procedural}/spa/SPALearner.java | 4 +-- .../spa/manager/DefaultATRManager.java | 4 +-- .../spa/manager/OptimizingATRManager.java | 11 ++++---- .../procedural}/spmm/ATManager.java | 4 +-- .../procedural}/spmm/MappingSPMM.java | 4 +-- .../spmm/ProceduralMembershipOracle.java | 16 +++++------ .../procedural}/spmm/SPMMLearner.java | 8 +++--- .../spmm/manager/DefaultATManager.java | 8 ++++-- .../spmm/manager/OptimizingATManager.java | 14 +++++++--- .../procedural}/sba/ATManagerTest.java | 6 ++-- .../algorithms/procedural}/sba/SBAIT.java | 27 +++++++++--------- .../procedural}/spa/ATRManagerTest.java | 6 ++-- .../algorithms/procedural}/spa/SPAIT.java | 26 ++++++++--------- .../procedural}/spmm/ATManagerTest.java | 6 ++-- .../algorithms/procedural}/spmm/SPMMIT.java | 28 +++++++++---------- distribution/pom.xml | 4 +-- pom.xml | 2 +- 41 files changed, 175 insertions(+), 145 deletions(-) rename algorithms/active/{spa => procedural}/pom.xml (93%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/sba => procedural/src/main/java/de/learnlib/algorithms/procedural}/AlphabetMapper.java (97%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/sba => procedural/src/main/java/de/learnlib/algorithms/procedural}/SymbolWrapper.java (97%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spa/adapter/DiscriminationTreeAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/DiscriminationTreeAdapterDFA.java} (83%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spa/adapter/KearnsVaziraniAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/KearnsVaziraniAdapterDFA.java} (86%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spa/adapter/LStarBaseAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/LStarBaseAdapterDFA.java} (87%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spa/adapter/RivestSchapireAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/RivestSchapireAdapterDFA.java} (90%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spa/adapter/TTTAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/TTTAdapterDFA.java} (86%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spmm/adapter/DiscriminationTreeMealyAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DiscriminationTreeAdapterMealy.java} (88%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spmm/adapter/KearnsVaziraniMealyAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/KearnsVaziraniAdapterMealy.java} (90%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spmm/adapter/LStarBaseMealyAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java} (92%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spmm/adapter/RivestSchapireMealyAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java} (83%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms/spmm/adapter/TTTMealyAdapter.java => procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/TTTAdapterMealy.java} (89%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/sba/ATManager.java (93%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/sba/MappingSBA.java (97%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/sba/ProceduralMembershipOracle.java (90%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/sba/SBALearner.java (98%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/sba/manager/DefaultATManager.java (95%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/sba/manager/OptimizingATManager.java (91%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spa/ATRManager.java (96%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spa/ProceduralMembershipOracle.java (98%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spa/SPALearner.java (99%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spa/manager/DefaultATRManager.java (96%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spa/manager/OptimizingATRManager.java (95%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spmm/ATManager.java (93%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spmm/MappingSPMM.java (97%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spmm/ProceduralMembershipOracle.java (91%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spmm/SPMMLearner.java (98%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spmm/manager/DefaultATManager.java (92%) rename algorithms/active/{spa/src/main/java/de/learnlib/algorithms => procedural/src/main/java/de/learnlib/algorithms/procedural}/spmm/manager/OptimizingATManager.java (95%) rename algorithms/active/{spa/src/test/java/de/learnlib/algorithms => procedural/src/test/java/de/learnlib/algorithms/procedural}/sba/ATManagerTest.java (92%) rename algorithms/active/{spa/src/test/java/de/learnlib/algorithms => procedural/src/test/java/de/learnlib/algorithms/procedural}/sba/SBAIT.java (75%) rename algorithms/active/{spa/src/test/java/de/learnlib/algorithms => procedural/src/test/java/de/learnlib/algorithms/procedural}/spa/ATRManagerTest.java (93%) rename algorithms/active/{spa/src/test/java/de/learnlib/algorithms => procedural/src/test/java/de/learnlib/algorithms/procedural}/spa/SPAIT.java (75%) rename algorithms/active/{spa/src/test/java/de/learnlib/algorithms => procedural/src/test/java/de/learnlib/algorithms/procedural}/spmm/ATManagerTest.java (93%) rename algorithms/active/{spa/src/test/java/de/learnlib/algorithms => procedural/src/test/java/de/learnlib/algorithms/procedural}/spmm/SPMMIT.java (79%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84fdd1526b..55c1cb5229 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,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 a new learning algorithm for systems of procedural systems (SPAs, SBAs, SPMMs). * Added Moore versions of the learners `DT`, `TTT`, `LStar`, thanks to [Mohamad Bayram](https://github.com/mohbayram). * Migrated the AAAR algorithm from the old closed-source LearnLib. diff --git a/README.md b/README.md index 5a46953dd3..4ff652e4f7 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Kearns & Vazirani | `DFA` `Mealy` L* (incl. variants) | `DFA` `Mealy` `Moore` NL* | `NFA` OML | `DFA` `Mealy` -SPA | `SPA` +Procedural | `SPA` `SBA` `SPMM` TTT | `DFA` `Mealy` `Moore` `VPDA` diff --git a/algorithms/active/pom.xml b/algorithms/active/pom.xml index 75cb010d94..c72b59a0e6 100644 --- a/algorithms/active/pom.xml +++ b/algorithms/active/pom.xml @@ -41,7 +41,7 @@ limitations under the License. lstar nlstar oml - spa + procedural ttt ttt-vpda diff --git a/algorithms/active/spa/pom.xml b/algorithms/active/procedural/pom.xml similarity index 93% rename from algorithms/active/spa/pom.xml rename to algorithms/active/procedural/pom.xml index 5dc97d050b..198db8adec 100644 --- a/algorithms/active/spa/pom.xml +++ b/algorithms/active/procedural/pom.xml @@ -25,11 +25,11 @@ limitations under the License. ../pom.xml - learnlib-spa + learnlib-procedural - LearnLib :: Algorithms :: SPA + LearnLib :: Algorithms :: Procedural - An active learning algorithm for systems of procedural automata. Contains the base learning framework as well as adapters for orchestrating various regular learners of LearnLib to the context-free learning setup. + Active learning algorithms for procedural systems. Currently, contains learners for SPAs, SBAs, and SPMMs including adapters for orchestrating various regular learners of LearnLib to the context-free learning setup. diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/AlphabetMapper.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java similarity index 97% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/AlphabetMapper.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java index 9ca4d379ef..a053649f06 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/AlphabetMapper.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba; +package de.learnlib.algorithms.procedural; import java.util.Arrays; import java.util.Collection; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SymbolWrapper.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java similarity index 97% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SymbolWrapper.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java index 2e62bfe668..880a8c4541 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SymbolWrapper.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba; +package de.learnlib.algorithms.procedural; import java.util.Objects; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/DiscriminationTreeAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/DiscriminationTreeAdapterDFA.java similarity index 83% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/DiscriminationTreeAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/DiscriminationTreeAdapterDFA.java index c0917d4d25..55b6e786ca 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/DiscriminationTreeAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/DiscriminationTreeAdapterDFA.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa.adapter; +package de.learnlib.algorithms.procedural.adapter.dfa; import de.learnlib.algorithms.discriminationtree.dfa.DTLearnerDFA; import de.learnlib.api.AccessSequenceTransformer; @@ -30,9 +30,9 @@ * * @author frohme */ -public class DiscriminationTreeAdapter extends DTLearnerDFA implements AccessSequenceTransformer { +public class DiscriminationTreeAdapterDFA extends DTLearnerDFA implements AccessSequenceTransformer { - public DiscriminationTreeAdapter(Alphabet alphabet, MembershipOracle oracle) { + public DiscriminationTreeAdapterDFA(Alphabet alphabet, MembershipOracle oracle) { super(alphabet, oracle, LocalSuffixFinders.RIVEST_SCHAPIRE, true, true); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/KearnsVaziraniAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/KearnsVaziraniAdapterDFA.java similarity index 86% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/KearnsVaziraniAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/KearnsVaziraniAdapterDFA.java index 7a56778bfb..cc654004c0 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/KearnsVaziraniAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/KearnsVaziraniAdapterDFA.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa.adapter; +package de.learnlib.algorithms.procedural.adapter.dfa; import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.kv.dfa.KearnsVaziraniDFA; @@ -31,9 +31,9 @@ * * @author frohme */ -public class KearnsVaziraniAdapter extends KearnsVaziraniDFA implements AccessSequenceTransformer { +public class KearnsVaziraniAdapterDFA extends KearnsVaziraniDFA implements AccessSequenceTransformer { - public KearnsVaziraniAdapter(Alphabet alphabet, MembershipOracle oracle) { + public KearnsVaziraniAdapterDFA(Alphabet alphabet, MembershipOracle oracle) { super(alphabet, oracle, true, AcexAnalyzers.BINARY_SEARCH_FWD); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/LStarBaseAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/LStarBaseAdapterDFA.java similarity index 87% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/LStarBaseAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/LStarBaseAdapterDFA.java index 6d746788f5..eec1553576 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/LStarBaseAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/LStarBaseAdapterDFA.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa.adapter; +package de.learnlib.algorithms.procedural.adapter.dfa; import java.util.Objects; @@ -34,9 +34,9 @@ * * @author frohme */ -public class LStarBaseAdapter extends ClassicLStarDFA implements AccessSequenceTransformer, DFALearner { +public class LStarBaseAdapterDFA extends ClassicLStarDFA implements AccessSequenceTransformer, DFALearner { - public LStarBaseAdapter(Alphabet alphabet, MembershipOracle oracle) { + public LStarBaseAdapterDFA(Alphabet alphabet, MembershipOracle oracle) { super(alphabet, oracle); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/RivestSchapireAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/RivestSchapireAdapterDFA.java similarity index 90% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/RivestSchapireAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/RivestSchapireAdapterDFA.java index 48def54e33..8985843fa8 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/RivestSchapireAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/RivestSchapireAdapterDFA.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa.adapter; +package de.learnlib.algorithms.procedural.adapter.dfa; import java.util.Objects; @@ -34,10 +34,10 @@ * * @author frohme */ -public class RivestSchapireAdapter extends RivestSchapireDFA +public class RivestSchapireAdapterDFA extends RivestSchapireDFA implements AccessSequenceTransformer, DFALearner { - public RivestSchapireAdapter(Alphabet alphabet, MembershipOracle oracle) { + public RivestSchapireAdapterDFA(Alphabet alphabet, MembershipOracle oracle) { super(alphabet, oracle); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/TTTAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/TTTAdapterDFA.java similarity index 86% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/TTTAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/TTTAdapterDFA.java index dca11306b8..9dae19589b 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/adapter/TTTAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/TTTAdapterDFA.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa.adapter; +package de.learnlib.algorithms.procedural.adapter.dfa; import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.ttt.base.TTTState; @@ -31,9 +31,9 @@ * * @author frohme */ -public class TTTAdapter extends TTTLearnerDFA implements AccessSequenceTransformer { +public class TTTAdapterDFA extends TTTLearnerDFA implements AccessSequenceTransformer { - public TTTAdapter(Alphabet alphabet, MembershipOracle oracle) { + public TTTAdapterDFA(Alphabet alphabet, MembershipOracle oracle) { super(alphabet, oracle, AcexAnalyzers.BINARY_SEARCH_BWD); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/DiscriminationTreeMealyAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DiscriminationTreeAdapterMealy.java similarity index 88% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/DiscriminationTreeMealyAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DiscriminationTreeAdapterMealy.java index 3ecc07aa80..7d0ad571f4 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/DiscriminationTreeMealyAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DiscriminationTreeAdapterMealy.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm.adapter; +package de.learnlib.algorithms.procedural.adapter.mealy; import de.learnlib.algorithms.discriminationtree.mealy.DTLearnerMealy; import de.learnlib.api.AccessSequenceTransformer; @@ -32,9 +32,9 @@ * * @author frohme */ -public class DiscriminationTreeMealyAdapter extends DTLearnerMealy implements AccessSequenceTransformer { +public class DiscriminationTreeAdapterMealy extends DTLearnerMealy implements AccessSequenceTransformer { - public DiscriminationTreeMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + public DiscriminationTreeAdapterMealy(Alphabet alphabet, MembershipOracle> oracle) { super(alphabet, oracle, LocalSuffixFinders.RIVEST_SCHAPIRE, true); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/KearnsVaziraniMealyAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/KearnsVaziraniAdapterMealy.java similarity index 90% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/KearnsVaziraniMealyAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/KearnsVaziraniAdapterMealy.java index d96d7cc8e7..b5b4f009d0 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/KearnsVaziraniMealyAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/KearnsVaziraniAdapterMealy.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm.adapter; +package de.learnlib.algorithms.procedural.adapter.mealy; import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.kv.mealy.KearnsVaziraniMealy; @@ -33,10 +33,10 @@ * * @author frohme */ -public class KearnsVaziraniMealyAdapter extends KearnsVaziraniMealy +public class KearnsVaziraniAdapterMealy extends KearnsVaziraniMealy implements AccessSequenceTransformer { - public KearnsVaziraniMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + public KearnsVaziraniAdapterMealy(Alphabet alphabet, MembershipOracle> oracle) { super(alphabet, oracle, false, AcexAnalyzers.LINEAR_FWD); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/LStarBaseMealyAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java similarity index 92% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/LStarBaseMealyAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java index 1146dfec57..d1ac122a75 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/LStarBaseMealyAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm.adapter; +package de.learnlib.algorithms.procedural.adapter.mealy; import java.util.Collections; import java.util.Objects; @@ -38,9 +38,9 @@ * * @author frohme */ -public class LStarBaseMealyAdapter extends ExtensibleLStarMealy implements AccessSequenceTransformer { +public class LStarBaseAdapterMealy extends ExtensibleLStarMealy implements AccessSequenceTransformer { - public LStarBaseMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + public LStarBaseAdapterMealy(Alphabet alphabet, MembershipOracle> oracle) { super(alphabet, oracle, Collections.singletonList(Word.epsilon()), diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/RivestSchapireMealyAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java similarity index 83% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/RivestSchapireMealyAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java index 23758cb418..b8f34b2c0d 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/RivestSchapireMealyAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm.adapter; +package de.learnlib.algorithms.procedural.adapter.mealy; import java.util.Objects; @@ -25,10 +25,20 @@ import net.automatalib.words.Alphabet; import net.automatalib.words.Word; -public class RivestSchapireMealyAdapter extends RivestSchapireMealy +/** + * Adapter for using {@link RivestSchapireMealy} as a sub-procedural learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +public class RivestSchapireAdapterMealy extends RivestSchapireMealy implements AccessSequenceTransformer { - public RivestSchapireMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + public RivestSchapireAdapterMealy(Alphabet alphabet, MembershipOracle> oracle) { super(alphabet, oracle); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/TTTMealyAdapter.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/TTTAdapterMealy.java similarity index 89% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/TTTMealyAdapter.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/TTTAdapterMealy.java index 16081d1ce9..a031080621 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/adapter/TTTMealyAdapter.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/TTTAdapterMealy.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm.adapter; +package de.learnlib.algorithms.procedural.adapter.mealy; import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.ttt.base.TTTState; @@ -33,9 +33,9 @@ * * @author frohme */ -public class TTTMealyAdapter extends TTTLearnerMealy implements AccessSequenceTransformer { +public class TTTAdapterMealy extends TTTLearnerMealy implements AccessSequenceTransformer { - public TTTMealyAdapter(Alphabet alphabet, MembershipOracle> oracle) { + public TTTAdapterMealy(Alphabet alphabet, MembershipOracle> oracle) { super(alphabet, oracle, AcexAnalyzers.BINARY_SEARCH_BWD); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java similarity index 93% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ATManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java index f1c692e3cd..eec8b1e29e 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba; +package de.learnlib.algorithms.procedural.sba; import java.util.Collection; import java.util.Map; import java.util.Set; +import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; import net.automatalib.commons.util.Pair; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappingSBA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java similarity index 97% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappingSBA.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java index 24bf5c99a6..535a4356d6 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/MappingSBA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba; +package de.learnlib.algorithms.procedural.sba; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; import com.google.common.collect.Maps; +import de.learnlib.algorithms.procedural.SymbolWrapper; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.sba.SBA; import net.automatalib.commons.util.mappings.Mapping; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java similarity index 90% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ProceduralMembershipOracle.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java index 126637b421..840e1c89ef 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java @@ -13,30 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba; +package de.learnlib.algorithms.procedural.sba; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; +import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import net.automatalib.words.SPAAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; -public class ProceduralMembershipOracle implements MembershipOracle, Boolean> { +final class ProceduralMembershipOracle implements MembershipOracle, Boolean> { private final SPAAlphabet alphabet; private final MembershipOracle delegate; private final I procedure; private final ATManager atManager; - public ProceduralMembershipOracle(SPAAlphabet alphabet, - MembershipOracle delegate, - I procedure, - ATManager atManager) { + ProceduralMembershipOracle(SPAAlphabet alphabet, + MembershipOracle delegate, + I procedure, + ATManager atManager) { this.alphabet = alphabet; this.delegate = delegate; this.procedure = procedure; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java similarity index 98% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java index aabbdc85af..9930152f6f 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/SBALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba; +package de.learnlib.algorithms.procedural.sba; import java.util.Collection; import java.util.Collections; @@ -22,7 +22,9 @@ import java.util.Set; import com.google.common.collect.Maps; -import de.learnlib.algorithms.sba.manager.OptimizingATManager; +import de.learnlib.algorithms.procedural.AlphabetMapper; +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.sba.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.algorithm.LearnerConstructor; import de.learnlib.api.algorithm.LearningAlgorithm; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java similarity index 95% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/DefaultATManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java index 55993e8e58..b2022f7abd 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba.manager; +package de.learnlib.algorithms.procedural.sba.manager; import java.util.Collection; import java.util.Collections; @@ -22,8 +22,8 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import de.learnlib.algorithms.sba.ATManager; -import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.sba.ATManager; import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; import net.automatalib.commons.util.Pair; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java similarity index 91% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/OptimizingATManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java index 3a0c0c8b6c..24f23ef888 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/sba/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba.manager; +package de.learnlib.algorithms.procedural.sba.manager; import java.util.ArrayList; import java.util.Collection; @@ -25,8 +25,8 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import de.learnlib.algorithms.sba.ATManager; -import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.sba.ATManager; import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; import net.automatalib.commons.util.Pair; @@ -35,6 +35,7 @@ import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; +import org.checkerframework.checker.nullness.qual.Nullable; public class OptimizingATManager implements ATManager { @@ -121,10 +122,10 @@ public Set scanRefinedProcedures(Map>> p return newTS; } - private Word getShortestHypothesisTS(DFA> hyp, - AccessSequenceTransformer> asTransformer, - Collection> inputs, - SymbolWrapper returnSymbol) { + private @Nullable Word getShortestHypothesisTS(DFA> hyp, + AccessSequenceTransformer> asTransformer, + Collection> inputs, + SymbolWrapper returnSymbol) { final Iterator>> iter = Covers.stateCoverIterator(hyp, inputs); Word result = null; @@ -202,8 +203,12 @@ private void extractPotentialAccessSequences(Word input, Set newCalls) { // update asBuilder final int callIdx = alphabet.findCallIndex(asBuilder, asBuilder.size() - 1); final I procedure = asBuilder.get(callIdx); + final Word ts = terminatingSequences.get(procedure); + + assert ts != null; + asBuilder.subList(callIdx + 1, asBuilder.size()).clear(); - asBuilder.addAll(terminatingSequences.get(procedure).asList()); + asBuilder.addAll(ts.asList()); asBuilder.add(alphabet.getReturnSymbol()); } } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/ATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java similarity index 96% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/ATRManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java index ea55eb406a..90d0caf199 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/ATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa; +package de.learnlib.algorithms.procedural.spa; import java.util.Collection; import java.util.Map; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java similarity index 98% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/ProceduralMembershipOracle.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java index f83bf46dbb..86cb4a074a 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa; +package de.learnlib.algorithms.procedural.spa; import java.util.ArrayList; import java.util.Collection; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/SPALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java similarity index 99% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/SPALearner.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java index e5fa2f7e34..eb0ef623ce 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/SPALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa; +package de.learnlib.algorithms.procedural.spa; import java.util.ArrayDeque; import java.util.ArrayList; @@ -26,7 +26,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import de.learnlib.algorithms.spa.manager.OptimizingATRManager; +import de.learnlib.algorithms.procedural.spa.manager.OptimizingATRManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.algorithm.LearnerConstructor; import de.learnlib.api.algorithm.LearningAlgorithm; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/manager/DefaultATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java similarity index 96% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/manager/DefaultATRManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java index 31a8b010fd..c92c69c694 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/manager/DefaultATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa.manager; +package de.learnlib.algorithms.procedural.spa.manager; import java.util.Collection; import java.util.Map; @@ -21,7 +21,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import de.learnlib.algorithms.spa.ATRManager; +import de.learnlib.algorithms.procedural.spa.ATRManager; import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; import net.automatalib.words.SPAAlphabet; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/manager/OptimizingATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java similarity index 95% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/manager/OptimizingATRManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java index 82ff321d10..50c3190020 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spa/manager/OptimizingATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa.manager; +package de.learnlib.algorithms.procedural.spa.manager; import java.util.ArrayList; import java.util.Collection; @@ -25,13 +25,14 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.collect.Streams; -import de.learnlib.algorithms.spa.ATRManager; +import de.learnlib.algorithms.procedural.spa.ATRManager; import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; import net.automatalib.util.automata.cover.Covers; import net.automatalib.words.SPAAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; +import org.checkerframework.checker.nullness.qual.Nullable; public class OptimizingATRManager implements ATRManager { @@ -112,9 +113,9 @@ public void scanRefinedProcedures(Map> procedures, } } - private Word getShortestHypothesisTS(DFA hyp, - AccessSequenceTransformer asTransformer, - Collection inputs) { + private @Nullable Word getShortestHypothesisTS(DFA hyp, + AccessSequenceTransformer asTransformer, + Collection inputs) { return Streams.stream(Covers.stateCoverIterator(hyp, inputs)) .filter(hyp::accepts) .map(asTransformer::transformAccessSequence) diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java similarity index 93% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ATManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java index 1c77af1836..2d6beec2ee 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm; +package de.learnlib.algorithms.procedural.spmm; import java.util.Collection; import java.util.Map; import java.util.Set; -import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.transducers.MealyMachine; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappingSPMM.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java similarity index 97% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappingSPMM.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java index 944ef79441..9343930dd4 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/MappingSPMM.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm; +package de.learnlib.algorithms.procedural.spmm; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; import com.google.common.collect.Maps; -import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.procedural.SymbolWrapper; import net.automatalib.automata.spmm.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.mappings.Mapping; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java similarity index 91% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ProceduralMembershipOracle.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java index e50e93000a..1b63d24bcd 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm; +package de.learnlib.algorithms.procedural.spmm; import java.util.ArrayList; import java.util.BitSet; @@ -22,14 +22,14 @@ import java.util.List; import java.util.stream.Collectors; -import de.learnlib.algorithms.sba.SymbolWrapper; +import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; import net.automatalib.words.SPAAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; -public class ProceduralMembershipOracle implements MembershipOracle, Word> { +final class ProceduralMembershipOracle implements MembershipOracle, Word> { private final SPAAlphabet alphabet; private final MembershipOracle> delegate; @@ -37,11 +37,11 @@ public class ProceduralMembershipOracle implements MembershipOracle atManager; - public ProceduralMembershipOracle(SPAAlphabet alphabet, - MembershipOracle> delegate, - I procedure, - O errorSymbol, - ATManager atManager) { + ProceduralMembershipOracle(SPAAlphabet alphabet, + MembershipOracle> delegate, + I procedure, + O errorSymbol, + ATManager atManager) { this.alphabet = alphabet; this.delegate = delegate; this.procedure = procedure; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java similarity index 98% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java index 818c9b608c..ce7c6811d0 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/SPMMLearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm; +package de.learnlib.algorithms.procedural.spmm; import java.util.Collection; import java.util.Collections; @@ -24,9 +24,9 @@ import java.util.Set; import com.google.common.collect.Maps; -import de.learnlib.algorithms.sba.AlphabetMapper; -import de.learnlib.algorithms.sba.SymbolWrapper; -import de.learnlib.algorithms.spmm.manager.OptimizingATManager; +import de.learnlib.algorithms.procedural.AlphabetMapper; +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.spmm.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.algorithm.LearnerConstructor; import de.learnlib.api.algorithm.LearningAlgorithm; diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java similarity index 92% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/DefaultATManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java index a53fcc030c..2f839c5905 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm.manager; +package de.learnlib.algorithms.procedural.spmm.manager; import java.util.Collection; import java.util.Collections; @@ -22,8 +22,8 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import de.learnlib.algorithms.sba.SymbolWrapper; -import de.learnlib.algorithms.spmm.ATManager; +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.spmm.ATManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.transducers.MealyMachine; @@ -50,11 +50,13 @@ public DefaultATManager(final SPAAlphabet inputAlphabet, final SPAOutputAlpha @Override public Word getAccessSequence(I procedure) { + assert this.accessSequences.containsKey(procedure); return this.accessSequences.get(procedure); } @Override public Word getTerminatingSequence(I procedure) { + assert this.terminatingSequences.containsKey(procedure); return this.terminatingSequences.get(procedure); } diff --git a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java similarity index 95% rename from algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/OptimizingATManager.java rename to algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java index d56ef98ed7..3021e5e20e 100644 --- a/algorithms/active/spa/src/main/java/de/learnlib/algorithms/spmm/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm.manager; +package de.learnlib.algorithms.procedural.spmm.manager; import java.util.ArrayList; import java.util.Collection; @@ -26,8 +26,8 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import de.learnlib.algorithms.sba.SymbolWrapper; -import de.learnlib.algorithms.spmm.ATManager; +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.spmm.ATManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.transducers.MealyMachine; @@ -58,11 +58,13 @@ public OptimizingATManager(final SPAAlphabet inputAlphabet, SPAOutputAlphabet @Override public Word getAccessSequence(I procedure) { + assert this.accessSequences.containsKey(procedure); return this.accessSequences.get(procedure); } @Override public Word getTerminatingSequence(I procedure) { + assert this.terminatingSequences.containsKey(procedure); return this.terminatingSequences.get(procedure); } @@ -217,8 +219,12 @@ private void extractPotentialAccessSequences(final DefaultQuery> coun // update asBuilder final int callIdx = inputAlphabet.findCallIndex(asBuilder, asBuilder.size() - 1); final I procedure = asBuilder.get(callIdx); + final Word ts = terminatingSequences.get(procedure); + + assert ts != null; + asBuilder.subList(callIdx + 1, asBuilder.size()).clear(); - asBuilder.addAll(terminatingSequences.get(procedure).asList()); + asBuilder.addAll(ts.asList()); asBuilder.add(inputAlphabet.getReturnSymbol()); } } diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/ATManagerTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/ATManagerTest.java similarity index 92% rename from algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/ATManagerTest.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/ATManagerTest.java index 3f151fbc88..284aa05418 100644 --- a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/ATManagerTest.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/ATManagerTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba; +package de.learnlib.algorithms.procedural.sba; -import de.learnlib.algorithms.sba.manager.DefaultATManager; -import de.learnlib.algorithms.sba.manager.OptimizingATManager; +import de.learnlib.algorithms.procedural.sba.manager.DefaultATManager; +import de.learnlib.algorithms.procedural.sba.manager.OptimizingATManager; import net.automatalib.words.Alphabet; import net.automatalib.words.SPAAlphabet; import net.automatalib.words.Word; diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/SBAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java similarity index 75% rename from algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/SBAIT.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java index 673f879e71..a86c63f9d2 100644 --- a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/sba/SBAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java @@ -13,19 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.sba; +package de.learnlib.algorithms.procedural.sba; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import de.learnlib.algorithms.sba.manager.DefaultATManager; -import de.learnlib.algorithms.sba.manager.OptimizingATManager; -import de.learnlib.algorithms.spa.adapter.DiscriminationTreeAdapter; -import de.learnlib.algorithms.spa.adapter.KearnsVaziraniAdapter; -import de.learnlib.algorithms.spa.adapter.LStarBaseAdapter; -import de.learnlib.algorithms.spa.adapter.RivestSchapireAdapter; -import de.learnlib.algorithms.spa.adapter.TTTAdapter; +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.adapter.dfa.DiscriminationTreeAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.KearnsVaziraniAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.LStarBaseAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.RivestSchapireAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.TTTAdapterDFA; +import de.learnlib.algorithms.procedural.sba.manager.DefaultATManager; +import de.learnlib.algorithms.procedural.sba.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.algorithm.LearnerConstructor; import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; @@ -44,11 +45,11 @@ protected void addLearnerVariants(SPAAlphabet alphabet, final Builder builder = new Builder<>(alphabet, mqOracle, variants); - builder.addLearnerVariant(DiscriminationTreeAdapter::new); - builder.addLearnerVariant(KearnsVaziraniAdapter::new); - builder.addLearnerVariant(LStarBaseAdapter::new); - builder.addLearnerVariant(RivestSchapireAdapter::new); - builder.addLearnerVariant(TTTAdapter::new); + builder.addLearnerVariant(DiscriminationTreeAdapterDFA::new); + builder.addLearnerVariant(KearnsVaziraniAdapterDFA::new); + builder.addLearnerVariant(LStarBaseAdapterDFA::new); + builder.addLearnerVariant(RivestSchapireAdapterDFA::new); + builder.addLearnerVariant(TTTAdapterDFA::new); } private static class Builder { diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/ATRManagerTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/ATRManagerTest.java similarity index 93% rename from algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/ATRManagerTest.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/ATRManagerTest.java index 1542ad0618..6cc013d0b6 100644 --- a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/ATRManagerTest.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/ATRManagerTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa; +package de.learnlib.algorithms.procedural.spa; -import de.learnlib.algorithms.spa.manager.DefaultATRManager; -import de.learnlib.algorithms.spa.manager.OptimizingATRManager; +import de.learnlib.algorithms.procedural.spa.manager.DefaultATRManager; +import de.learnlib.algorithms.procedural.spa.manager.OptimizingATRManager; import net.automatalib.words.Alphabet; import net.automatalib.words.SPAAlphabet; import net.automatalib.words.Word; diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/SPAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java similarity index 75% rename from algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/SPAIT.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java index d6f3c91f72..0cd6e39496 100644 --- a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spa/SPAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java @@ -13,19 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spa; +package de.learnlib.algorithms.procedural.spa; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import de.learnlib.algorithms.spa.adapter.DiscriminationTreeAdapter; -import de.learnlib.algorithms.spa.adapter.KearnsVaziraniAdapter; -import de.learnlib.algorithms.spa.adapter.LStarBaseAdapter; -import de.learnlib.algorithms.spa.adapter.RivestSchapireAdapter; -import de.learnlib.algorithms.spa.adapter.TTTAdapter; -import de.learnlib.algorithms.spa.manager.DefaultATRManager; -import de.learnlib.algorithms.spa.manager.OptimizingATRManager; +import de.learnlib.algorithms.procedural.adapter.dfa.DiscriminationTreeAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.KearnsVaziraniAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.LStarBaseAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.RivestSchapireAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.TTTAdapterDFA; +import de.learnlib.algorithms.procedural.spa.manager.DefaultATRManager; +import de.learnlib.algorithms.procedural.spa.manager.OptimizingATRManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.algorithm.LearnerConstructor; import de.learnlib.api.algorithm.LearningAlgorithm.DFALearner; @@ -44,11 +44,11 @@ protected void addLearnerVariants(SPAAlphabet alphabet, final Builder builder = new Builder<>(alphabet, mqOracle, variants); - builder.addLearnerVariant(DiscriminationTreeAdapter::new); - builder.addLearnerVariant(KearnsVaziraniAdapter::new); - builder.addLearnerVariant(LStarBaseAdapter::new); - builder.addLearnerVariant(RivestSchapireAdapter::new); - builder.addLearnerVariant(TTTAdapter::new); + builder.addLearnerVariant(DiscriminationTreeAdapterDFA::new); + builder.addLearnerVariant(KearnsVaziraniAdapterDFA::new); + builder.addLearnerVariant(LStarBaseAdapterDFA::new); + builder.addLearnerVariant(RivestSchapireAdapterDFA::new); + builder.addLearnerVariant(TTTAdapterDFA::new); } private static class Builder { diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/ATManagerTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java similarity index 93% rename from algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/ATManagerTest.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java index 4e9e4e5d41..0d36ff80df 100644 --- a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/ATManagerTest.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm; +package de.learnlib.algorithms.procedural.spmm; -import de.learnlib.algorithms.spmm.manager.DefaultATManager; -import de.learnlib.algorithms.spmm.manager.OptimizingATManager; +import de.learnlib.algorithms.procedural.spmm.manager.DefaultATManager; +import de.learnlib.algorithms.procedural.spmm.manager.OptimizingATManager; import de.learnlib.api.query.DefaultQuery; import net.automatalib.words.Alphabet; import net.automatalib.words.SPAAlphabet; diff --git a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/SPMMIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java similarity index 79% rename from algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/SPMMIT.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java index ea51bbceca..c0f929901e 100644 --- a/algorithms/active/spa/src/test/java/de/learnlib/algorithms/spmm/SPMMIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java @@ -13,20 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.spmm; +package de.learnlib.algorithms.procedural.spmm; import java.util.Arrays; import java.util.List; import java.util.function.BiFunction; -import de.learnlib.algorithms.sba.SymbolWrapper; -import de.learnlib.algorithms.spmm.adapter.DiscriminationTreeMealyAdapter; -import de.learnlib.algorithms.spmm.adapter.KearnsVaziraniMealyAdapter; -import de.learnlib.algorithms.spmm.adapter.LStarBaseMealyAdapter; -import de.learnlib.algorithms.spmm.adapter.RivestSchapireMealyAdapter; -import de.learnlib.algorithms.spmm.adapter.TTTMealyAdapter; -import de.learnlib.algorithms.spmm.manager.DefaultATManager; -import de.learnlib.algorithms.spmm.manager.OptimizingATManager; +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.adapter.mealy.DiscriminationTreeAdapterMealy; +import de.learnlib.algorithms.procedural.adapter.mealy.KearnsVaziraniAdapterMealy; +import de.learnlib.algorithms.procedural.adapter.mealy.LStarBaseAdapterMealy; +import de.learnlib.algorithms.procedural.adapter.mealy.RivestSchapireAdapterMealy; +import de.learnlib.algorithms.procedural.adapter.mealy.TTTAdapterMealy; +import de.learnlib.algorithms.procedural.spmm.manager.DefaultATManager; +import de.learnlib.algorithms.procedural.spmm.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.algorithm.LearnerConstructor; import de.learnlib.api.algorithm.LearningAlgorithm.MealyLearner; @@ -48,11 +48,11 @@ protected void addLearnerVariants(SPAAlphabet alphabet, final Builder builder = new Builder<>(alphabet, outputAlphabet, mqOracle, variants); - builder.addLearnerVariant(DiscriminationTreeMealyAdapter::new); - builder.addLearnerVariant(KearnsVaziraniMealyAdapter::new); - builder.addLearnerVariant(LStarBaseMealyAdapter::new); - builder.addLearnerVariant(RivestSchapireMealyAdapter::new); - builder.addLearnerVariant(TTTMealyAdapter::new); + builder.addLearnerVariant(DiscriminationTreeAdapterMealy::new); + builder.addLearnerVariant(KearnsVaziraniAdapterMealy::new); + builder.addLearnerVariant(LStarBaseAdapterMealy::new); + builder.addLearnerVariant(RivestSchapireAdapterMealy::new); + builder.addLearnerVariant(TTTAdapterMealy::new); } private static class Builder { diff --git a/distribution/pom.xml b/distribution/pom.xml index ef968fb1eb..6358afc164 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -94,7 +94,7 @@ limitations under the License. de.learnlib - learnlib-spa + learnlib-procedural @@ -351,7 +351,7 @@ limitations under the License. de.learnlib - learnlib-spa + learnlib-procedural ${project.version} sources diff --git a/pom.xml b/pom.xml index 034d069cd7..3891dfd7a2 100644 --- a/pom.xml +++ b/pom.xml @@ -325,7 +325,7 @@ limitations under the License. de.learnlib - learnlib-spa + learnlib-procedural ${project.version} From 6dab2c50d8a4424082d0fde47f015df68b3cbcc9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 14 Jul 2023 14:57:35 +0200 Subject: [PATCH 04/15] adjust to Automatalib refactorings --- .../algorithms/procedural/AlphabetMapper.java | 6 ++-- .../algorithms/procedural/sba/MappingSBA.java | 10 +++--- .../sba/ProceduralMembershipOracle.java | 6 ++-- .../algorithms/procedural/sba/SBALearner.java | 22 ++++++------- .../sba/manager/DefaultATManager.java | 6 ++-- .../sba/manager/OptimizingATManager.java | 6 ++-- .../spa/ProceduralMembershipOracle.java | 12 +++---- .../algorithms/procedural/spa/SPALearner.java | 16 +++++----- .../spa/manager/DefaultATRManager.java | 6 ++-- .../spa/manager/OptimizingATRManager.java | 6 ++-- .../procedural/spmm/MappingSPMM.java | 18 +++++------ .../spmm/ProceduralMembershipOracle.java | 6 ++-- .../procedural/spmm/SPMMLearner.java | 32 +++++++++---------- .../spmm/manager/DefaultATManager.java | 10 +++--- .../spmm/manager/OptimizingATManager.java | 10 +++--- .../procedural/sba/ATManagerTest.java | 8 ++--- .../algorithms/procedural/sba/SBAIT.java | 12 +++---- .../procedural/spa/ATRManagerTest.java | 8 ++--- .../algorithms/procedural/spa/SPAIT.java | 12 +++---- .../procedural/spmm/ATManagerTest.java | 16 +++++----- .../algorithms/procedural/spmm/SPMMIT.java | 20 ++++++------ .../equivalence/sba/SimulatorEQOracle.java | 8 ++--- .../equivalence/spa/SimulatorEQOracle.java | 8 ++--- .../equivalence/spa/WMethodSPAEQOracle.java | 8 ++--- .../equivalence/spa/WpMethodSPAEQOracle.java | 8 ++--- .../equivalence/spmm/SimulatorEQOracle.java | 8 ++--- .../spa/WMethodSPAEQOracleTest.java | 10 +++--- .../spa/WpMethodSPAEQOracleTest.java | 10 +++--- .../it/learner/AbstractSBALearnerIT.java | 6 ++-- .../it/learner/AbstractSPALearnerIT.java | 6 ++-- .../it/learner/AbstractSPMMLearnerIT.java | 8 ++--- .../testsupport/it/learner/LearnerITUtil.java | 6 ++-- .../it/learner/LearnerVariantList.java | 6 ++-- .../it/learner/LearnerVariantListImpl.java | 6 ++-- .../it/learner/SBALearnerITCase.java | 2 +- .../it/learner/SPALearnerITCase.java | 2 +- .../it/learner/SPMMLearnerITCase.java | 2 +- .../examples/DefaultLearningExample.java | 18 +++++------ .../de/learnlib/examples/LearningExample.java | 18 +++++------ .../learnlib/examples/LearningExamples.java | 16 +++++----- .../examples/sba/ExampleRandomSBA.java | 8 ++--- .../examples/spa/ExamplePalindrome.java | 14 ++++---- .../examples/spa/ExampleRandomSPA.java | 8 ++--- .../examples/spmm/ExampleRandomSPMM.java | 10 +++--- 44 files changed, 222 insertions(+), 222 deletions(-) diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java index a053649f06..b4b8f02c04 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java @@ -19,15 +19,15 @@ import java.util.Collection; import net.automatalib.commons.util.mappings.Mapping; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; public class AlphabetMapper implements Mapping> { - private final SPAAlphabet source; + private final ProceduralInputAlphabet source; private final SymbolWrapper[] target; @SuppressWarnings("unchecked") - public AlphabetMapper(SPAAlphabet source) { + public AlphabetMapper(ProceduralInputAlphabet source) { this.source = source; this.target = new SymbolWrapper[source.size()]; } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java index 535a4356d6..d7d10f0ece 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java @@ -22,10 +22,10 @@ import com.google.common.collect.Maps; import de.learnlib.algorithms.procedural.SymbolWrapper; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.sba.SBA; +import net.automatalib.automata.procedural.SBA; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.ts.simple.SimpleDTS; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -40,13 +40,13 @@ */ class MappingSBA implements SBA, SimpleDTS { - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; private final Mapping> mapping; private final SBA> delegate; private final Map> procedures; - MappingSBA(SPAAlphabet alphabet, Mapping> mapping, SBA> delegate) { + MappingSBA(ProceduralInputAlphabet alphabet, Mapping> mapping, SBA> delegate) { this.alphabet = alphabet; this.mapping = mapping; this.delegate = delegate; @@ -81,7 +81,7 @@ public S getInitialState() { } @Override - public SPAAlphabet getInputAlphabet() { + public ProceduralInputAlphabet getInputAlphabet() { return this.alphabet; } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java index 840e1c89ef..0d5e48547d 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java @@ -23,18 +23,18 @@ import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; final class ProceduralMembershipOracle implements MembershipOracle, Boolean> { - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; private final MembershipOracle delegate; private final I procedure; private final ATManager atManager; - ProceduralMembershipOracle(SPAAlphabet alphabet, + ProceduralMembershipOracle(ProceduralInputAlphabet alphabet, MembershipOracle delegate, I procedure, ATManager atManager) { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java index 9930152f6f..528257b926 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java @@ -34,25 +34,25 @@ import de.learnlib.util.MQUtil; import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.sba.EmptySBA; -import net.automatalib.automata.sba.SBA; -import net.automatalib.automata.sba.StackSBA; +import net.automatalib.automata.procedural.EmptySBA; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.automata.procedural.StackSBA; import net.automatalib.commons.util.Pair; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.util.automata.Automata; -import net.automatalib.util.automata.sba.SBAUtil; +import net.automatalib.util.automata.procedural.SBAUtil; import net.automatalib.words.Alphabet; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; -import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; import net.automatalib.words.impl.GrowingMapAlphabet; public class SBALearner> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> implements LearningAlgorithm, I, Boolean> { - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; private final MembershipOracle oracle; private final Mapping, Boolean>> learnerConstructors; private final ATManager atManager; @@ -62,13 +62,13 @@ public class SBALearner> & SupportsGrow private final AlphabetMapper mapper; - public SBALearner(final SPAAlphabet alphabet, + public SBALearner(final ProceduralInputAlphabet alphabet, final MembershipOracle oracle, final LearnerConstructor, Boolean> learnerConstructor) { this(alphabet, oracle, (i) -> learnerConstructor, new OptimizingATManager<>(alphabet)); } - public SBALearner(final SPAAlphabet alphabet, + public SBALearner(final ProceduralInputAlphabet alphabet, final MembershipOracle oracle, final Mapping, Boolean>> learnerConstructors, final ATManager atManager) { @@ -166,8 +166,8 @@ public SBA getHypothesisModel() { } } - final SPAAlphabet> mappedAlphabet = - new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, this.mapper.get(alphabet.getReturnSymbol())); + final ProceduralInputAlphabet> mappedAlphabet = + new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, this.mapper.get(alphabet.getReturnSymbol())); final StackSBA> delegate = new StackSBA<>(mappedAlphabet, this.mapper.get(initialCallSymbol), mappedProcedures); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java index b2022f7abd..a4048791fd 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java @@ -27,7 +27,7 @@ import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; import net.automatalib.commons.util.Pair; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; public class DefaultATManager implements ATManager { @@ -35,9 +35,9 @@ public class DefaultATManager implements ATManager { private final Map> accessSequences; private final Map> terminatingSequences; - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; - public DefaultATManager(final SPAAlphabet alphabet) { + public DefaultATManager(final ProceduralInputAlphabet alphabet) { this.alphabet = alphabet; this.accessSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java index 24f23ef888..b27d00dc31 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java @@ -31,7 +31,7 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.commons.util.Pair; import net.automatalib.util.automata.cover.Covers; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; @@ -42,9 +42,9 @@ public class OptimizingATManager implements ATManager { private final Map> accessSequences; private final Map> terminatingSequences; - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; - public OptimizingATManager(final SPAAlphabet alphabet) { + public OptimizingATManager(final ProceduralInputAlphabet alphabet) { this.alphabet = alphabet; this.accessSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java index 86cb4a074a..5c27c6c553 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java @@ -21,21 +21,21 @@ import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; final class ProceduralMembershipOracle implements MembershipOracle { - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; private final MembershipOracle delegate; private final I procedure; private final ATRManager atrManager; - ProceduralMembershipOracle(SPAAlphabet alphabet, - MembershipOracle delegate, - I procedure, - ATRManager atrManager) { + ProceduralMembershipOracle(ProceduralInputAlphabet alphabet, + MembershipOracle delegate, + I procedure, + ATRManager atrManager) { this.alphabet = alphabet; this.delegate = delegate; this.procedure = procedure; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java index eb0ef623ce..ca789b30d1 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java @@ -36,11 +36,11 @@ import de.learnlib.util.MQUtil; import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.spa.EmptySPA; -import net.automatalib.automata.spa.SPA; -import net.automatalib.automata.spa.StackSPA; +import net.automatalib.automata.procedural.EmptySPA; +import net.automatalib.automata.procedural.SPA; +import net.automatalib.automata.procedural.StackSPA; import net.automatalib.commons.util.mappings.Mapping; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import net.automatalib.words.impl.GrowingMapAlphabet; @@ -59,7 +59,7 @@ public class SPALearner & SupportsGrowingAlphabet & AccessSequenceTransformer> implements LearningAlgorithm, I, Boolean> { - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; private final MembershipOracle oracle; private final Mapping> learnerConstructors; private final ATRManager atrManager; @@ -68,19 +68,19 @@ public class SPALearner & SupportsGrowingAlphabet private final Set activeAlphabet; private I initialCallSymbol; - public SPALearner(SPAAlphabet alphabet, + public SPALearner(ProceduralInputAlphabet alphabet, MembershipOracle oracle, LearnerConstructor learnerConstructor) { this(alphabet, oracle, (i) -> learnerConstructor); } - public SPALearner(SPAAlphabet alphabet, + public SPALearner(ProceduralInputAlphabet alphabet, MembershipOracle oracle, Mapping> learnerConstructors) { this(alphabet, oracle, learnerConstructors, new OptimizingATRManager<>(alphabet)); } - public SPALearner(SPAAlphabet alphabet, + public SPALearner(ProceduralInputAlphabet alphabet, MembershipOracle oracle, Mapping> learnerConstructors, ATRManager atrManager) { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java index c92c69c694..5284bfa229 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java @@ -24,7 +24,7 @@ import de.learnlib.algorithms.procedural.spa.ATRManager; import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; public class DefaultATRManager implements ATRManager { @@ -33,9 +33,9 @@ public class DefaultATRManager implements ATRManager { private final Map> returnSequences; private final Map> terminatingSequences; - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; - public DefaultATRManager(SPAAlphabet alphabet) { + public DefaultATRManager(ProceduralInputAlphabet alphabet) { this.alphabet = alphabet; this.accessSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java index 50c3190020..8ec8bc4bca 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java @@ -29,7 +29,7 @@ import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; import net.automatalib.util.automata.cover.Covers; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import org.checkerframework.checker.nullness.qual.Nullable; @@ -40,9 +40,9 @@ public class OptimizingATRManager implements ATRManager { private final Map> returnSequences; private final Map> terminatingSequences; - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; - public OptimizingATRManager(SPAAlphabet alphabet) { + public OptimizingATRManager(ProceduralInputAlphabet alphabet) { this.alphabet = alphabet; this.accessSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java index 9343930dd4..68c9291b77 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java @@ -21,11 +21,11 @@ import com.google.common.collect.Maps; import de.learnlib.algorithms.procedural.SymbolWrapper; -import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.procedural.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.mappings.Mapping; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -40,15 +40,15 @@ */ class MappingSPMM implements SPMM { - private final SPAAlphabet inputAlphabet; - private final SPAOutputAlphabet outputAlphabet; + private final ProceduralInputAlphabet inputAlphabet; + private final ProceduralOutputAlphabet outputAlphabet; private final Mapping> mapping; private final SPMM, T, O> delegate; private final Map> procedures; - MappingSPMM(SPAAlphabet inputAlphabet, - SPAOutputAlphabet outputAlphabet, + MappingSPMM(ProceduralInputAlphabet inputAlphabet, + ProceduralOutputAlphabet outputAlphabet, Mapping> mapping, SPMM, T, O> delegate) { this.inputAlphabet = inputAlphabet; @@ -81,12 +81,12 @@ public S getInitialState() { } @Override - public SPAAlphabet getInputAlphabet() { + public ProceduralInputAlphabet getInputAlphabet() { return this.inputAlphabet; } @Override - public SPAOutputAlphabet getOutputAlphabet() { + public ProceduralOutputAlphabet getOutputAlphabet() { return this.outputAlphabet; } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java index 1b63d24bcd..8233e66823 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java @@ -25,19 +25,19 @@ import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.api.query.Query; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; final class ProceduralMembershipOracle implements MembershipOracle, Word> { - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; private final MembershipOracle> delegate; private final I procedure; private final O errorSymbol; private final ATManager atManager; - ProceduralMembershipOracle(SPAAlphabet alphabet, + ProceduralMembershipOracle(ProceduralInputAlphabet alphabet, MembershipOracle> delegate, I procedure, O errorSymbol, diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java index ce7c6811d0..ff75b84c1d 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java @@ -35,28 +35,28 @@ import de.learnlib.api.query.DefaultQuery; import de.learnlib.util.MQUtil; import net.automatalib.SupportsGrowingAlphabet; -import net.automatalib.automata.spmm.EmptySPMM; -import net.automatalib.automata.spmm.SPMM; -import net.automatalib.automata.spmm.StackSPMM; +import net.automatalib.automata.procedural.EmptySPMM; +import net.automatalib.automata.procedural.SPMM; +import net.automatalib.automata.procedural.StackSPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.util.automata.Automata; -import net.automatalib.util.automata.spmm.SPMMUtil; +import net.automatalib.util.automata.procedural.SPMMUtil; import net.automatalib.words.Alphabet; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; -import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; import net.automatalib.words.impl.GrowingMapAlphabet; public class SPMMLearner, O> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> implements LearningAlgorithm, I, Word> { - private final SPAAlphabet inputAlphabet; - private final SPAOutputAlphabet outputAlphabet; + private final ProceduralInputAlphabet inputAlphabet; + private final ProceduralOutputAlphabet outputAlphabet; private final MembershipOracle> oracle; private final Mapping, Word>> learnerConstructors; private final ATManager atManager; @@ -67,8 +67,8 @@ public class SPMMLearner, O> & Sup private final AlphabetMapper mapper; - public SPMMLearner(SPAAlphabet inputAlphabet, - SPAOutputAlphabet outputAlphabet, + public SPMMLearner(ProceduralInputAlphabet inputAlphabet, + ProceduralOutputAlphabet outputAlphabet, MembershipOracle> oracle, LearnerConstructor, Word> learnerConstructor) { this(inputAlphabet, @@ -78,8 +78,8 @@ public SPMMLearner(SPAAlphabet inputAlphabet, new OptimizingATManager<>(inputAlphabet, outputAlphabet)); } - public SPMMLearner(SPAAlphabet inputAlphabet, - SPAOutputAlphabet outputAlphabet, + public SPMMLearner(ProceduralInputAlphabet inputAlphabet, + ProceduralOutputAlphabet outputAlphabet, MembershipOracle> oracle, Mapping, Word>> learnerConstructors, ATManager atManager) { @@ -185,9 +185,9 @@ private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) } } - final SPAAlphabet> mappedAlphabet = new DefaultSPAAlphabet<>(internalAlphabet, - callAlphabet, - this.mapper.get(inputAlphabet.getReturnSymbol())); + final ProceduralInputAlphabet> mappedAlphabet = new DefaultProceduralInputAlphabet<>(internalAlphabet, + callAlphabet, + this.mapper.get(inputAlphabet.getReturnSymbol())); final StackSPMM, ?, O> delegate = new StackSPMM<>(mappedAlphabet, outputAlphabet, diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java index 2f839c5905..717806158a 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java @@ -28,8 +28,8 @@ import de.learnlib.api.query.DefaultQuery; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; public class DefaultATManager implements ATManager { @@ -37,10 +37,10 @@ public class DefaultATManager implements ATManager { private final Map> accessSequences; private final Map> terminatingSequences; - private final SPAAlphabet inputAlphabet; - private final SPAOutputAlphabet outputAlphabet; + private final ProceduralInputAlphabet inputAlphabet; + private final ProceduralOutputAlphabet outputAlphabet; - public DefaultATManager(final SPAAlphabet inputAlphabet, final SPAOutputAlphabet outputAlphabet) { + public DefaultATManager(final ProceduralInputAlphabet inputAlphabet, final ProceduralOutputAlphabet outputAlphabet) { this.inputAlphabet = inputAlphabet; this.outputAlphabet = outputAlphabet; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java index 3021e5e20e..68d188e579 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java @@ -33,8 +33,8 @@ import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; import net.automatalib.util.automata.cover.Covers; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; @@ -45,10 +45,10 @@ public class OptimizingATManager implements ATManager { private final Map> accessSequences; private final Map> terminatingSequences; - private final SPAAlphabet inputAlphabet; - private final SPAOutputAlphabet outputAlphabet; + private final ProceduralInputAlphabet inputAlphabet; + private final ProceduralOutputAlphabet outputAlphabet; - public OptimizingATManager(final SPAAlphabet inputAlphabet, SPAOutputAlphabet outputAlphabet) { + public OptimizingATManager(final ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet) { this.inputAlphabet = inputAlphabet; this.outputAlphabet = outputAlphabet; diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/ATManagerTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/ATManagerTest.java index 284aa05418..8148bc4a07 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/ATManagerTest.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/ATManagerTest.java @@ -18,24 +18,24 @@ import de.learnlib.algorithms.procedural.sba.manager.DefaultATManager; import de.learnlib.algorithms.procedural.sba.manager.OptimizingATManager; import net.automatalib.words.Alphabet; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class ATManagerTest { - private static final SPAAlphabet ALPHABET; + private static final ProceduralInputAlphabet ALPHABET; static { final Alphabet callAlphabet = Alphabets.characters('A', 'C'); final Alphabet internalAlphabet = Alphabets.characters('a', 'b'); final char returnSymbol = 'R'; - ALPHABET = new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); + ALPHABET = new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); } @DataProvider diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java index a86c63f9d2..3eff3bbc9b 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java @@ -34,12 +34,12 @@ import de.learnlib.testsupport.it.learner.AbstractSBALearnerIT; import de.learnlib.testsupport.it.learner.LearnerVariantList.SBALearnerVariantList; import net.automatalib.SupportsGrowingAlphabet; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; public class SBAIT extends AbstractSBALearnerIT { @Override - protected void addLearnerVariants(SPAAlphabet alphabet, + protected void addLearnerVariants(ProceduralInputAlphabet alphabet, MembershipOracle mqOracle, SBALearnerVariantList variants) { @@ -54,12 +54,12 @@ protected void addLearnerVariants(SPAAlphabet alphabet, private static class Builder { - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; private final MembershipOracle mqOracle; private final SBALearnerVariantList variants; - private final List, ATManager>> atProviders; + private final List, ATManager>> atProviders; - Builder(SPAAlphabet alphabet, MembershipOracle mqOracle, SBALearnerVariantList variants) { + Builder(ProceduralInputAlphabet alphabet, MembershipOracle mqOracle, SBALearnerVariantList variants) { this.alphabet = alphabet; this.mqOracle = mqOracle; this.variants = variants; @@ -69,7 +69,7 @@ private static class Builder { > & SupportsGrowingAlphabet> & AccessSequenceTransformer>> void addLearnerVariant( LearnerConstructor, Boolean> provider) { - for (Function, ATManager> atProvider : atProviders) { + for (Function, ATManager> atProvider : atProviders) { final SBALearner learner = new SBALearner<>(alphabet, mqOracle, (i) -> provider, atProvider.apply(alphabet)); final String name = String.format("adapter=%s,manager=%s", provider, atProvider); diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/ATRManagerTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/ATRManagerTest.java index 6cc013d0b6..8987fc796b 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/ATRManagerTest.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/ATRManagerTest.java @@ -18,24 +18,24 @@ import de.learnlib.algorithms.procedural.spa.manager.DefaultATRManager; import de.learnlib.algorithms.procedural.spa.manager.OptimizingATRManager; import net.automatalib.words.Alphabet; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class ATRManagerTest { - private static final SPAAlphabet ALPHABET; + private static final ProceduralInputAlphabet ALPHABET; static { final Alphabet callAlphabet = Alphabets.characters('A', 'C'); final Alphabet internalAlphabet = Alphabets.characters('a', 'b'); final char returnSymbol = 'R'; - ALPHABET = new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); + ALPHABET = new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); } @DataProvider diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java index 0cd6e39496..860f004d9f 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java @@ -33,12 +33,12 @@ import de.learnlib.testsupport.it.learner.AbstractSPALearnerIT; import de.learnlib.testsupport.it.learner.LearnerVariantList.SPALearnerVariantList; import net.automatalib.SupportsGrowingAlphabet; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; public class SPAIT extends AbstractSPALearnerIT { @Override - protected void addLearnerVariants(SPAAlphabet alphabet, + protected void addLearnerVariants(ProceduralInputAlphabet alphabet, MembershipOracle mqOracle, SPALearnerVariantList variants) { @@ -53,12 +53,12 @@ protected void addLearnerVariants(SPAAlphabet alphabet, private static class Builder { - private final SPAAlphabet alphabet; + private final ProceduralInputAlphabet alphabet; private final MembershipOracle mqOracle; private final SPALearnerVariantList variants; - private final List, ATRManager>> atrProviders; + private final List, ATRManager>> atrProviders; - Builder(SPAAlphabet alphabet, MembershipOracle mqOracle, SPALearnerVariantList variants) { + Builder(ProceduralInputAlphabet alphabet, MembershipOracle mqOracle, SPALearnerVariantList variants) { this.alphabet = alphabet; this.mqOracle = mqOracle; this.variants = variants; @@ -68,7 +68,7 @@ private static class Builder { & SupportsGrowingAlphabet & AccessSequenceTransformer> void addLearnerVariant( LearnerConstructor provider) { - for (Function, ATRManager> atrProvider : atrProviders) { + for (Function, ATRManager> atrProvider : atrProviders) { final SPALearner learner = new SPALearner<>(alphabet, mqOracle, (i) -> provider, atrProvider.apply(alphabet)); final String name = String.format("adapter=%s,manager=%s", provider, atrProvider); diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java index 0d36ff80df..c808d88021 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java @@ -19,28 +19,28 @@ import de.learnlib.algorithms.procedural.spmm.manager.OptimizingATManager; import de.learnlib.api.query.DefaultQuery; import net.automatalib.words.Alphabet; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import net.automatalib.words.impl.DefaultSPAAlphabet; -import net.automatalib.words.impl.DefaultSPAOutputAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; +import net.automatalib.words.impl.DefaultProceduralOutputAlphabet; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class ATManagerTest { - private static final SPAAlphabet INPUT_ALPHABET; - private static final SPAOutputAlphabet OUTPUT_ALPHABET; + private static final ProceduralInputAlphabet INPUT_ALPHABET; + private static final ProceduralOutputAlphabet OUTPUT_ALPHABET; static { final Alphabet callAlphabet = Alphabets.characters('A', 'C'); final Alphabet internalAlphabet = Alphabets.characters('a', 'b'); final char returnSymbol = 'R'; - INPUT_ALPHABET = new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); - OUTPUT_ALPHABET = new DefaultSPAOutputAlphabet<>(Alphabets.characters('x', 'z'), '✗'); + INPUT_ALPHABET = new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); + OUTPUT_ALPHABET = new DefaultProceduralOutputAlphabet<>(Alphabets.characters('x', 'z'), '✗'); } @DataProvider diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java index c0f929901e..1dd91ec158 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java @@ -34,15 +34,15 @@ import de.learnlib.testsupport.it.learner.AbstractSPMMLearnerIT; import de.learnlib.testsupport.it.learner.LearnerVariantList.SPMMLearnerVariantList; import net.automatalib.SupportsGrowingAlphabet; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; public class SPMMIT extends AbstractSPMMLearnerIT { @Override - protected void addLearnerVariants(SPAAlphabet alphabet, - SPAOutputAlphabet outputAlphabet, + protected void addLearnerVariants(ProceduralInputAlphabet alphabet, + ProceduralOutputAlphabet outputAlphabet, MembershipOracle> mqOracle, SPMMLearnerVariantList variants) { @@ -57,14 +57,14 @@ protected void addLearnerVariants(SPAAlphabet alphabet, private static class Builder { - private final SPAAlphabet inputAlphabet; - private final SPAOutputAlphabet outputAlphabet; + private final ProceduralInputAlphabet inputAlphabet; + private final ProceduralOutputAlphabet outputAlphabet; private final MembershipOracle> mqOracle; private final SPMMLearnerVariantList variants; - private final List, SPAOutputAlphabet, ATManager>> atProviders; + private final List, ProceduralOutputAlphabet, ATManager>> atProviders; - Builder(SPAAlphabet inputAlphabet, - SPAOutputAlphabet outputAlphabet, + Builder(ProceduralInputAlphabet inputAlphabet, + ProceduralOutputAlphabet outputAlphabet, MembershipOracle> mqOracle, SPMMLearnerVariantList variants) { this.inputAlphabet = inputAlphabet; @@ -77,7 +77,7 @@ private static class Builder { , O> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> void addLearnerVariant( LearnerConstructor, Word> provider) { - for (BiFunction, SPAOutputAlphabet, ATManager> atProvider : atProviders) { + for (BiFunction, ProceduralOutputAlphabet, ATManager> atProvider : atProviders) { final SPMMLearner learner = new SPMMLearner<>(inputAlphabet, outputAlphabet, mqOracle, diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java index 69c424ccf2..a7c78e4a46 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java @@ -19,9 +19,9 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.sba.SBA; +import net.automatalib.automata.procedural.SBA; import net.automatalib.util.automata.Automata; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; @@ -35,12 +35,12 @@ public SimulatorEQOracle(SBA sba) { @Override public @Nullable DefaultQuery findCounterExample(SBA hypothesis, Collection inputs) { - if (!(inputs instanceof SPAAlphabet)) { + if (!(inputs instanceof ProceduralInputAlphabet)) { throw new IllegalArgumentException("Inputs are not an SPA alphabet"); } @SuppressWarnings("unchecked") - final SPAAlphabet alphabet = (SPAAlphabet) inputs; + final ProceduralInputAlphabet alphabet = (ProceduralInputAlphabet) inputs; final Word sep = Automata.findSeparatingWord(sba, hypothesis, alphabet); diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/SimulatorEQOracle.java index a09438e55a..f7670057a5 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/SimulatorEQOracle.java @@ -19,9 +19,9 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.procedural.SPA; import net.automatalib.util.automata.Automata; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; @@ -35,12 +35,12 @@ public SimulatorEQOracle(SPA spa) { @Override public @Nullable DefaultQuery findCounterExample(SPA hypothesis, Collection inputs) { - if (!(inputs instanceof SPAAlphabet)) { + if (!(inputs instanceof ProceduralInputAlphabet)) { throw new IllegalArgumentException("Inputs are not an SPA alphabet"); } @SuppressWarnings("unchecked") - final SPAAlphabet alphabet = (SPAAlphabet) inputs; + final ProceduralInputAlphabet alphabet = (ProceduralInputAlphabet) inputs; final Word sep = Automata.findSeparatingWord(spa, hypothesis, alphabet); diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracle.java index 085383ca8b..607e6d8c67 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracle.java @@ -23,10 +23,10 @@ import de.learnlib.oracle.equivalence.AbstractTestWordEQOracle; import de.learnlib.oracle.equivalence.WMethodEQOracle; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.procedural.SPA; import net.automatalib.util.automata.conformance.SPATestsIterator; import net.automatalib.util.automata.conformance.WMethodTestsIterator; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; /** @@ -96,12 +96,12 @@ public WMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead, @Override protected Stream> generateTestWords(SPA hypothesis, Collection inputs) { - if (!(inputs instanceof SPAAlphabet)) { + if (!(inputs instanceof ProceduralInputAlphabet)) { throw new IllegalArgumentException("Inputs are not an SPA alphabet"); } @SuppressWarnings("unchecked") - final SPAAlphabet alphabet = (SPAAlphabet) inputs; + final ProceduralInputAlphabet alphabet = (ProceduralInputAlphabet) inputs; return Streams.stream(new SPATestsIterator<>(hypothesis, alphabet, diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracle.java index 6d733df988..e661015705 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracle.java @@ -23,11 +23,11 @@ import de.learnlib.oracle.equivalence.AbstractTestWordEQOracle; import de.learnlib.oracle.equivalence.WpMethodEQOracle; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.procedural.SPA; import net.automatalib.util.automata.conformance.SPATestsIterator; import net.automatalib.util.automata.conformance.WMethodTestsIterator; import net.automatalib.util.automata.conformance.WpMethodTestsIterator; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; /** @@ -97,12 +97,12 @@ public WpMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead @Override protected Stream> generateTestWords(SPA hypothesis, Collection inputs) { - if (!(inputs instanceof SPAAlphabet)) { + if (!(inputs instanceof ProceduralInputAlphabet)) { throw new IllegalArgumentException("Inputs are not an SPA alphabet"); } @SuppressWarnings("unchecked") - final SPAAlphabet alphabet = (SPAAlphabet) inputs; + final ProceduralInputAlphabet alphabet = (ProceduralInputAlphabet) inputs; return Streams.stream(new SPATestsIterator<>(hypothesis, alphabet, diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java index 030fac0e40..6ee8025b82 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java @@ -19,9 +19,9 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.api.query.DefaultQuery; -import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.procedural.SPMM; import net.automatalib.util.automata.Automata; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; @@ -36,12 +36,12 @@ public SimulatorEQOracle(SPMM spmm) { @Override public @Nullable DefaultQuery> findCounterExample(SPMM hypothesis, Collection inputs) { - if (!(inputs instanceof SPAAlphabet)) { + if (!(inputs instanceof ProceduralInputAlphabet)) { throw new IllegalArgumentException("Inputs are not an SPA alphabet"); } @SuppressWarnings("unchecked") - final SPAAlphabet alphabet = (SPAAlphabet) inputs; + final ProceduralInputAlphabet alphabet = (ProceduralInputAlphabet) inputs; final Word sep = Automata.findSeparatingWord(spmm, hypothesis, alphabet); diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java index bc41217423..9e92e01b65 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java @@ -21,14 +21,14 @@ import com.google.common.collect.Streams; import de.learnlib.oracle.membership.SimulatorOracle; -import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.procedural.SPA; import net.automatalib.util.automata.conformance.SPATestsIterator; import net.automatalib.util.automata.conformance.WMethodTestsIterator; import net.automatalib.util.automata.random.RandomAutomata; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; import org.testng.Assert; import org.testng.annotations.Test; @@ -37,8 +37,8 @@ public class WMethodSPAEQOracleTest { @Test public void testOracle() { final Random random = new Random(42); - final SPAAlphabet alphabet = - new DefaultSPAAlphabet<>(Alphabets.characters('x', 'z'), Alphabets.characters('A', 'C'), 'R'); + final ProceduralInputAlphabet alphabet = + new DefaultProceduralInputAlphabet<>(Alphabets.characters('x', 'z'), Alphabets.characters('A', 'C'), 'R'); final SPA spa = RandomAutomata.randomSPA(random, alphabet, 4); final int lookahead = 2; diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java index e9140ce9ff..02ca52b408 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java @@ -21,14 +21,14 @@ import com.google.common.collect.Streams; import de.learnlib.oracle.membership.SimulatorOracle; -import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.procedural.SPA; import net.automatalib.util.automata.conformance.SPATestsIterator; import net.automatalib.util.automata.conformance.WpMethodTestsIterator; import net.automatalib.util.automata.random.RandomAutomata; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; import org.testng.Assert; import org.testng.annotations.Test; @@ -37,8 +37,8 @@ public class WpMethodSPAEQOracleTest { @Test public void testOracle() { final Random random = new Random(42); - final SPAAlphabet alphabet = - new DefaultSPAAlphabet<>(Alphabets.characters('x', 'z'), Alphabets.characters('A', 'C'), 'R'); + final ProceduralInputAlphabet alphabet = + new DefaultProceduralInputAlphabet<>(Alphabets.characters('x', 'z'), Alphabets.characters('A', 'C'), 'R'); final SPA spa = RandomAutomata.randomSPA(random, alphabet, 4); final int lookahead = 2; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java index 36b513f874..9521f09182 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java @@ -25,7 +25,7 @@ import de.learnlib.oracle.membership.SimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.SBALearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SBALearnerVariantListImpl; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import org.testng.annotations.Factory; /** @@ -49,7 +49,7 @@ public Object[] createExampleITCases() { private List> createAllVariantsITCase(SBALearningExample example) { - final SPAAlphabet alphabet = example.getAlphabet(); + final ProceduralInputAlphabet alphabet = example.getAlphabet(); final MembershipOracle mqOracle = new SimulatorOracle<>(example.getReferenceAutomaton()); final SBALearnerVariantListImpl variants = new SBALearnerVariantListImpl<>(); addLearnerVariants(alphabet, mqOracle, variants); @@ -70,7 +70,7 @@ private List> createAllVariantsITCase(SBALearningExample * @param variants * list to add the learner variants to */ - protected abstract void addLearnerVariants(SPAAlphabet alphabet, + protected abstract void addLearnerVariants(ProceduralInputAlphabet alphabet, MembershipOracle mqOracle, SBALearnerVariantList variants); } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPALearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPALearnerIT.java index c7a869cef4..47accb4452 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPALearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPALearnerIT.java @@ -25,7 +25,7 @@ import de.learnlib.oracle.membership.SimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.SPALearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SPALearnerVariantListImpl; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import org.testng.annotations.Factory; /** @@ -49,7 +49,7 @@ public Object[] createExampleITCases() { private List> createAllVariantsITCase(SPALearningExample example) { - final SPAAlphabet alphabet = example.getAlphabet(); + final ProceduralInputAlphabet alphabet = example.getAlphabet(); final MembershipOracle mqOracle = new SimulatorOracle<>(example.getReferenceAutomaton()); final SPALearnerVariantListImpl variants = new SPALearnerVariantListImpl<>(); addLearnerVariants(alphabet, mqOracle, variants); @@ -70,7 +70,7 @@ private List> createAllVariantsITCase(SPALearningExample * @param variants * list to add the learner variants to */ - protected abstract void addLearnerVariants(SPAAlphabet alphabet, + protected abstract void addLearnerVariants(ProceduralInputAlphabet alphabet, MembershipOracle mqOracle, SPALearnerVariantList variants); } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java index 7c4a553f2e..4feb03dac7 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java @@ -25,8 +25,8 @@ import de.learnlib.oracle.membership.SimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.SPMMLearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SPMMLearnerVariantListImpl; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; import org.testng.annotations.Factory; @@ -73,8 +73,8 @@ private List> createAllVariantsITCase(SPMMLearnin * @param variants * list to add the learner variants to */ - protected abstract void addLearnerVariants(SPAAlphabet inputAlphabet, - SPAOutputAlphabet outputAlphabet, + protected abstract void addLearnerVariants(ProceduralInputAlphabet inputAlphabet, + ProceduralOutputAlphabet outputAlphabet, MembershipOracle> mqOracle, SPMMLearnerVariantList variants); } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java index 48cc076d1c..82cdf44ed5 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/LearnerITUtil.java @@ -37,9 +37,9 @@ import net.automatalib.automata.UniversalDeterministicAutomaton; import net.automatalib.automata.concepts.FiniteRepresentation; import net.automatalib.automata.concepts.SuffixOutput; -import net.automatalib.automata.sba.SBA; -import net.automatalib.automata.spa.SPA; -import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.automata.procedural.SPA; +import net.automatalib.automata.procedural.SPMM; import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Alphabet; import net.automatalib.words.Word; 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 142330a6c0..c6d812e5b5 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 @@ -17,9 +17,9 @@ import de.learnlib.api.algorithm.LearningAlgorithm; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.sba.SBA; -import net.automatalib.automata.spa.SPA; -import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.automata.procedural.SPA; +import net.automatalib.automata.procedural.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.vpda.OneSEVPA; 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 c1288d0010..66012a1cc8 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 @@ -22,9 +22,9 @@ import de.learnlib.util.mealy.MealyUtil; import de.learnlib.util.moore.MooreUtil; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.sba.SBA; -import net.automatalib.automata.spa.SPA; -import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.automata.procedural.SPA; +import net.automatalib.automata.procedural.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.automata.transducers.MooreMachine; import net.automatalib.automata.vpda.OneSEVPA; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SBALearnerITCase.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SBALearnerITCase.java index 764bd36d46..f0e0fad644 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SBALearnerITCase.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SBALearnerITCase.java @@ -17,7 +17,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.examples.LearningExample.SBALearningExample; -import net.automatalib.automata.sba.SBA; +import net.automatalib.automata.procedural.SBA; import net.automatalib.util.automata.Automata; import net.automatalib.words.Word; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPALearnerITCase.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPALearnerITCase.java index fe28b67bc4..1da9104fb8 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPALearnerITCase.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPALearnerITCase.java @@ -17,7 +17,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.examples.LearningExample.SPALearningExample; -import net.automatalib.automata.spa.SPA; +import net.automatalib.automata.procedural.SPA; import net.automatalib.util.automata.Automata; import net.automatalib.words.Word; diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPMMLearnerITCase.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPMMLearnerITCase.java index 38e74a4370..14b1fdbc16 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPMMLearnerITCase.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/SPMMLearnerITCase.java @@ -17,7 +17,7 @@ import de.learnlib.api.oracle.EquivalenceOracle; import de.learnlib.examples.LearningExample.SPMMLearningExample; -import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.procedural.SPMM; import net.automatalib.util.automata.Automata; import net.automatalib.words.Word; 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 bdd3aeb3f6..8871e563ea 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 @@ -19,16 +19,16 @@ import net.automatalib.automata.concepts.InputAlphabetHolder; import net.automatalib.automata.concepts.SuffixOutput; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.sba.SBA; -import net.automatalib.automata.spa.SPA; -import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.automata.procedural.SPA; +import net.automatalib.automata.procedural.SPMM; 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; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.VPDAlphabet; import net.automatalib.words.Word; @@ -150,7 +150,7 @@ public SPA getReferenceAutomaton() { } @Override - public SPAAlphabet getAlphabet() { + public ProceduralInputAlphabet getAlphabet() { return this.referenceAutomaton.getInputAlphabet(); } } @@ -169,7 +169,7 @@ public SBA getReferenceAutomaton() { } @Override - public SPAAlphabet getAlphabet() { + public ProceduralInputAlphabet getAlphabet() { return this.referenceAutomaton.getInputAlphabet(); } } @@ -188,12 +188,12 @@ public DefaultSPMMLearningExample(SPMM referenceAutomaton) { } @Override - public SPAAlphabet getAlphabet() { + public ProceduralInputAlphabet getAlphabet() { return this.referenceAutomaton.getInputAlphabet(); } @Override - public SPAOutputAlphabet getOutputAlphabet() { + public ProceduralOutputAlphabet getOutputAlphabet() { return this.referenceAutomaton.getOutputAlphabet(); } } 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 abdc09dcd3..c6b581c159 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 @@ -17,17 +17,17 @@ import net.automatalib.automata.UniversalAutomaton; import net.automatalib.automata.fsa.DFA; -import net.automatalib.automata.sba.SBA; -import net.automatalib.automata.spa.SPA; -import net.automatalib.automata.spmm.SPMM; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.automata.procedural.SPA; +import net.automatalib.automata.procedural.SPMM; 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; import net.automatalib.words.Alphabet; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.VPDAlphabet; public interface LearningExample { @@ -66,21 +66,21 @@ interface StateLocalInputMealyLearningExample interface SPALearningExample extends LearningExample> { @Override - SPAAlphabet getAlphabet(); + ProceduralInputAlphabet getAlphabet(); } interface SBALearningExample extends LearningExample> { @Override - SPAAlphabet getAlphabet(); + ProceduralInputAlphabet getAlphabet(); } interface SPMMLearningExample extends LearningExample> { @Override - SPAAlphabet getAlphabet(); + ProceduralInputAlphabet getAlphabet(); - SPAOutputAlphabet getOutputAlphabet(); + ProceduralOutputAlphabet getOutputAlphabet(); } interface OneSEVPALearningExample extends LearningExample> { 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 9911ed4997..73d8f66589 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 @@ -49,22 +49,22 @@ import de.learnlib.examples.sst.ExampleRandomSST; import de.learnlib.examples.vpda.ExampleRandomOneSEVPA; import net.automatalib.words.Alphabet; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.VPDAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; -import net.automatalib.words.impl.DefaultSPAAlphabet; -import net.automatalib.words.impl.DefaultSPAOutputAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; +import net.automatalib.words.impl.DefaultProceduralOutputAlphabet; import net.automatalib.words.impl.DefaultVPDAlphabet; public final class LearningExamples { private static final Alphabet RANDOM_ALPHABET = Alphabets.characters('a', 'c'); - private static final SPAAlphabet SPA_INPUT_ALPHABET = - new DefaultSPAAlphabet<>(Alphabets.characters('A', 'F'), Alphabets.characters('a', 'f'), 'R'); - private static final SPAOutputAlphabet SPA_OUTPUT_ALPHABET = - new DefaultSPAOutputAlphabet<>(Alphabets.characters('u', 'z'), '✗'); + private static final ProceduralInputAlphabet SPA_INPUT_ALPHABET = + new DefaultProceduralInputAlphabet<>(Alphabets.characters('A', 'F'), Alphabets.characters('a', 'f'), 'R'); + private static final ProceduralOutputAlphabet SPA_OUTPUT_ALPHABET = + new DefaultProceduralOutputAlphabet<>(Alphabets.characters('u', 'z'), '✗'); private static final VPDAlphabet VPD_ALPHABET = new DefaultVPDAlphabet<>(Alphabets.characters('a', 'f'), Alphabets.characters('1', '3'), Alphabets.characters('7', '9')); diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExampleRandomSBA.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExampleRandomSBA.java index c16b363628..70134dfe8d 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExampleRandomSBA.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExampleRandomSBA.java @@ -19,19 +19,19 @@ import de.learnlib.examples.DefaultLearningExample.DefaultSBALearningExample; import net.automatalib.util.automata.random.RandomAutomata; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; public class ExampleRandomSBA extends DefaultSBALearningExample { - public ExampleRandomSBA(SPAAlphabet alphabet, int size) { + public ExampleRandomSBA(ProceduralInputAlphabet alphabet, int size) { this(new Random(), alphabet, size); } - public ExampleRandomSBA(Random random, SPAAlphabet alphabet, int size) { + public ExampleRandomSBA(Random random, ProceduralInputAlphabet alphabet, int size) { super(RandomAutomata.randomSBA(random, alphabet, size)); } - public static ExampleRandomSBA createExample(Random random, SPAAlphabet alphabet, int size) { + public static ExampleRandomSBA createExample(Random random, ProceduralInputAlphabet alphabet, int size) { return new ExampleRandomSBA<>(random, alphabet, size); } } diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExamplePalindrome.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExamplePalindrome.java index 5f671ae6cc..1cc05b73e2 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExamplePalindrome.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExamplePalindrome.java @@ -22,14 +22,14 @@ import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.fsa.impl.FastDFA; import net.automatalib.automata.fsa.impl.compact.CompactDFA; -import net.automatalib.automata.spa.SPA; -import net.automatalib.automata.spa.StackSPA; +import net.automatalib.automata.procedural.SPA; +import net.automatalib.automata.procedural.StackSPA; import net.automatalib.util.automata.builders.AutomatonBuilders; import net.automatalib.util.automata.fsa.MutableDFAs; import net.automatalib.words.Alphabet; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.impl.Alphabets; -import net.automatalib.words.impl.DefaultSPAAlphabet; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; public class ExamplePalindrome extends DefaultSPALearningExample { @@ -44,7 +44,7 @@ public static ExamplePalindrome createExample() { private static SPA createSPA() { final Alphabet internalAlphabet = Alphabets.characters('a', 'c'); final Alphabet callAlphabet = Alphabets.characters('S', 'T'); - final SPAAlphabet alphabet = new DefaultSPAAlphabet<>(internalAlphabet, callAlphabet, 'R'); + final ProceduralInputAlphabet alphabet = new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, 'R'); final DFA sProcedure = buildSProcedure(alphabet); final DFA tProcedure = buildTProcedure(alphabet); @@ -56,7 +56,7 @@ private static SPA createSPA() { return new StackSPA<>(alphabet, 'S', subModels); } - private static DFA buildSProcedure(SPAAlphabet alphabet) { + private static DFA buildSProcedure(ProceduralInputAlphabet alphabet) { final CompactDFA result = new CompactDFA<>(alphabet.getProceduralAlphabet()); @@ -78,7 +78,7 @@ private static DFA buildSProcedure(SPAAlphabet alphabet return result; } - private static DFA buildTProcedure(SPAAlphabet alphabet) { + private static DFA buildTProcedure(ProceduralInputAlphabet alphabet) { final FastDFA result = new FastDFA<>(alphabet.getProceduralAlphabet()); diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExampleRandomSPA.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExampleRandomSPA.java index b0ab449691..9ebe2ca714 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExampleRandomSPA.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/spa/ExampleRandomSPA.java @@ -19,19 +19,19 @@ import de.learnlib.examples.DefaultLearningExample.DefaultSPALearningExample; import net.automatalib.util.automata.random.RandomAutomata; -import net.automatalib.words.SPAAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; public class ExampleRandomSPA extends DefaultSPALearningExample { - public ExampleRandomSPA(SPAAlphabet alphabet, int size) { + public ExampleRandomSPA(ProceduralInputAlphabet alphabet, int size) { this(new Random(), alphabet, size); } - public ExampleRandomSPA(Random random, SPAAlphabet alphabet, int size) { + public ExampleRandomSPA(Random random, ProceduralInputAlphabet alphabet, int size) { super(RandomAutomata.randomSPA(random, alphabet, size)); } - public static ExampleRandomSPA createExample(Random random, SPAAlphabet alphabet, int size) { + public static ExampleRandomSPA createExample(Random random, ProceduralInputAlphabet alphabet, int size) { return new ExampleRandomSPA<>(random, alphabet, size); } } diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExampleRandomSPMM.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExampleRandomSPMM.java index 585ff5f04b..f70a53ab1b 100644 --- a/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExampleRandomSPMM.java +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExampleRandomSPMM.java @@ -19,20 +19,20 @@ import de.learnlib.examples.DefaultLearningExample.DefaultSPMMLearningExample; import net.automatalib.util.automata.random.RandomAutomata; -import net.automatalib.words.SPAAlphabet; -import net.automatalib.words.SPAOutputAlphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; public class ExampleRandomSPMM extends DefaultSPMMLearningExample { - public ExampleRandomSPMM(SPAAlphabet inputAlphabet, SPAOutputAlphabet outputAlphabet, int size) { + public ExampleRandomSPMM(ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet, int size) { this(new Random(), inputAlphabet, outputAlphabet, size); } - public ExampleRandomSPMM(Random random, SPAAlphabet inputAlphabet, SPAOutputAlphabet outputAlphabet, int size) { + public ExampleRandomSPMM(Random random, ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet, int size) { super(RandomAutomata.randomSPMM(random, inputAlphabet, outputAlphabet, size)); } - public static ExampleRandomSPMM createExample(Random random, SPAAlphabet inputAlphabet, SPAOutputAlphabet outputAlphabet, int size) { + public static ExampleRandomSPMM createExample(Random random, ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet, int size) { return new ExampleRandomSPMM<>(random, inputAlphabet, outputAlphabet, size); } } From f4df9a6681cc90265d420266b57698010c4f372b Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 27 Jul 2023 23:23:47 +0200 Subject: [PATCH 05/15] add procedural W-method oracles --- .../equivalence/sba/SimulatorEQOracle.java | 3 + .../equivalence/sba/WMethodEQOracle.java | 110 +++++++++++++++++ .../equivalence/spa/SimulatorEQOracle.java | 2 +- ...dSPAEQOracle.java => WMethodEQOracle.java} | 32 ++--- ...SPAEQOracle.java => WpMethodEQOracle.java} | 30 ++--- .../equivalence/spmm/SimulatorEQOracle.java | 3 + .../equivalence/spmm/WMethodEQOracle.java | 111 ++++++++++++++++++ .../equivalence/sba/WMethodEQOracleTest.java | 54 +++++++++ ...acleTest.java => WMethodEQOracleTest.java} | 8 +- ...cleTest.java => WpMethodEQOracleTest.java} | 8 +- .../equivalence/spmm/WMethodEQOracleTest.java | 62 ++++++++++ 11 files changed, 385 insertions(+), 38 deletions(-) create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracle.java rename oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/{WMethodSPAEQOracle.java => WMethodEQOracle.java} (73%) rename oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/{WpMethodSPAEQOracle.java => WpMethodEQOracle.java} (73%) create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/WMethodEQOracle.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracleTest.java rename oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/{WMethodSPAEQOracleTest.java => WMethodEQOracleTest.java} (88%) rename oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/{WpMethodSPAEQOracleTest.java => WpMethodEQOracleTest.java} (88%) create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spmm/WMethodEQOracleTest.java diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java index a7c78e4a46..de198a4620 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/SimulatorEQOracle.java @@ -25,6 +25,9 @@ import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * @author frohme + */ public class SimulatorEQOracle implements EquivalenceOracle, I, Boolean> { private final SBA sba; diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracle.java new file mode 100644 index 0000000000..a7490cd4de --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracle.java @@ -0,0 +1,110 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.sba; + +import java.util.Collection; +import java.util.stream.Stream; + +import com.google.common.collect.Streams; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.oracle.equivalence.AbstractTestWordEQOracle; +import net.automatalib.automata.concepts.FiniteRepresentation; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.util.automata.conformance.SBAWMethodTestsIterator; +import net.automatalib.util.automata.conformance.WMethodTestsIterator; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.Word; + +/** + * Implements an equivalence test by applying the W-method test on the procedures of the given hypothesis {@link SBA}, + * as described in "Testing software design modeled by finite state machines" by T.S. Chow. + * + * @param + * input symbol type + * + * @author frohme + */ +public class WMethodEQOracle extends AbstractTestWordEQOracle, I, Boolean> { + + private final int lookahead; + private final int expectedSize; + + /** + * Constructor. Convenience method for {@link #WMethodEQOracle(MembershipOracle, int, int)} that sets + * {@code expectedSize} to 0. + * + * @param sulOracle + * interface to the system under learning + * @param lookahead + * the maximum length of the "middle" part of the test cases + */ + public WMethodEQOracle(MembershipOracle sulOracle, int lookahead) { + this(sulOracle, lookahead, 0); + } + + /** + * Constructor. Convenience method for {@link #WMethodEQOracle(MembershipOracle, int, int, int)} that sets + * {@code batchSize} to 1. + * + * @param sulOracle + * interface to the system under learning + * @param lookahead + * the (minimal) maximum length of the "middle" part of the test cases + * @param expectedSize + * the expected size of the system under learning + */ + public WMethodEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize) { + this(sulOracle, lookahead, expectedSize, 1); + } + + /** + * Constructor. Uses + * {@link Math#max(int, int) Math.max}{@code (lookahead, expectedSize - }{@link FiniteRepresentation#size() + * hypothesis.size()}{@code )} to determine the maximum length of sequences, that should be appended to the + * transition-cover part of the test sequence to account for the fact that the system under learning may have more + * states than the current hypothesis. + * + * @param sulOracle + * interface to the system under learning + * @param lookahead + * the (minimal) maximum length of the "middle" part of the test cases + * @param expectedSize + * the expected size of the system under learning + * @param batchSize + * size of the batches sent to the membership oracle + * + * @see WMethodTestsIterator + */ + public WMethodEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize, int batchSize) { + super(sulOracle, batchSize); + this.lookahead = lookahead; + this.expectedSize = expectedSize; + } + + @Override + protected Stream> generateTestWords(SBA hypothesis, Collection inputs) { + if (!(inputs instanceof ProceduralInputAlphabet)) { + throw new IllegalArgumentException("Inputs are not a procedural alphabet"); + } + + @SuppressWarnings("unchecked") + final ProceduralInputAlphabet alphabet = (ProceduralInputAlphabet) inputs; + + return Streams.stream(new SBAWMethodTestsIterator<>(hypothesis, + alphabet, + Math.max(lookahead, expectedSize - hypothesis.size()))); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/SimulatorEQOracle.java index f7670057a5..9d1591b7b4 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/SimulatorEQOracle.java @@ -36,7 +36,7 @@ public SimulatorEQOracle(SPA spa) { @Override public @Nullable DefaultQuery findCounterExample(SPA hypothesis, Collection inputs) { if (!(inputs instanceof ProceduralInputAlphabet)) { - throw new IllegalArgumentException("Inputs are not an SPA alphabet"); + throw new IllegalArgumentException("Inputs are not a procedural alphabet"); } @SuppressWarnings("unchecked") diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodEQOracle.java similarity index 73% rename from oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracle.java rename to oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodEQOracle.java index 607e6d8c67..f5679ca4a9 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WMethodEQOracle.java @@ -21,7 +21,6 @@ import com.google.common.collect.Streams; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.oracle.equivalence.AbstractTestWordEQOracle; -import de.learnlib.oracle.equivalence.WMethodEQOracle; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.procedural.SPA; import net.automatalib.util.automata.conformance.SPATestsIterator; @@ -30,35 +29,35 @@ import net.automatalib.words.Word; /** - * An {@link SPA} version of {@link WMethodEQOracle} which generates test sequences based on the W-method for each - * procedure. + * An {@link SPA} version of {@link de.learnlib.oracle.equivalence.WMethodEQOracle} which generates test sequences based + * on the W-method for each procedure. * * @param * input symbol type * * @author frohme */ -public class WMethodSPAEQOracle extends AbstractTestWordEQOracle, I, Boolean> { +public class WMethodEQOracle extends AbstractTestWordEQOracle, I, Boolean> { private final int lookahead; private final int expectedSize; /** - * Constructor. Convenience method for {@link #WMethodSPAEQOracle(MembershipOracle, int, int)} that sets {@code - * expectedSize} to 0. + * Constructor. Convenience method for {@link #WMethodEQOracle(MembershipOracle, int, int)} that sets + * {@code expectedSize} to 0. * * @param sulOracle * interface to the system under learning * @param lookahead * the maximum length of the "middle" part of the test cases */ - public WMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead) { + public WMethodEQOracle(MembershipOracle sulOracle, int lookahead) { this(sulOracle, lookahead, 0); } /** - * Constructor. Convenience method for {@link #WMethodSPAEQOracle(MembershipOracle, int, int, int)} that sets {@code - * batchSize} to 1. + * Constructor. Convenience method for {@link #WMethodEQOracle(MembershipOracle, int, int, int)} that sets + * {@code batchSize} to 1. * * @param sulOracle * interface to the system under learning @@ -67,15 +66,16 @@ public WMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead) * @param expectedSize * the expected size of the system under learning */ - public WMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize) { + public WMethodEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize) { this(sulOracle, lookahead, expectedSize, 1); } /** - * Constructor. Uses {@link Math#max(int, int) Math.max}{@code (lookahead, expectedSize - }{@link DFA#size() - * hypothesis.size()}{@code )} (for each procedural {@code hypothesis}) to determine the maximum length of - * sequences, that should be appended to the transition-cover part of the test sequence to account for the fact that - * the system under learning may have more states than the current hypothesis. + * Constructor. Uses + * {@link Math#max(int, int) Math.max}{@code (lookahead, expectedSize - }{@link DFA#size() hypothesis.size()}{@code + * )} (for each procedural {@code hypothesis}) to determine the maximum length of sequences, that should be appended + * to the transition-cover part of the test sequence to account for the fact that the system under learning may have + * more states than the current hypothesis. * * @param sulOracle * interface to the system under learning @@ -88,7 +88,7 @@ public WMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead, * * @see WMethodTestsIterator */ - public WMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize, int batchSize) { + public WMethodEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize, int batchSize) { super(sulOracle, batchSize); this.lookahead = lookahead; this.expectedSize = expectedSize; @@ -97,7 +97,7 @@ public WMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead, @Override protected Stream> generateTestWords(SPA hypothesis, Collection inputs) { if (!(inputs instanceof ProceduralInputAlphabet)) { - throw new IllegalArgumentException("Inputs are not an SPA alphabet"); + throw new IllegalArgumentException("Inputs are not a procedural alphabet"); } @SuppressWarnings("unchecked") diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodEQOracle.java similarity index 73% rename from oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracle.java rename to oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodEQOracle.java index e661015705..cb21d7557b 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spa/WpMethodEQOracle.java @@ -21,7 +21,6 @@ import com.google.common.collect.Streams; import de.learnlib.api.oracle.MembershipOracle; import de.learnlib.oracle.equivalence.AbstractTestWordEQOracle; -import de.learnlib.oracle.equivalence.WpMethodEQOracle; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.procedural.SPA; import net.automatalib.util.automata.conformance.SPATestsIterator; @@ -31,34 +30,34 @@ import net.automatalib.words.Word; /** - * An {@link SPA} version of {@link WpMethodEQOracle} which generates test sequences based on the partial W-method for - * each procedure. + * An {@link SPA} version of {@link de.learnlib.oracle.equivalence.WpMethodEQOracle} which generates test sequences + * based on the partial W-method for each procedure. * * @param * input symbol type * * @author frohme */ -public class WpMethodSPAEQOracle extends AbstractTestWordEQOracle, I, Boolean> { +public class WpMethodEQOracle extends AbstractTestWordEQOracle, I, Boolean> { private final int lookahead; private final int expectedSize; /** - * Constructor. Convenience method for {@link #WpMethodSPAEQOracle(MembershipOracle, int, int)} that sets {@code - * expectedSize} to 0. + * Constructor. Convenience method for {@link #WpMethodEQOracle(MembershipOracle, int, int)} that sets + * {@code expectedSize} to 0. * * @param sulOracle * interface to the system under learning * @param lookahead * the maximum length of the "middle" part of the test cases */ - public WpMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead) { + public WpMethodEQOracle(MembershipOracle sulOracle, int lookahead) { this(sulOracle, lookahead, 0); } /** - * Constructor. Convenience method for {@link #WpMethodSPAEQOracle(MembershipOracle, int, int, int)} that sets + * Constructor. Convenience method for {@link #WpMethodEQOracle(MembershipOracle, int, int, int)} that sets * {@code batchSize} to 1. * * @param sulOracle @@ -68,15 +67,16 @@ public WpMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead * @param expectedSize * the expected size of the system under learning */ - public WpMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize) { + public WpMethodEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize) { this(sulOracle, lookahead, expectedSize, 1); } /** - * Constructor. Uses {@link Math#max(int, int) Math.max}{@code (lookahead, expectedSize - }{@link DFA#size() - * hypothesis.size()}{@code )} (for each procedural {@code hypothesis}) to determine the maximum length of - * sequences, that should be appended to the transition-cover part of the test sequence to account for the fact that - * the system under learning may have more states than the current hypothesis. + * Constructor. Uses + * {@link Math#max(int, int) Math.max}{@code (lookahead, expectedSize - }{@link DFA#size() hypothesis.size()}{@code + * )} (for each procedural {@code hypothesis}) to determine the maximum length of sequences, that should be appended + * to the transition-cover part of the test sequence to account for the fact that the system under learning may have + * more states than the current hypothesis. * * @param sulOracle * interface to the system under learning @@ -89,7 +89,7 @@ public WpMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead * * @see WMethodTestsIterator */ - public WpMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize, int batchSize) { + public WpMethodEQOracle(MembershipOracle sulOracle, int lookahead, int expectedSize, int batchSize) { super(sulOracle, batchSize); this.lookahead = lookahead; this.expectedSize = expectedSize; @@ -98,7 +98,7 @@ public WpMethodSPAEQOracle(MembershipOracle sulOracle, int lookahead @Override protected Stream> generateTestWords(SPA hypothesis, Collection inputs) { if (!(inputs instanceof ProceduralInputAlphabet)) { - throw new IllegalArgumentException("Inputs are not an SPA alphabet"); + throw new IllegalArgumentException("Inputs are not a procedural alphabet"); } @SuppressWarnings("unchecked") diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java index 6ee8025b82..c44d3329be 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/SimulatorEQOracle.java @@ -25,6 +25,9 @@ import net.automatalib.words.Word; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * @author frohme + */ public class SimulatorEQOracle implements EquivalenceOracle, I, Word> { private final SPMM spmm; diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/WMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/WMethodEQOracle.java new file mode 100644 index 0000000000..e5090f4eff --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/spmm/WMethodEQOracle.java @@ -0,0 +1,111 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.spmm; + +import java.util.Collection; +import java.util.stream.Stream; + +import com.google.common.collect.Streams; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.oracle.equivalence.AbstractTestWordEQOracle; +import net.automatalib.automata.concepts.FiniteRepresentation; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.automata.procedural.SPMM; +import net.automatalib.util.automata.conformance.SPMMWMethodTestsIterator; +import net.automatalib.util.automata.conformance.WMethodTestsIterator; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.Word; + +/** + * Implements an equivalence test by applying the W-method test on the procedures of the given hypothesis {@link SBA}, + * as described in "Testing software design modeled by finite state machines" by T.S. Chow. + * + * @param + * input symbol type + * + * @author frohme + */ +public class WMethodEQOracle extends AbstractTestWordEQOracle, I, Word> { + + private final int lookahead; + private final int expectedSize; + + /** + * Constructor. Convenience method for {@link #WMethodEQOracle(MembershipOracle, int, int)} that sets + * {@code expectedSize} to 0. + * + * @param sulOracle + * interface to the system under learning + * @param lookahead + * the maximum length of the "middle" part of the test cases + */ + public WMethodEQOracle(MembershipOracle> sulOracle, int lookahead) { + this(sulOracle, lookahead, 0); + } + + /** + * Constructor. Convenience method for {@link #WMethodEQOracle(MembershipOracle, int, int, int)} that sets + * {@code batchSize} to 1. + * + * @param sulOracle + * interface to the system under learning + * @param lookahead + * the (minimal) maximum length of the "middle" part of the test cases + * @param expectedSize + * the expected size of the system under learning + */ + public WMethodEQOracle(MembershipOracle> sulOracle, int lookahead, int expectedSize) { + this(sulOracle, lookahead, expectedSize, 1); + } + + /** + * Constructor. Uses + * {@link Math#max(int, int) Math.max}{@code (lookahead, expectedSize - }{@link FiniteRepresentation#size() + * hypothesis.size()}{@code )} to determine the maximum length of sequences, that should be appended to the + * transition-cover part of the test sequence to account for the fact that the system under learning may have more + * states than the current hypothesis. + * + * @param sulOracle + * interface to the system under learning + * @param lookahead + * the (minimal) maximum length of the "middle" part of the test cases + * @param expectedSize + * the expected size of the system under learning + * @param batchSize + * size of the batches sent to the membership oracle + * + * @see WMethodTestsIterator + */ + public WMethodEQOracle(MembershipOracle> sulOracle, int lookahead, int expectedSize, int batchSize) { + super(sulOracle, batchSize); + this.lookahead = lookahead; + this.expectedSize = expectedSize; + } + + @Override + protected Stream> generateTestWords(SPMM hypothesis, Collection inputs) { + if (!(inputs instanceof ProceduralInputAlphabet)) { + throw new IllegalArgumentException("Inputs are not a procedural alphabet"); + } + + @SuppressWarnings("unchecked") + final ProceduralInputAlphabet alphabet = (ProceduralInputAlphabet) inputs; + + return Streams.stream(new SPMMWMethodTestsIterator<>(hypothesis, + alphabet, + Math.max(lookahead, expectedSize - hypothesis.size()))); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracleTest.java new file mode 100644 index 0000000000..fcd4301003 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracleTest.java @@ -0,0 +1,54 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.sba; + +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +import com.google.common.collect.Streams; +import de.learnlib.oracle.membership.SimulatorOracle; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.util.automata.conformance.SBAWMethodTestsIterator; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class WMethodEQOracleTest { + + @Test + public void testOracle() { + final Random random = new Random(42); + final ProceduralInputAlphabet alphabet = + new DefaultProceduralInputAlphabet<>(Alphabets.characters('x', 'z'), + Alphabets.characters('A', 'C'), + 'R'); + final SBA sba = RandomAutomata.randomSBA(random, alphabet, 4); + final int lookahead = 2; + + final WMethodEQOracle oracle = new WMethodEQOracle<>(new SimulatorOracle<>(sba), lookahead); + + final List> eqWords = oracle.generateTestWords(sba, alphabet).collect(Collectors.toList()); + final List> testWords = + Streams.stream(new SBAWMethodTestsIterator<>(sba, alphabet, lookahead)).collect(Collectors.toList()); + + Assert.assertEquals(eqWords, testWords); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodEQOracleTest.java similarity index 88% rename from oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java rename to oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodEQOracleTest.java index 9e92e01b65..69fbe311a4 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodSPAEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WMethodEQOracleTest.java @@ -32,17 +32,19 @@ import org.testng.Assert; import org.testng.annotations.Test; -public class WMethodSPAEQOracleTest { +public class WMethodEQOracleTest { @Test public void testOracle() { final Random random = new Random(42); final ProceduralInputAlphabet alphabet = - new DefaultProceduralInputAlphabet<>(Alphabets.characters('x', 'z'), Alphabets.characters('A', 'C'), 'R'); + new DefaultProceduralInputAlphabet<>(Alphabets.characters('x', 'z'), + Alphabets.characters('A', 'C'), + 'R'); final SPA spa = RandomAutomata.randomSPA(random, alphabet, 4); final int lookahead = 2; - final WMethodSPAEQOracle oracle = new WMethodSPAEQOracle<>(new SimulatorOracle<>(spa), lookahead); + final WMethodEQOracle oracle = new WMethodEQOracle<>(new SimulatorOracle<>(spa), lookahead); final List> eqWords = oracle.generateTestWords(spa, alphabet).collect(Collectors.toList()); final List> testWords = Streams.stream(new SPATestsIterator<>(spa, diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodEQOracleTest.java similarity index 88% rename from oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java rename to oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodEQOracleTest.java index 02ca52b408..4e86b79faa 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodSPAEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spa/WpMethodEQOracleTest.java @@ -32,17 +32,19 @@ import org.testng.Assert; import org.testng.annotations.Test; -public class WpMethodSPAEQOracleTest { +public class WpMethodEQOracleTest { @Test public void testOracle() { final Random random = new Random(42); final ProceduralInputAlphabet alphabet = - new DefaultProceduralInputAlphabet<>(Alphabets.characters('x', 'z'), Alphabets.characters('A', 'C'), 'R'); + new DefaultProceduralInputAlphabet<>(Alphabets.characters('x', 'z'), + Alphabets.characters('A', 'C'), + 'R'); final SPA spa = RandomAutomata.randomSPA(random, alphabet, 4); final int lookahead = 2; - final WpMethodSPAEQOracle oracle = new WpMethodSPAEQOracle<>(new SimulatorOracle<>(spa), lookahead); + final WpMethodEQOracle oracle = new WpMethodEQOracle<>(new SimulatorOracle<>(spa), lookahead); final List> eqWords = oracle.generateTestWords(spa, alphabet).collect(Collectors.toList()); final List> testWords = Streams.stream(new SPATestsIterator<>(spa, diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spmm/WMethodEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spmm/WMethodEQOracleTest.java new file mode 100644 index 0000000000..20615d6491 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/spmm/WMethodEQOracleTest.java @@ -0,0 +1,62 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.oracle.equivalence.spmm; + +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +import com.google.common.collect.Streams; +import de.learnlib.oracle.membership.SimulatorOracle; +import net.automatalib.automata.procedural.SPMM; +import net.automatalib.util.automata.conformance.SPMMWMethodTestsIterator; +import net.automatalib.util.automata.random.RandomAutomata; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.ProceduralOutputAlphabet; +import net.automatalib.words.Word; +import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; +import net.automatalib.words.impl.DefaultProceduralOutputAlphabet; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class WMethodEQOracleTest { + + @Test + public void testOracle() { + final Random random = new Random(42); + final ProceduralInputAlphabet inputAlphabet = + new DefaultProceduralInputAlphabet<>(Alphabets.characters('x', 'z'), + Alphabets.characters('A', 'C'), + 'R'); + final ProceduralOutputAlphabet outputAlphabet = + new DefaultProceduralOutputAlphabet<>(Alphabets.characters('d', 'f'), '-'); + final SPMM spmm = + RandomAutomata.randomSPMM(random, inputAlphabet, outputAlphabet, 4); + final int lookahead = 2; + + final WMethodEQOracle oracle = + new WMethodEQOracle<>(new SimulatorOracle<>(spmm), lookahead); + + final List> eqWords = + oracle.generateTestWords(spmm, inputAlphabet).collect(Collectors.toList()); + final List> testWords = + Streams.stream(new SPMMWMethodTestsIterator<>(spmm, inputAlphabet, lookahead)) + .collect(Collectors.toList()); + + Assert.assertEquals(eqWords, testWords); + } +} \ No newline at end of file From e2cf1bd930a0b9a4d1488de6e25500e687c8884d Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 14 Aug 2023 17:04:15 +0200 Subject: [PATCH 06/15] make SBA/SPMM learner add non-continuable symbols lazily --- .../algorithms/procedural/AlphabetMapper.java | 47 ------- .../algorithms/procedural/SymbolWrapper.java | 25 +--- .../adapter/mealy/LStarBaseAdapterMealy.java | 2 +- .../mealy/RivestSchapireAdapterMealy.java | 2 +- .../algorithms/procedural/sba/MappingSBA.java | 18 +-- .../sba/ProceduralMembershipOracle.java | 7 +- .../algorithms/procedural/sba/SBALearner.java | 122 +++++++++--------- .../sba/manager/DefaultATManager.java | 2 +- .../sba/manager/OptimizingATManager.java | 11 +- .../procedural/spmm/MappingSPMM.java | 15 +-- .../spmm/ProceduralMembershipOracle.java | 11 +- .../procedural/spmm/SPMMLearner.java | 91 ++++++------- .../spmm/manager/DefaultATManager.java | 2 +- .../spmm/manager/OptimizingATManager.java | 16 +-- 14 files changed, 156 insertions(+), 215 deletions(-) delete mode 100644 algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java deleted file mode 100644 index b4b8f02c04..0000000000 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/AlphabetMapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (C) 2013-2023 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.algorithms.procedural; - -import java.util.Arrays; -import java.util.Collection; - -import net.automatalib.commons.util.mappings.Mapping; -import net.automatalib.words.ProceduralInputAlphabet; - -public class AlphabetMapper implements Mapping> { - - private final ProceduralInputAlphabet source; - private final SymbolWrapper[] target; - - @SuppressWarnings("unchecked") - public AlphabetMapper(ProceduralInputAlphabet source) { - this.source = source; - this.target = new SymbolWrapper[source.size()]; - } - - public void set(I symbol, SymbolWrapper representative) { - this.target[source.getSymbolIndex(symbol)] = representative; - } - - @Override - public SymbolWrapper get(I symbol) { - return this.target[source.getSymbolIndex(symbol)]; - } - - public Collection> values() { - return Arrays.asList(this.target); - } -} diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java index 880a8c4541..f05ebbf08e 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java @@ -15,39 +15,26 @@ */ package de.learnlib.algorithms.procedural; -import java.util.Objects; - -import net.automatalib.words.VPDAlphabet.SymbolType; - public class SymbolWrapper { private final I delegate; - private final boolean isTerminating; - private final SymbolType type; + private final boolean continuable; - public SymbolWrapper(I delegate, boolean isTerminating, SymbolType type) { + public SymbolWrapper(I delegate, boolean continuable) { this.delegate = delegate; - this.isTerminating = isTerminating; - this.type = type; + this.continuable = continuable; } public I getDelegate() { return delegate; } - public boolean isTerminating() { - return isTerminating; - } - - public SymbolType getType() { - return type; + public boolean isContinuable() { + return continuable; } @Override public String toString() { - if (type == SymbolType.CALL) { - return String.valueOf(delegate) + '(' + isTerminating + ')'; - } - return Objects.toString(delegate); + return String.valueOf(delegate) + '(' + continuable + ')'; } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java index d1ac122a75..7b0b91e617 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java @@ -55,7 +55,7 @@ public Word transformAccessSequence(Word word) { final Object reachedState = hypothesis.getState(word); - for (final Word shortPrefix : observationTable.getShortPrefixes()) { + for (Word shortPrefix : observationTable.getShortPrefixes()) { final Object reachedSPState = hypothesis.getState(shortPrefix); if (Objects.equals(reachedState, reachedSPState)) { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java index b8f34b2c0d..773cb874ec 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java @@ -49,7 +49,7 @@ public Word transformAccessSequence(Word word) { final Object reachedState = hypothesis.getState(word); - for (final Word shortPrefix : observationTable.getShortPrefixes()) { + for (Word shortPrefix : observationTable.getShortPrefixes()) { final Object reachedSPState = hypothesis.getState(shortPrefix); if (Objects.equals(reachedState, reachedSPState)) { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java index d7d10f0ece..c70941b789 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java @@ -23,8 +23,6 @@ import de.learnlib.algorithms.procedural.SymbolWrapper; import net.automatalib.automata.fsa.DFA; import net.automatalib.automata.procedural.SBA; -import net.automatalib.commons.util.mappings.Mapping; -import net.automatalib.ts.simple.SimpleDTS; import net.automatalib.words.ProceduralInputAlphabet; import org.checkerframework.checker.nullness.qual.Nullable; @@ -38,15 +36,15 @@ * * @author frohme */ -class MappingSBA implements SBA, SimpleDTS { +class MappingSBA implements SBA { private final ProceduralInputAlphabet alphabet; - private final Mapping> mapping; + private final Map> mapping; private final SBA> delegate; private final Map> procedures; - MappingSBA(ProceduralInputAlphabet alphabet, Mapping> mapping, SBA> delegate) { + MappingSBA(ProceduralInputAlphabet alphabet, Map> mapping, SBA> delegate) { this.alphabet = alphabet; this.mapping = mapping; this.delegate = delegate; @@ -60,8 +58,9 @@ class MappingSBA implements SBA, SimpleDTS { } @Override - public S getTransition(S state, I i) { - return this.delegate.getTransition(state, this.mapping.get(i)); + public @Nullable S getTransition(S state, I i) { + final SymbolWrapper w = this.mapping.get(i); + return w == null ? null : this.delegate.getTransition(state, w); } @Override @@ -106,10 +105,7 @@ public Collection getStates() { @Override public @Nullable S2 getTransition(S2 s, I i) { final SymbolWrapper w = mapping.get(i); - if (w == null) { - return null; - } - return delegate.getTransition(s, w); + return w == null ? null : delegate.getTransition(s, w); } @Override diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java index 0d5e48547d..ed31196b28 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java @@ -48,7 +48,7 @@ final class ProceduralMembershipOracle implements MembershipOracle, Boolean>> collection) { final List> transformedQueries = new ArrayList<>(collection.size()); - for (final Query, Boolean> q : collection) { + for (Query, Boolean> q : collection) { if (isWellDefined(q)) { transformedQueries.add(new TransformedQuery(q)); } else { @@ -64,8 +64,7 @@ private boolean isWellDefined(Query, Boolean> q) { while (iter.hasNext()) { final SymbolWrapper wrapper = iter.next(); - final I sym = wrapper.getDelegate(); - if (alphabet.isReturnSymbol(sym) || alphabet.isCallSymbol(sym) && !wrapper.isTerminating()) { + if (!wrapper.isContinuable()) { return !iter.hasNext(); } } @@ -83,7 +82,7 @@ private Word transformLocalQuery(Word> query) { final I i = w.getDelegate(); builder.append(i); if (alphabet.isCallSymbol(i) && iter.hasNext()) { - assert w.isTerminating(); + assert w.isContinuable(); builder.append(atManager.getTerminatingSequence(i)); builder.append(alphabet.getReturnSymbol()); } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java index 528257b926..83845272f3 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java @@ -19,10 +19,10 @@ import java.util.Collections; import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import com.google.common.collect.Maps; -import de.learnlib.algorithms.procedural.AlphabetMapper; import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.algorithms.procedural.sba.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; @@ -43,7 +43,6 @@ import net.automatalib.util.automata.procedural.SBAUtil; import net.automatalib.words.Alphabet; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import net.automatalib.words.impl.DefaultProceduralInputAlphabet; @@ -57,40 +56,36 @@ public class SBALearner> & SupportsGrow private final Mapping, Boolean>> learnerConstructors; private final ATManager atManager; - private final Map subLearners; + private final Map learners; private I initialCallSymbol; - private final AlphabetMapper mapper; + private final Map> mapping; - public SBALearner(final ProceduralInputAlphabet alphabet, - final MembershipOracle oracle, - final LearnerConstructor, Boolean> learnerConstructor) { + public SBALearner(ProceduralInputAlphabet alphabet, + MembershipOracle oracle, + LearnerConstructor, Boolean> learnerConstructor) { this(alphabet, oracle, (i) -> learnerConstructor, new OptimizingATManager<>(alphabet)); } - public SBALearner(final ProceduralInputAlphabet alphabet, - final MembershipOracle oracle, - final Mapping, Boolean>> learnerConstructors, - final ATManager atManager) { + public SBALearner(ProceduralInputAlphabet alphabet, + MembershipOracle oracle, + Mapping, Boolean>> learnerConstructors, + ATManager atManager) { this.alphabet = alphabet; this.oracle = oracle; this.learnerConstructors = learnerConstructors; this.atManager = atManager; - this.subLearners = Maps.newHashMapWithExpectedSize(this.alphabet.getNumCalls()); - this.mapper = new AlphabetMapper<>(alphabet); + this.learners = Maps.newHashMapWithExpectedSize(this.alphabet.getNumCalls()); + this.mapping = Maps.newHashMapWithExpectedSize(this.alphabet.size()); - for (I i : this.alphabet.getCallAlphabet()) { - final SymbolWrapper wrapper = new SymbolWrapper<>(i, false, SymbolType.CALL); - this.mapper.set(i, wrapper); - } for (I i : this.alphabet.getInternalAlphabet()) { - final SymbolWrapper wrapper = new SymbolWrapper<>(i, false, SymbolType.INTERNAL); - this.mapper.set(i, wrapper); + final SymbolWrapper wrapper = new SymbolWrapper<>(i, true); + this.mapping.put(i, wrapper); } - final SymbolWrapper wrapper = new SymbolWrapper<>(this.alphabet.getReturnSymbol(), false, SymbolType.RETURN); - this.mapper.set(this.alphabet.getReturnSymbol(), wrapper); + final SymbolWrapper wrapper = new SymbolWrapper<>(this.alphabet.getReturnSymbol(), false); + this.mapping.put(this.alphabet.getReturnSymbol(), wrapper); } @Override @@ -133,7 +128,7 @@ private boolean refineHypothesisInternal(DefaultQuery defaultQuery) this.alphabet.project(input.subWord(callIdx + 1, mismatchIdx), 0).append(input.getSymbol(mismatchIdx)); final DefaultQuery, Boolean> localCE = constructLocalCE(localTrace, defaultQuery.getOutput()); - boolean localRefinement = this.subLearners.get(procedure).refineHypothesis(localCE); + boolean localRefinement = this.learners.get(procedure).refineHypothesis(localCE); assert localRefinement; return true; @@ -142,37 +137,41 @@ private boolean refineHypothesisInternal(DefaultQuery defaultQuery) @Override public SBA getHypothesisModel() { - if (this.subLearners.isEmpty()) { + if (this.learners.isEmpty()) { return new EmptySBA<>(this.alphabet); } - final Map>> procedures = getSubModels(); final Alphabet> internalAlphabet = new GrowingMapAlphabet<>(); final Alphabet> callAlphabet = new GrowingMapAlphabet<>(); + final SymbolWrapper returnSymbol; + + final Map>> procedures = getSubModels(); final Map, DFA>> mappedProcedures = Maps.newHashMapWithExpectedSize(procedures.size()); - for (I i : this.alphabet) { - final SymbolWrapper mappedI = this.mapper.get(i); + for (Entry>> e : procedures.entrySet()) { + final SymbolWrapper w = this.mapping.get(e.getKey()); + assert w != null; + mappedProcedures.put(w, e.getValue()); + callAlphabet.add(w); + } - if (this.alphabet.isCallSymbol(i)) { - callAlphabet.add(mappedI); - final DFA> p = procedures.get(i); - if (p != null) { - mappedProcedures.put(mappedI, p); - } - } else if (alphabet.isInternalSymbol(i)) { - internalAlphabet.add(mappedI); - } + for (I i : this.alphabet.getInternalAlphabet()) { + final SymbolWrapper w = this.mapping.get(i); + assert w != null; + internalAlphabet.add(w); } + returnSymbol = this.mapping.get(alphabet.getReturnSymbol()); + assert returnSymbol != null; + final ProceduralInputAlphabet> mappedAlphabet = - new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, this.mapper.get(alphabet.getReturnSymbol())); + new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); final StackSBA> delegate = - new StackSBA<>(mappedAlphabet, this.mapper.get(initialCallSymbol), mappedProcedures); + new StackSBA<>(mappedAlphabet, this.mapping.get(initialCallSymbol), mappedProcedures); - return new MappingSBA<>(alphabet, mapper, delegate); + return new MappingSBA<>(alphabet, mapping, delegate); } private boolean extractUsefulInformationFromCounterExample(DefaultQuery defaultQuery) { @@ -192,9 +191,9 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery newTerms = newSeqs.getSecond(); for (I call : newTerms) { - final SymbolWrapper sym = new SymbolWrapper<>(call, true, SymbolType.CALL); - this.mapper.set(call, sym); - for (L learner : this.subLearners.values()) { + final SymbolWrapper sym = new SymbolWrapper<>(call, true); + this.mapping.put(call, sym); + for (L learner : this.learners.values()) { learner.addAlphabetSymbol(sym); update = true; } @@ -203,7 +202,7 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery(this.mapper.values()), + .constructLearner(new GrowingMapAlphabet<>(this.mapping.values()), new ProceduralMembershipOracle<>(alphabet, oracle, sym, @@ -212,18 +211,27 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery newTS = this.atManager.scanRefinedProcedures(Collections.singletonMap(sym, newLearner.getHypothesisModel()), - subLearners, - mapper.values()); + learners, + mapping.values()); for (I call : newTS) { - final SymbolWrapper wrapper = new SymbolWrapper<>(call, true, SymbolType.CALL); - this.mapper.set(call, wrapper); - for (L learner : this.subLearners.values()) { + final SymbolWrapper wrapper = new SymbolWrapper<>(call, true); + this.mapping.put(call, wrapper); + for (L learner : this.learners.values()) { + learner.addAlphabetSymbol(wrapper); + } + } + + // add non-terminating version for new call + if (!this.mapping.containsKey(sym)) { + final SymbolWrapper wrapper = new SymbolWrapper<>(sym, false); + this.mapping.put(sym, wrapper); + for (L learner : this.learners.values()) { learner.addAlphabetSymbol(wrapper); } } @@ -233,9 +241,9 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery>> getSubModels() { - final Map>> subModels = Maps.newHashMapWithExpectedSize(this.subLearners.size()); + final Map>> subModels = Maps.newHashMapWithExpectedSize(this.learners.size()); - for (final Map.Entry entry : this.subLearners.entrySet()) { + for (Map.Entry entry : this.learners.entrySet()) { subModels.put(entry.getKey(), entry.getValue().getHypothesisModel()); } @@ -283,7 +291,7 @@ private DefaultQuery, Boolean> constructLocalCE(Word input, final WordBuilder> wb = new WordBuilder<>(input.length()); for (I i : input) { - wb.append(mapper.get(i)); + wb.append(mapping.get(i)); } return new DefaultQuery<>(wb.toWord(), output); @@ -292,15 +300,13 @@ private DefaultQuery, Boolean> constructLocalCE(Word input, private void ensureCallAndReturnClosure() { final Set> nonContinuableSymbols = new HashSet<>(); - nonContinuableSymbols.add(mapper.get(alphabet.getReturnSymbol())); - for (I i : alphabet.getCallAlphabet()) { - final SymbolWrapper mapped = mapper.get(i); - if (!mapped.isTerminating()) { + for (SymbolWrapper mapped : mapping.values()) { + if (!mapped.isContinuable()) { nonContinuableSymbols.add(mapped); } } - for (L learner : this.subLearners.values()) { + for (L learner : this.learners.values()) { boolean stable = false; while (!stable) { @@ -314,7 +320,7 @@ private boolean ensureCallAndReturnClosure(DFA> hyp, L learner) { final Set>> cover = new HashSet<>(); - for (Word> sc : Automata.stateCover(hyp, mapper.values())) { + for (Word> sc : Automata.stateCover(hyp, mapping.values())) { cover.add(learner.transformAccessSequence(sc)); } @@ -324,7 +330,7 @@ private boolean ensureCallAndReturnClosure(DFA> hyp, for (SymbolWrapper i : nonContinuableSymbols) { final S succ = hyp.getSuccessor(state, i); - for (SymbolWrapper next : mapper.values()) { + for (SymbolWrapper next : mapping.values()) { if (hyp.isAccepting(hyp.getSuccessor(succ, next))) { // closure is violated diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java index a4048791fd..5f6d7a17ef 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java @@ -37,7 +37,7 @@ public class DefaultATManager implements ATManager { private final ProceduralInputAlphabet alphabet; - public DefaultATManager(final ProceduralInputAlphabet alphabet) { + public DefaultATManager(ProceduralInputAlphabet alphabet) { this.alphabet = alphabet; this.accessSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java index b27d00dc31..33de297aaa 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java @@ -21,6 +21,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import com.google.common.collect.Maps; @@ -32,7 +33,6 @@ import net.automatalib.commons.util.Pair; import net.automatalib.util.automata.cover.Covers; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import org.checkerframework.checker.nullness.qual.Nullable; @@ -44,7 +44,7 @@ public class OptimizingATManager implements ATManager { private final ProceduralInputAlphabet alphabet; - public OptimizingATManager(final ProceduralInputAlphabet alphabet) { + public OptimizingATManager(ProceduralInputAlphabet alphabet) { this.alphabet = alphabet; this.accessSequences = Maps.newHashMapWithExpectedSize(alphabet.getNumCalls()); @@ -85,7 +85,8 @@ public Set scanRefinedProcedures(Map>> p if (!procedures.isEmpty()) { final SymbolWrapper returnSymbol = inputs.stream() - .filter(i -> i.getType() == SymbolType.RETURN) + .filter(i -> Objects.equals(i.getDelegate(), + alphabet.getReturnSymbol())) .findAny() .orElseThrow(IllegalArgumentException::new); boolean foundImprovements = false; @@ -145,8 +146,8 @@ public Set scanRefinedProcedures(Map>> p return result; } - private void optimizeSequences(final Map> sequences) { - for (final Map.Entry> entry : sequences.entrySet()) { + private void optimizeSequences(Map> sequences) { + for (Map.Entry> entry : sequences.entrySet()) { final Word currentSequence = entry.getValue(); final Word minimized = minifyWellMatched(currentSequence); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java index 68c9291b77..70958a98f8 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java @@ -23,7 +23,6 @@ import de.learnlib.algorithms.procedural.SymbolWrapper; import net.automatalib.automata.procedural.SPMM; import net.automatalib.automata.transducers.MealyMachine; -import net.automatalib.commons.util.mappings.Mapping; import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.ProceduralOutputAlphabet; import org.checkerframework.checker.nullness.qual.Nullable; @@ -42,14 +41,14 @@ class MappingSPMM implements SPMM { private final ProceduralInputAlphabet inputAlphabet; private final ProceduralOutputAlphabet outputAlphabet; - private final Mapping> mapping; + private final Map> mapping; private final SPMM, T, O> delegate; private final Map> procedures; MappingSPMM(ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet, - Mapping> mapping, + Map> mapping, SPMM, T, O> delegate) { this.inputAlphabet = inputAlphabet; this.outputAlphabet = outputAlphabet; @@ -65,8 +64,9 @@ class MappingSPMM implements SPMM { } @Override - public T getTransition(S state, I i) { - return this.delegate.getTransition(state, this.mapping.get(i)); + public @Nullable T getTransition(S state, I i) { + final SymbolWrapper w = this.mapping.get(i); + return w == null ? null : this.delegate.getTransition(state, w); } @Override @@ -126,10 +126,7 @@ public O getTransitionOutput(T2 t2) { @Override public @Nullable T2 getTransition(S2 s2, I i) { final SymbolWrapper w = mapping.get(i); - if (w == null) { - return null; - } - return delegate.getTransition(s2, w); + return w == null ? null : delegate.getTransition(s2, w); } @Override diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java index 8233e66823..8f345a91d2 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java @@ -53,7 +53,7 @@ final class ProceduralMembershipOracle implements MembershipOracle, Word>> collection) { final List>> transformedQueries = new ArrayList<>(collection.size()); - for (final Query, Word> q : collection) { + for (Query, Word> q : collection) { if (hasErrorInPrefix(q.getPrefix())) { q.answer(Word.fromList(Collections.nCopies(q.getSuffix().length(), errorSymbol))); } else { @@ -68,7 +68,7 @@ private Word transformPrefix(Word> query) { final WordBuilder builder = new WordBuilder<>(); builder.append(atManager.getAccessSequence(this.procedure)); - for (final SymbolWrapper wrapper : query) { + for (SymbolWrapper wrapper : query) { final I i = wrapper.getDelegate(); if (alphabet.isInternalSymbol(i)) { builder.append(i); @@ -87,14 +87,14 @@ private Word transformPrefix(Word> query) { private Word transformSuffix(Word> query, BitSet indices) { final WordBuilder builder = new WordBuilder<>(); - for (final SymbolWrapper wrapper : query) { + for (SymbolWrapper wrapper : query) { final I i = wrapper.getDelegate(); indices.set(builder.size()); if (alphabet.isInternalSymbol(i)) { builder.append(i); } else if (alphabet.isCallSymbol(i)) { builder.append(i); - if (wrapper.isTerminating()) { + if (wrapper.isContinuable()) { builder.append(atManager.getTerminatingSequence(i)); builder.append(alphabet.getReturnSymbol()); } else { @@ -112,8 +112,7 @@ private Word transformSuffix(Word> query, BitSet indices) { private boolean hasErrorInPrefix(Word> prefix) { for (SymbolWrapper wrapper : prefix) { - final I i = wrapper.getDelegate(); - if (alphabet.isReturnSymbol(i) || alphabet.isCallSymbol(i) && !wrapper.isTerminating()) { + if (!wrapper.isContinuable()) { return true; } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java index ff75b84c1d..9218d6071f 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java @@ -20,11 +20,11 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import com.google.common.collect.Maps; -import de.learnlib.algorithms.procedural.AlphabetMapper; import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.algorithms.procedural.spmm.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; @@ -46,7 +46,6 @@ import net.automatalib.words.Alphabet; import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.ProceduralOutputAlphabet; -import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import net.automatalib.words.impl.DefaultProceduralInputAlphabet; @@ -65,7 +64,7 @@ public class SPMMLearner, O> & Sup private I initialCallSymbol; private O initialOutputSymbol; - private final AlphabetMapper mapper; + private final Map> mapping; public SPMMLearner(ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet, @@ -90,20 +89,15 @@ public SPMMLearner(ProceduralInputAlphabet inputAlphabet, this.atManager = atManager; this.learners = Maps.newHashMapWithExpectedSize(this.inputAlphabet.getNumCalls()); - this.mapper = new AlphabetMapper<>(inputAlphabet); + this.mapping = Maps.newHashMapWithExpectedSize(this.inputAlphabet.size()); - for (I i : this.inputAlphabet.getCallAlphabet()) { - final SymbolWrapper wrapper = new SymbolWrapper<>(i, false, SymbolType.CALL); - this.mapper.set(i, wrapper); - } for (I i : this.inputAlphabet.getInternalAlphabet()) { - final SymbolWrapper wrapper = new SymbolWrapper<>(i, false, SymbolType.INTERNAL); - this.mapper.set(i, wrapper); + final SymbolWrapper wrapper = new SymbolWrapper<>(i, true); + this.mapping.put(i, wrapper); } - final SymbolWrapper wrapper = - new SymbolWrapper<>(this.inputAlphabet.getReturnSymbol(), false, SymbolType.RETURN); - this.mapper.set(this.inputAlphabet.getReturnSymbol(), wrapper); + final SymbolWrapper wrapper = new SymbolWrapper<>(this.inputAlphabet.getReturnSymbol(), false); + this.mapping.put(this.inputAlphabet.getReturnSymbol(), wrapper); } @Override @@ -150,10 +144,7 @@ private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) final DefaultQuery, Word> localCE = constructLocalCE(localTraces.getFirst(), localTraces.getSecond()); final boolean localRefinement = this.learners.get(procedure).refineHypothesis(localCE); - - if (!localRefinement) { - throw new AssertionError(); - } + assert localRefinement; return true; } @@ -165,37 +156,40 @@ private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) return new EmptySPMM<>(this.inputAlphabet, outputAlphabet); } - final Map, ?, O>> procedures = getSubModels(); final Alphabet> internalAlphabet = new GrowingMapAlphabet<>(); final Alphabet> callAlphabet = new GrowingMapAlphabet<>(); + final SymbolWrapper returnSymbol; + + final Map, ?, O>> procedures = getSubModels(); final Map, MealyMachine, ?, O>> mappedProcedures = Maps.newHashMapWithExpectedSize(procedures.size()); - for (I i : this.inputAlphabet) { - final SymbolWrapper mappedI = this.mapper.get(i); + for (Entry, ?, O>> e : procedures.entrySet()) { + final SymbolWrapper w = this.mapping.get(e.getKey()); + assert w != null; + mappedProcedures.put(w, e.getValue()); + callAlphabet.add(w); + } - if (this.inputAlphabet.isCallSymbol(i)) { - callAlphabet.add(mappedI); - final MealyMachine, ?, O> p = procedures.get(i); - if (p != null) { - mappedProcedures.put(mappedI, p); - } - } else if (inputAlphabet.isInternalSymbol(i)) { - internalAlphabet.add(mappedI); - } + for (I i : this.inputAlphabet.getInternalAlphabet()) { + final SymbolWrapper w = this.mapping.get(i); + assert w != null; + internalAlphabet.add(w); } - final ProceduralInputAlphabet> mappedAlphabet = new DefaultProceduralInputAlphabet<>(internalAlphabet, - callAlphabet, - this.mapper.get(inputAlphabet.getReturnSymbol())); + returnSymbol = this.mapping.get(inputAlphabet.getReturnSymbol()); + assert returnSymbol != null; + + final ProceduralInputAlphabet> mappedAlphabet = + new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); final StackSPMM, ?, O> delegate = new StackSPMM<>(mappedAlphabet, outputAlphabet, - this.mapper.get(initialCallSymbol), + this.mapping.get(initialCallSymbol), initialOutputSymbol, mappedProcedures); - return new MappingSPMM<>(inputAlphabet, outputAlphabet, mapper, delegate); + return new MappingSPMM<>(inputAlphabet, outputAlphabet, mapping, delegate); } private boolean extractUsefulInformationFromCounterExample(DefaultQuery> defaultQuery) { @@ -214,8 +208,8 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery sym = new SymbolWrapper<>(call, true, SymbolType.CALL); - this.mapper.set(call, sym); + final SymbolWrapper sym = new SymbolWrapper<>(call, true); + this.mapping.put(call, sym); for (L learner : this.learners.values()) { learner.addAlphabetSymbol(sym); update = true; @@ -225,7 +219,7 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery(this.mapper.values()), + .constructLearner(new GrowingMapAlphabet<>(this.mapping.values()), new ProceduralMembershipOracle<>(inputAlphabet, oracle, sym, @@ -241,11 +235,20 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery newTS = this.atManager.scanRefinedProcedures(Collections.singletonMap(sym, newLearner.getHypothesisModel()), learners, - mapper.values()); + mapping.values()); for (I call : newTS) { - final SymbolWrapper wrapper = new SymbolWrapper<>(call, true, SymbolType.CALL); - this.mapper.set(call, wrapper); + final SymbolWrapper wrapper = new SymbolWrapper<>(call, true); + this.mapping.put(call, wrapper); + for (L learner : this.learners.values()) { + learner.addAlphabetSymbol(wrapper); + } + } + + // add non-terminating version for new call + if (!this.mapping.containsKey(sym)) { + final SymbolWrapper wrapper = new SymbolWrapper<>(sym, false); + this.mapping.put(sym, wrapper); for (L learner : this.learners.values()) { learner.addAlphabetSymbol(wrapper); } @@ -259,7 +262,7 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery, ?, O>> subModels = Maps.newHashMapWithExpectedSize(this.learners.size()); - for (final Map.Entry entry : this.learners.entrySet()) { + for (Map.Entry entry : this.learners.entrySet()) { subModels.put(entry.getKey(), entry.getValue().getHypothesisModel()); } @@ -270,7 +273,7 @@ private DefaultQuery, Word> constructLocalCE(Word input, final WordBuilder> wb = new WordBuilder<>(input.length()); for (I i : input) { - wb.append(mapper.get(i)); + wb.append(mapping.get(i)); } return new DefaultQuery<>(wb.toWord(), output); @@ -281,7 +284,7 @@ private void ensureReturnClosure() { boolean stable = false; while (!stable) { - stable = ensureReturnClosure(learner.getHypothesisModel(), mapper.values(), learner); + stable = ensureReturnClosure(learner.getHypothesisModel(), mapping.values(), learner); } } } @@ -299,7 +302,7 @@ private boolean ensureReturnClosure(MealyMachine, T, final S state = hyp.getState(cov); for (SymbolWrapper i : inputs) { - if (i.getType() == SymbolType.RETURN) { + if (Objects.equals(i.getDelegate(), inputAlphabet.getReturnSymbol())) { final S succ = hyp.getSuccessor(state, i); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java index 717806158a..ca010d975d 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java @@ -40,7 +40,7 @@ public class DefaultATManager implements ATManager { private final ProceduralInputAlphabet inputAlphabet; private final ProceduralOutputAlphabet outputAlphabet; - public DefaultATManager(final ProceduralInputAlphabet inputAlphabet, final ProceduralOutputAlphabet outputAlphabet) { + public DefaultATManager(ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet) { this.inputAlphabet = inputAlphabet; this.outputAlphabet = outputAlphabet; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java index 68d188e579..5981672444 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; import com.google.common.collect.Maps; @@ -35,7 +36,6 @@ import net.automatalib.util.automata.cover.Covers; import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.ProceduralOutputAlphabet; -import net.automatalib.words.VPDAlphabet.SymbolType; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import org.checkerframework.checker.nullness.qual.Nullable; @@ -48,7 +48,7 @@ public class OptimizingATManager implements ATManager { private final ProceduralInputAlphabet inputAlphabet; private final ProceduralOutputAlphabet outputAlphabet; - public OptimizingATManager(final ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet) { + public OptimizingATManager(ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet) { this.inputAlphabet = inputAlphabet; this.outputAlphabet = outputAlphabet; @@ -89,7 +89,8 @@ public Set scanRefinedProcedures(Map returnSymbol = inputs.stream() - .filter(i -> i.getType() == SymbolType.RETURN) + .filter(i -> Objects.equals(i.getDelegate(), + inputAlphabet.getReturnSymbol())) .findAny() .orElseThrow(IllegalArgumentException::new); boolean foundImprovements = false; @@ -150,8 +151,8 @@ public Set scanRefinedProcedures(Map> sequences) { - for (final Entry> entry : sequences.entrySet()) { + private void optimizeSequences(Map> sequences) { + for (Entry> entry : sequences.entrySet()) { final Word currentSequence = entry.getValue(); final Word minimized = minifyWellMatched(currentSequence); @@ -161,8 +162,7 @@ private void optimizeSequences(final Map> sequences) { } } - private void extractPotentialTerminatingSequences(final DefaultQuery> counterexample, - final Set newProcedures) { + private void extractPotentialTerminatingSequences(DefaultQuery> counterexample, Set newProcedures) { final Word input = counterexample.getInput(); final Word output = counterexample.getOutput(); @@ -189,7 +189,7 @@ private void extractPotentialTerminatingSequences(final DefaultQuery> } } - private void extractPotentialAccessSequences(final DefaultQuery> counterexample, final Set newCalls) { + private void extractPotentialAccessSequences(DefaultQuery> counterexample, Set newCalls) { final Word input = counterexample.getInput(); final Word output = counterexample.getOutput(); From 18a754ee114eff9f50d0eb6faba8841a1a45a17f Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 18 Aug 2023 01:29:34 +0200 Subject: [PATCH 07/15] make counterexample analysis parameterizable --- .../algorithms/procedural/sba/SBALearner.java | 78 +++++----- .../algorithms/procedural/spa/SPALearner.java | 137 +++++++++--------- .../algorithms/procedural/sba/SBAIT.java | 15 +- .../algorithms/procedural/spa/SPAIT.java | 18 ++- 4 files changed, 131 insertions(+), 117 deletions(-) diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java index 83845272f3..9b724c57cf 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java @@ -20,9 +20,14 @@ import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; +import java.util.function.Predicate; import com.google.common.collect.Maps; +import de.learnlib.acex.AcexAnalyzer; +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.acex.impl.AbstractBaseCounterexample; import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.algorithms.procedural.sba.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; @@ -54,6 +59,7 @@ public class SBALearner> & SupportsGrow private final ProceduralInputAlphabet alphabet; private final MembershipOracle oracle; private final Mapping, Boolean>> learnerConstructors; + private final AcexAnalyzer analyzer; private final ATManager atManager; private final Map learners; @@ -64,16 +70,22 @@ public class SBALearner> & SupportsGrow public SBALearner(ProceduralInputAlphabet alphabet, MembershipOracle oracle, LearnerConstructor, Boolean> learnerConstructor) { - this(alphabet, oracle, (i) -> learnerConstructor, new OptimizingATManager<>(alphabet)); + this(alphabet, + oracle, + (i) -> learnerConstructor, + AcexAnalyzers.BINARY_SEARCH_BWD, + new OptimizingATManager<>(alphabet)); } public SBALearner(ProceduralInputAlphabet alphabet, MembershipOracle oracle, Mapping, Boolean>> learnerConstructors, + AcexAnalyzer analyzer, ATManager atManager) { this.alphabet = alphabet; this.oracle = oracle; this.learnerConstructors = learnerConstructors; + this.analyzer = analyzer; this.atManager = atManager; this.learners = Maps.newHashMapWithExpectedSize(this.alphabet.getNumCalls()); @@ -118,7 +130,10 @@ private boolean refineHypothesisInternal(DefaultQuery defaultQuery) } final Word input = defaultQuery.getInput(); - final int mismatchIdx = detectMismatchingIdx(hypothesis, input, defaultQuery.getOutput()); + final int mismatchIdx = analyzer.analyzeAbstractCounterexample(new Acex<>(input, + defaultQuery.getOutput() ? + hypothesis::accepts : + this.oracle::answerQuery)); // extract local ce final int callIdx = this.alphabet.findCallIndex(input, mismatchIdx); @@ -250,43 +265,6 @@ private Map>> getSubModels() { return subModels; } - private int detectMismatchingIdx(SBA sba, Word input, boolean output) { - - if (output) { - S stateIter = sba.getInitialState(); - int idx = 0; - - for (I i : input) { - final S succ = sba.getSuccessor(stateIter, i); - - if (succ == null || !sba.isAccepting(succ)) { - return idx; - } - stateIter = succ; - idx++; - } - } else { - int lower = 0; - int upper = input.size() - 1; - int result = input.size(); - - while (upper - lower > -1) { - int mid = lower + (upper - lower) / 2; - boolean answer = this.oracle.answerQuery(input.prefix(mid)); - if (answer) { - lower = mid + 1; - } else { - result = mid; - upper = mid - 1; - } - } - - return result - 1; - } - - throw new IllegalStateException("Could not properly analyze CE"); - } - private DefaultQuery, Boolean> constructLocalCE(Word input, boolean output) { final WordBuilder> wb = new WordBuilder<>(input.length()); @@ -347,4 +325,26 @@ private boolean ensureCallAndReturnClosure(DFA> hyp, return true; } + + private static class Acex extends AbstractBaseCounterexample { + + private final Word input; + private final Predicate> oracle; + + Acex(Word input, Predicate> oracle) { + super(input.size() + 1); + this.input = input; + this.oracle = oracle; + } + + @Override + protected Boolean computeEffect(int index) { + return oracle.test(input.prefix(index)); + } + + @Override + public boolean checkEffects(Boolean eff1, Boolean eff2) { + return Objects.equals(eff1, eff2); + } + } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java index ca789b30d1..108b788913 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java @@ -21,11 +21,15 @@ import java.util.Deque; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Predicate; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import de.learnlib.acex.AcexAnalyzer; +import de.learnlib.acex.analyzers.AcexAnalyzers; +import de.learnlib.acex.impl.AbstractBaseCounterexample; import de.learnlib.algorithms.procedural.spa.manager.OptimizingATRManager; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.algorithm.LearnerConstructor; @@ -62,6 +66,7 @@ public class SPALearner & SupportsGrowingAlphabet private final ProceduralInputAlphabet alphabet; private final MembershipOracle oracle; private final Mapping> learnerConstructors; + private final AcexAnalyzer analyzer; private final ATRManager atrManager; private final Map subLearners; @@ -77,16 +82,22 @@ public SPALearner(ProceduralInputAlphabet alphabet, public SPALearner(ProceduralInputAlphabet alphabet, MembershipOracle oracle, Mapping> learnerConstructors) { - this(alphabet, oracle, learnerConstructors, new OptimizingATRManager<>(alphabet)); + this(alphabet, + oracle, + learnerConstructors, + AcexAnalyzers.BINARY_SEARCH_FWD, + new OptimizingATRManager<>(alphabet)); } public SPALearner(ProceduralInputAlphabet alphabet, MembershipOracle oracle, Mapping> learnerConstructors, + AcexAnalyzer analyzer, ATRManager atrManager) { this.alphabet = alphabet; this.oracle = oracle; this.learnerConstructors = learnerConstructors; + this.analyzer = analyzer; this.atrManager = atrManager; this.subLearners = Maps.newHashMapWithExpectedSize(this.alphabet.getNumCalls()); @@ -119,19 +130,22 @@ private boolean refineHypothesisInternal(DefaultQuery defaultQuery) return false; } - final Word input = defaultQuery.getInput(); - // look for better sequences and ensure TS conformance prior to CE analysis boolean localRefinement = updateATRAndCheckTSConformance(hypothesis); - final int returnIdx; - - if (defaultQuery.getOutput()) { - returnIdx = detectRejectingProcedure(getHypothesisModel()::accepts, input); - } else { - returnIdx = detectRejectingProcedure(this.oracle::answerQuery, input); + if (!MQUtil.isCounterexample(defaultQuery, hypothesis)) { + return localRefinement; } + final Word input = defaultQuery.getInput(); + final List returnIndices = determineReturnIndices(input); + final int idx = analyzer.analyzeAbstractCounterexample(new Acex(input, + defaultQuery.getOutput() ? + hypothesis::accepts : + this.oracle::answerQuery, + returnIndices)); + final int returnIdx = returnIndices.get(idx); + // extract local ce final int callIdx = this.alphabet.findCallIndex(input, returnIdx); final I procedure = input.getSymbol(callIdx); @@ -228,7 +242,7 @@ private boolean updateATRAndCheckTSConformance(SPA hypothesis) { return refinement; } - private int detectRejectingProcedure(Predicate> rejectingSystem, Word input) { + private List determineReturnIndices(Word input) { final List returnIndices = new ArrayList<>(); @@ -238,64 +252,7 @@ private int detectRejectingProcedure(Predicate> rejectingSystem, Word } } - // skip last index, because we know its accepting - int returnIdxPos = findLowestAcceptingReturnIndex(rejectingSystem, - input, - returnIndices.subList(0, returnIndices.size() - 1)); - - // if everything is rejecting the error happens at the main procedure - if (returnIdxPos == -1) { - returnIdxPos = returnIndices.size() - 1; - } - - return returnIndices.get(returnIdxPos); - } - - private int findLowestAcceptingReturnIndex(Predicate> system, - Word input, - List returnIndices) { - - int lower = 0; - int upper = returnIndices.size() - 1; - int result = -1; - - while (upper - lower > -1) { - final int mid = lower + ((upper - lower) / 2); - final int returnIdx = returnIndices.get(mid); - - final boolean answer = acceptsDecomposition(system, input, returnIdx + 1); - - if (answer) { - result = mid; - upper = mid - 1; - } else { - lower = mid + 1; - } - } - - return result; - } - - private boolean acceptsDecomposition(Predicate> system, Word input, int idxAfterReturn) { - final Deque> wordStack = new ArrayDeque<>(); - int idx = idxAfterReturn; - - while (idx > 0) { - final int callIdx = this.alphabet.findCallIndex(input, idx); - final I callSymbol = input.getSymbol(callIdx); - final Word normalized = this.alphabet.project(input.subWord(callIdx + 1, idx), 0); - final Word expanded = this.alphabet.expand(normalized, this.atrManager::getTerminatingSequence); - - wordStack.push(expanded.prepend(callSymbol)); - - idx = callIdx; - } - - final WordBuilder builder = new WordBuilder<>(); - wordStack.forEach(builder::append); - builder.append(input.subWord(idxAfterReturn)); - - return system.test(builder.toWord()); + return returnIndices; } private boolean checkAndEnsureTSConformance(Map> subModels) { @@ -337,4 +294,48 @@ private boolean checkSingleTerminatingSequence(Word input, Map> return refinement; } + private class Acex extends AbstractBaseCounterexample { + + private final Word input; + private final Predicate> oracle; + private final List returnIndices; + + Acex(Word input, Predicate> oracle, List returnIndices) { + super(returnIndices.size() + 1); + this.input = input; + this.oracle = oracle; + this.returnIndices = returnIndices; + + setEffect(returnIndices.size(), true); + setEffect(0, false); + } + + @Override + protected Boolean computeEffect(int index) { + final Deque> wordStack = new ArrayDeque<>(); + int idx = this.returnIndices.get(index); + + while (idx > 0) { + final int callIdx = alphabet.findCallIndex(input, idx); + final I callSymbol = input.getSymbol(callIdx); + final Word normalized = alphabet.project(input.subWord(callIdx + 1, idx), 0); + final Word expanded = alphabet.expand(normalized, atrManager::getTerminatingSequence); + + wordStack.push(expanded.prepend(callSymbol)); + + idx = callIdx; + } + + final WordBuilder builder = new WordBuilder<>(); + wordStack.forEach(builder::append); + builder.append(input.subWord(this.returnIndices.get(index))); + + return oracle.test(builder.toWord()); + } + + @Override + public boolean checkEffects(Boolean eff1, Boolean eff2) { + return Objects.equals(eff1, eff2); + } + } } diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java index 3eff3bbc9b..0cdd616b8e 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java @@ -19,6 +19,8 @@ import java.util.List; import java.util.function.Function; +import de.learnlib.acex.analyzers.AbstractNamedAcexAnalyzer; +import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.algorithms.procedural.adapter.dfa.DiscriminationTreeAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.KearnsVaziraniAdapterDFA; @@ -69,11 +71,14 @@ private static class Builder { > & SupportsGrowingAlphabet> & AccessSequenceTransformer>> void addLearnerVariant( LearnerConstructor, Boolean> provider) { - for (Function, ATManager> atProvider : atProviders) { - final SBALearner learner = - new SBALearner<>(alphabet, mqOracle, (i) -> provider, atProvider.apply(alphabet)); - final String name = String.format("adapter=%s,manager=%s", provider, atProvider); - variants.addLearnerVariant(name, learner); + for (AbstractNamedAcexAnalyzer analyzer : AcexAnalyzers.getAllAnalyzers()) { + for (Function, ATManager> atProvider : atProviders) { + final SBALearner learner = + new SBALearner<>(alphabet, mqOracle, (i) -> provider, analyzer, atProvider.apply(alphabet)); + final String name = + String.format("adapter=%s,analyzer=%s,manager=%s", provider, analyzer, atProvider); + variants.addLearnerVariant(name, learner); + } } } } diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java index 860f004d9f..bfe7dc6503 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java @@ -19,6 +19,8 @@ import java.util.List; import java.util.function.Function; +import de.learnlib.acex.analyzers.AbstractNamedAcexAnalyzer; +import de.learnlib.acex.analyzers.AcexAnalyzers; import de.learnlib.algorithms.procedural.adapter.dfa.DiscriminationTreeAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.KearnsVaziraniAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.LStarBaseAdapterDFA; @@ -68,11 +70,17 @@ private static class Builder { & SupportsGrowingAlphabet & AccessSequenceTransformer> void addLearnerVariant( LearnerConstructor provider) { - for (Function, ATRManager> atrProvider : atrProviders) { - final SPALearner learner = - new SPALearner<>(alphabet, mqOracle, (i) -> provider, atrProvider.apply(alphabet)); - final String name = String.format("adapter=%s,manager=%s", provider, atrProvider); - variants.addLearnerVariant(name, learner); + for (AbstractNamedAcexAnalyzer analyzer : AcexAnalyzers.getAllAnalyzers()) { + for (Function, ATRManager> atrProvider : atrProviders) { + final SPALearner learner = new SPALearner<>(alphabet, + mqOracle, + (i) -> provider, + analyzer, + atrProvider.apply(alphabet)); + final String name = + String.format("adapter=%s,analyzer=%s,manager=%s", provider, analyzer, atrProvider); + variants.addLearnerVariant(name, learner); + } } } } From 852cd976655e4fbcd1343e18bd4543ba83d5ba12 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 25 Aug 2023 11:08:30 +0200 Subject: [PATCH 08/15] add adapters for OML and DHC --- algorithms/active/procedural/pom.xml | 12 ++++- .../adapter/dfa/OptimalTTTAdapterDFA.java | 49 ++++++++++++++++++ .../adapter/mealy/DHCAdapterMealy.java | 43 ++++++++++++++++ .../adapter/mealy/OptimalTTTAdapterMealy.java | 51 +++++++++++++++++++ .../algorithms/procedural/sba/SBAIT.java | 2 + .../algorithms/procedural/spa/SPAIT.java | 2 + .../algorithms/procedural/spmm/SPMMIT.java | 4 ++ 7 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/OptimalTTTAdapterDFA.java create mode 100644 algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DHCAdapterMealy.java create mode 100644 algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/OptimalTTTAdapterMealy.java diff --git a/algorithms/active/procedural/pom.xml b/algorithms/active/procedural/pom.xml index 198db8adec..df5c8cea01 100644 --- a/algorithms/active/procedural/pom.xml +++ b/algorithms/active/procedural/pom.xml @@ -48,11 +48,15 @@ limitations under the License. de.learnlib - learnlib-discrimination-tree + learnlib-datastructure-ot de.learnlib - learnlib-datastructure-ot + learnlib-dhc + + + de.learnlib + learnlib-discrimination-tree de.learnlib @@ -62,6 +66,10 @@ limitations under the License. de.learnlib learnlib-lstar + + de.learnlib + learnlib-oml + de.learnlib learnlib-ttt diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/OptimalTTTAdapterDFA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/OptimalTTTAdapterDFA.java new file mode 100644 index 0000000000..55ccbd3fdb --- /dev/null +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/OptimalTTTAdapterDFA.java @@ -0,0 +1,49 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.procedural.adapter.dfa; + +import java.util.List; + +import de.learnlib.algorithms.oml.ttt.dfa.OptimalTTTDFA; +import de.learnlib.algorithms.oml.ttt.pt.PTNode; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * Adapter for using {@link OptimalTTTDFA} as a sub-procedural learner. + * + * @param + * input symbol type + * + * @author frohme + */ +public class OptimalTTTAdapterDFA extends OptimalTTTDFA implements AccessSequenceTransformer { + + public OptimalTTTAdapterDFA(Alphabet alphabet, MembershipOracle oracle) { + super(alphabet, oracle); + } + + @Override + public Word transformAccessSequence(Word word) { + final List> shortPrefixes = super.getState(word).getShortPrefixes(); + + assert shortPrefixes.size() == 1; + + return shortPrefixes.get(0).word(); + } +} diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DHCAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DHCAdapterMealy.java new file mode 100644 index 0000000000..bbc5433a90 --- /dev/null +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DHCAdapterMealy.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.procedural.adapter.mealy; + +import java.util.Collections; + +import de.learnlib.algorithms.dhc.mealy.MealyDHC; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.oracle.MembershipOracle; +import de.learnlib.counterexamples.GlobalSuffixFinders; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * Adapter for using {@link MealyDHC} as a sub-procedural learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +public class DHCAdapterMealy extends MealyDHC implements AccessSequenceTransformer { + + public DHCAdapterMealy(Alphabet alphabet, MembershipOracle> oracle) { + super(alphabet, oracle, GlobalSuffixFinders.RIVEST_SCHAPIRE, Collections.emptyList()); + } + +} diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/OptimalTTTAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/OptimalTTTAdapterMealy.java new file mode 100644 index 0000000000..dd205aeae5 --- /dev/null +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/OptimalTTTAdapterMealy.java @@ -0,0 +1,51 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.procedural.adapter.mealy; + +import java.util.List; + +import de.learnlib.algorithms.oml.ttt.mealy.OptimalTTTMealy; +import de.learnlib.algorithms.oml.ttt.pt.PTNode; +import de.learnlib.api.AccessSequenceTransformer; +import de.learnlib.api.oracle.MembershipOracle; +import net.automatalib.words.Alphabet; +import net.automatalib.words.Word; + +/** + * Adapter for using {@link OptimalTTTMealy} as a sub-procedural learner. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ +public class OptimalTTTAdapterMealy extends OptimalTTTMealy implements AccessSequenceTransformer { + + public OptimalTTTAdapterMealy(Alphabet alphabet, MembershipOracle> oracle) { + super(alphabet, oracle); + } + + @Override + public Word transformAccessSequence(Word word) { + final List>> shortPrefixes = super.getState(word).getShortPrefixes(); + + assert shortPrefixes.size() == 1; + + return shortPrefixes.get(0).word(); + } +} diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java index 0cdd616b8e..a6408250ba 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java @@ -25,6 +25,7 @@ import de.learnlib.algorithms.procedural.adapter.dfa.DiscriminationTreeAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.KearnsVaziraniAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.LStarBaseAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.OptimalTTTAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.RivestSchapireAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.TTTAdapterDFA; import de.learnlib.algorithms.procedural.sba.manager.DefaultATManager; @@ -50,6 +51,7 @@ protected void addLearnerVariants(ProceduralInputAlphabet alphabet, builder.addLearnerVariant(DiscriminationTreeAdapterDFA::new); builder.addLearnerVariant(KearnsVaziraniAdapterDFA::new); builder.addLearnerVariant(LStarBaseAdapterDFA::new); + builder.addLearnerVariant(OptimalTTTAdapterDFA::new); builder.addLearnerVariant(RivestSchapireAdapterDFA::new); builder.addLearnerVariant(TTTAdapterDFA::new); } diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java index bfe7dc6503..6880c69719 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java @@ -24,6 +24,7 @@ import de.learnlib.algorithms.procedural.adapter.dfa.DiscriminationTreeAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.KearnsVaziraniAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.LStarBaseAdapterDFA; +import de.learnlib.algorithms.procedural.adapter.dfa.OptimalTTTAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.RivestSchapireAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.TTTAdapterDFA; import de.learnlib.algorithms.procedural.spa.manager.DefaultATRManager; @@ -49,6 +50,7 @@ protected void addLearnerVariants(ProceduralInputAlphabet alphabet, builder.addLearnerVariant(DiscriminationTreeAdapterDFA::new); builder.addLearnerVariant(KearnsVaziraniAdapterDFA::new); builder.addLearnerVariant(LStarBaseAdapterDFA::new); + builder.addLearnerVariant(OptimalTTTAdapterDFA::new); builder.addLearnerVariant(RivestSchapireAdapterDFA::new); builder.addLearnerVariant(TTTAdapterDFA::new); } diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java index 1dd91ec158..105a53b686 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java @@ -20,9 +20,11 @@ import java.util.function.BiFunction; import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.adapter.mealy.DHCAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.DiscriminationTreeAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.KearnsVaziraniAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.LStarBaseAdapterMealy; +import de.learnlib.algorithms.procedural.adapter.mealy.OptimalTTTAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.RivestSchapireAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.TTTAdapterMealy; import de.learnlib.algorithms.procedural.spmm.manager.DefaultATManager; @@ -49,8 +51,10 @@ protected void addLearnerVariants(ProceduralInputAlphabet alphabet, final Builder builder = new Builder<>(alphabet, outputAlphabet, mqOracle, variants); builder.addLearnerVariant(DiscriminationTreeAdapterMealy::new); + builder.addLearnerVariant(DHCAdapterMealy::new); builder.addLearnerVariant(KearnsVaziraniAdapterMealy::new); builder.addLearnerVariant(LStarBaseAdapterMealy::new); + builder.addLearnerVariant(OptimalTTTAdapterMealy::new); builder.addLearnerVariant(RivestSchapireAdapterMealy::new); builder.addLearnerVariant(TTTAdapterMealy::new); } From 64a0fee30ad71ad6acde939c8527021be628d5c1 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Fri, 25 Aug 2023 11:10:59 +0200 Subject: [PATCH 09/15] Only use DHC for testing Since the adapter does not provide any functionality, skip redundant adapter class. --- algorithms/active/procedural/pom.xml | 9 ++-- .../adapter/mealy/DHCAdapterMealy.java | 43 ------------------- .../algorithms/procedural/spmm/SPMMIT.java | 4 +- 3 files changed, 7 insertions(+), 49 deletions(-) delete mode 100644 algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DHCAdapterMealy.java diff --git a/algorithms/active/procedural/pom.xml b/algorithms/active/procedural/pom.xml index df5c8cea01..54e3378d73 100644 --- a/algorithms/active/procedural/pom.xml +++ b/algorithms/active/procedural/pom.xml @@ -50,10 +50,6 @@ limitations under the License. de.learnlib learnlib-datastructure-ot - - de.learnlib - learnlib-dhc - de.learnlib learnlib-discrimination-tree @@ -114,6 +110,11 @@ limitations under the License. + + de.learnlib + learnlib-dhc + test + de.learnlib learnlib-drivers-simulator diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DHCAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DHCAdapterMealy.java deleted file mode 100644 index bbc5433a90..0000000000 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DHCAdapterMealy.java +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (C) 2013-2023 TU Dortmund - * This file is part of LearnLib, http://www.learnlib.de/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.learnlib.algorithms.procedural.adapter.mealy; - -import java.util.Collections; - -import de.learnlib.algorithms.dhc.mealy.MealyDHC; -import de.learnlib.api.AccessSequenceTransformer; -import de.learnlib.api.oracle.MembershipOracle; -import de.learnlib.counterexamples.GlobalSuffixFinders; -import net.automatalib.words.Alphabet; -import net.automatalib.words.Word; - -/** - * Adapter for using {@link MealyDHC} as a sub-procedural learner. - * - * @param - * input symbol type - * @param - * output symbol type - * - * @author frohme - */ -public class DHCAdapterMealy extends MealyDHC implements AccessSequenceTransformer { - - public DHCAdapterMealy(Alphabet alphabet, MembershipOracle> oracle) { - super(alphabet, oracle, GlobalSuffixFinders.RIVEST_SCHAPIRE, Collections.emptyList()); - } - -} diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java index 105a53b686..598eb01b2a 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java @@ -19,8 +19,8 @@ import java.util.List; import java.util.function.BiFunction; +import de.learnlib.algorithms.dhc.mealy.MealyDHC; import de.learnlib.algorithms.procedural.SymbolWrapper; -import de.learnlib.algorithms.procedural.adapter.mealy.DHCAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.DiscriminationTreeAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.KearnsVaziraniAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.LStarBaseAdapterMealy; @@ -51,7 +51,7 @@ protected void addLearnerVariants(ProceduralInputAlphabet alphabet, final Builder builder = new Builder<>(alphabet, outputAlphabet, mqOracle, variants); builder.addLearnerVariant(DiscriminationTreeAdapterMealy::new); - builder.addLearnerVariant(DHCAdapterMealy::new); + builder.addLearnerVariant(MealyDHC::new); builder.addLearnerVariant(KearnsVaziraniAdapterMealy::new); builder.addLearnerVariant(LStarBaseAdapterMealy::new); builder.addLearnerVariant(OptimalTTTAdapterMealy::new); From fb64025a371193698a644a3c7961e0a393d02e22 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 7 Sep 2023 01:50:45 +0200 Subject: [PATCH 10/15] adjust to AutomataLib refactorings --- .../procedural/spmm/MappingSPMM.java | 19 +++--- .../procedural/spmm/SPMMLearner.java | 61 +++++++++---------- .../spmm/manager/DefaultATManager.java | 10 +-- .../spmm/manager/OptimizingATManager.java | 13 ++-- .../procedural/spmm/ATManagerTest.java | 13 ++-- .../algorithms/procedural/spmm/SPMMIT.java | 27 ++++---- .../it/learner/AbstractSPMMLearnerIT.java | 21 +++---- .../examples/DefaultLearningExample.java | 6 -- .../de/learnlib/examples/LearningExample.java | 3 - .../learnlib/examples/LearningExamples.java | 12 ++-- 10 files changed, 85 insertions(+), 100 deletions(-) diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java index 70958a98f8..9a741f09a8 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java @@ -24,7 +24,6 @@ import net.automatalib.automata.procedural.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -39,19 +38,19 @@ */ class MappingSPMM implements SPMM { - private final ProceduralInputAlphabet inputAlphabet; - private final ProceduralOutputAlphabet outputAlphabet; + private final ProceduralInputAlphabet alphabet; + private final O errorOutput; private final Map> mapping; private final SPMM, T, O> delegate; private final Map> procedures; - MappingSPMM(ProceduralInputAlphabet inputAlphabet, - ProceduralOutputAlphabet outputAlphabet, + MappingSPMM(ProceduralInputAlphabet alphabet, + O errorOutput, Map> mapping, SPMM, T, O> delegate) { - this.inputAlphabet = inputAlphabet; - this.outputAlphabet = outputAlphabet; + this.alphabet = alphabet; + this.errorOutput = errorOutput; this.mapping = mapping; this.delegate = delegate; @@ -82,12 +81,12 @@ public S getInitialState() { @Override public ProceduralInputAlphabet getInputAlphabet() { - return this.inputAlphabet; + return this.alphabet; } @Override - public ProceduralOutputAlphabet getOutputAlphabet() { - return this.outputAlphabet; + public O getErrorOutput() { + return this.errorOutput; } @Override diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java index 9218d6071f..32aed39a7d 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java @@ -45,7 +45,6 @@ import net.automatalib.util.automata.procedural.SPMMUtil; import net.automatalib.words.Alphabet; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import net.automatalib.words.impl.DefaultProceduralInputAlphabet; @@ -54,8 +53,8 @@ public class SPMMLearner, O> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> implements LearningAlgorithm, I, Word> { - private final ProceduralInputAlphabet inputAlphabet; - private final ProceduralOutputAlphabet outputAlphabet; + private final ProceduralInputAlphabet alphabet; + private final O errorOutput; private final MembershipOracle> oracle; private final Mapping, Word>> learnerConstructors; private final ATManager atManager; @@ -66,38 +65,38 @@ public class SPMMLearner, O> & Sup private final Map> mapping; - public SPMMLearner(ProceduralInputAlphabet inputAlphabet, - ProceduralOutputAlphabet outputAlphabet, + public SPMMLearner(ProceduralInputAlphabet alphabet, + O errorOutput, MembershipOracle> oracle, LearnerConstructor, Word> learnerConstructor) { - this(inputAlphabet, - outputAlphabet, + this(alphabet, + errorOutput, oracle, (i) -> learnerConstructor, - new OptimizingATManager<>(inputAlphabet, outputAlphabet)); + new OptimizingATManager<>(alphabet, errorOutput)); } - public SPMMLearner(ProceduralInputAlphabet inputAlphabet, - ProceduralOutputAlphabet outputAlphabet, + public SPMMLearner(ProceduralInputAlphabet alphabet, + O errorOutput, MembershipOracle> oracle, Mapping, Word>> learnerConstructors, ATManager atManager) { - this.inputAlphabet = inputAlphabet; - this.outputAlphabet = outputAlphabet; + this.alphabet = alphabet; + this.errorOutput = errorOutput; this.oracle = oracle; this.learnerConstructors = learnerConstructors; this.atManager = atManager; - this.learners = Maps.newHashMapWithExpectedSize(this.inputAlphabet.getNumCalls()); - this.mapping = Maps.newHashMapWithExpectedSize(this.inputAlphabet.size()); + this.learners = Maps.newHashMapWithExpectedSize(this.alphabet.getNumCalls()); + this.mapping = Maps.newHashMapWithExpectedSize(this.alphabet.size()); - for (I i : this.inputAlphabet.getInternalAlphabet()) { + for (I i : this.alphabet.getInternalAlphabet()) { final SymbolWrapper wrapper = new SymbolWrapper<>(i, true); this.mapping.put(i, wrapper); } - final SymbolWrapper wrapper = new SymbolWrapper<>(this.inputAlphabet.getReturnSymbol(), false); - this.mapping.put(this.inputAlphabet.getReturnSymbol(), wrapper); + final SymbolWrapper wrapper = new SymbolWrapper<>(this.alphabet.getReturnSymbol(), false); + this.mapping.put(this.alphabet.getReturnSymbol(), wrapper); } @Override @@ -135,12 +134,12 @@ private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) final int mismatchIdx = detectMismatchingIdx(hypothesis, input, output); // extract local ce - final int callIdx = inputAlphabet.findCallIndex(input, mismatchIdx); + final int callIdx = alphabet.findCallIndex(input, mismatchIdx); final I procedure = input.getSymbol(callIdx); - final Pair, Word> localTraces = inputAlphabet.project(input.subWord(callIdx + 1, mismatchIdx + 1), - output.subWord(callIdx + 1, mismatchIdx + 1), - 0); + final Pair, Word> localTraces = alphabet.project(input.subWord(callIdx + 1, mismatchIdx + 1), + output.subWord(callIdx + 1, mismatchIdx + 1), + 0); final DefaultQuery, Word> localCE = constructLocalCE(localTraces.getFirst(), localTraces.getSecond()); final boolean localRefinement = this.learners.get(procedure).refineHypothesis(localCE); @@ -153,7 +152,7 @@ private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) public SPMM getHypothesisModel() { if (this.learners.isEmpty()) { - return new EmptySPMM<>(this.inputAlphabet, outputAlphabet); + return new EmptySPMM<>(this.alphabet, errorOutput); } final Alphabet> internalAlphabet = new GrowingMapAlphabet<>(); @@ -171,25 +170,25 @@ private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) callAlphabet.add(w); } - for (I i : this.inputAlphabet.getInternalAlphabet()) { + for (I i : this.alphabet.getInternalAlphabet()) { final SymbolWrapper w = this.mapping.get(i); assert w != null; internalAlphabet.add(w); } - returnSymbol = this.mapping.get(inputAlphabet.getReturnSymbol()); + returnSymbol = this.mapping.get(alphabet.getReturnSymbol()); assert returnSymbol != null; final ProceduralInputAlphabet> mappedAlphabet = new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); final StackSPMM, ?, O> delegate = new StackSPMM<>(mappedAlphabet, - outputAlphabet, + errorOutput, this.mapping.get(initialCallSymbol), initialOutputSymbol, mappedProcedures); - return new MappingSPMM<>(inputAlphabet, outputAlphabet, mapping, delegate); + return new MappingSPMM<>(alphabet, errorOutput, mapping, delegate); } private boolean extractUsefulInformationFromCounterExample(DefaultQuery> defaultQuery) { @@ -220,10 +219,10 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery(this.mapping.values()), - new ProceduralMembershipOracle<>(inputAlphabet, + new ProceduralMembershipOracle<>(alphabet, oracle, sym, - outputAlphabet.getErrorSymbol(), + errorOutput, atManager)); newLearner.startLearning(); @@ -302,20 +301,20 @@ private boolean ensureReturnClosure(MealyMachine, T, final S state = hyp.getState(cov); for (SymbolWrapper i : inputs) { - if (Objects.equals(i.getDelegate(), inputAlphabet.getReturnSymbol())) { + if (Objects.equals(i.getDelegate(), alphabet.getReturnSymbol())) { final S succ = hyp.getSuccessor(state, i); for (SymbolWrapper next : inputs) { final O succOut = hyp.getOutput(succ, next); - if (!outputAlphabet.isErrorSymbol(succOut)) { // error closure is violated + if (!Objects.equals(errorOutput, succOut)) { // error closure is violated // TODO split prefix/suffix? Issue with learners? final Word> lp = cov.append(i); final DefaultQuery, Word> ce = new DefaultQuery<>(Word.epsilon(), lp.append(next), hyp.computeOutput(lp) - .append(outputAlphabet.getErrorSymbol())); + .append(errorOutput)); final boolean refined = learner.refineHypothesis(ce); assert refined; return false; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java index ca010d975d..e7c286dd45 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java @@ -18,6 +18,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.Objects; import java.util.Set; import com.google.common.collect.Maps; @@ -29,7 +30,6 @@ import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; public class DefaultATManager implements ATManager { @@ -38,11 +38,11 @@ public class DefaultATManager implements ATManager { private final Map> terminatingSequences; private final ProceduralInputAlphabet inputAlphabet; - private final ProceduralOutputAlphabet outputAlphabet; + private final O errorOutput; - public DefaultATManager(ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet) { + public DefaultATManager(ProceduralInputAlphabet inputAlphabet, O errorOutput) { this.inputAlphabet = inputAlphabet; - this.outputAlphabet = outputAlphabet; + this.errorOutput = errorOutput; this.accessSequences = Maps.newHashMapWithExpectedSize(inputAlphabet.getNumCalls()); this.terminatingSequences = Maps.newHashMapWithExpectedSize(inputAlphabet.getNumCalls()); @@ -82,7 +82,7 @@ public Pair, Set> scanCounterexample(DefaultQuery> countere final int returnIdx = inputAlphabet.findReturnIndex(input, i + 1); if (returnIdx > 0 && !this.terminatingSequences.containsKey(sym) && - !this.outputAlphabet.isErrorSymbol(output.getSymbol(returnIdx))) { + !Objects.equals(this.errorOutput, output.getSymbol(returnIdx))) { this.terminatingSequences.put(sym, input.subWord(i + 1, returnIdx)); newTerms.add(sym); } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java index 5981672444..a2dd6d29f5 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java @@ -35,7 +35,6 @@ import net.automatalib.commons.util.Pair; import net.automatalib.util.automata.cover.Covers; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; import org.checkerframework.checker.nullness.qual.Nullable; @@ -46,11 +45,11 @@ public class OptimizingATManager implements ATManager { private final Map> terminatingSequences; private final ProceduralInputAlphabet inputAlphabet; - private final ProceduralOutputAlphabet outputAlphabet; + private final O errorOutput; - public OptimizingATManager(ProceduralInputAlphabet inputAlphabet, ProceduralOutputAlphabet outputAlphabet) { + public OptimizingATManager(ProceduralInputAlphabet inputAlphabet, O errorOutput) { this.inputAlphabet = inputAlphabet; - this.outputAlphabet = outputAlphabet; + this.errorOutput = errorOutput; this.accessSequences = Maps.newHashMapWithExpectedSize(inputAlphabet.getNumCalls()); this.terminatingSequences = Maps.newHashMapWithExpectedSize(inputAlphabet.getNumCalls()); @@ -139,7 +138,7 @@ public Set scanRefinedProcedures(Map> as = asTransformer.transformAccessSequence(cover); final Word> asReturn = as.append(returnSymbol); - if (!this.outputAlphabet.isErrorSymbol(hyp.computeOutput(asReturn).lastSymbol())) { + if (!Objects.equals(this.errorOutput, hyp.computeOutput(asReturn).lastSymbol())) { final Word ts = this.inputAlphabet.expand(as.transform(SymbolWrapper::getDelegate), terminatingSequences::get); if (result == null || result.size() > ts.size()) { @@ -174,7 +173,7 @@ private void extractPotentialTerminatingSequences(DefaultQuery> count final int returnIdx = inputAlphabet.findReturnIndex(input, i + 1); - if (returnIdx > 0 && !this.outputAlphabet.isErrorSymbol(output.getSymbol(returnIdx))) { + if (returnIdx > 0 && !Objects.equals(this.errorOutput, output.getSymbol(returnIdx))) { final Word potentialTermSeq = input.subWord(i + 1, returnIdx); final Word currentTermSeq = this.terminatingSequences.get(sym); @@ -203,7 +202,7 @@ private void extractPotentialAccessSequences(DefaultQuery> counterexa if (this.inputAlphabet.isCallSymbol(sym)) { - if (this.outputAlphabet.isErrorSymbol(output.getSymbol(i))) { + if (Objects.equals(this.errorOutput, output.getSymbol(i))) { return; } diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java index c808d88021..c75af71820 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/ATManagerTest.java @@ -20,32 +20,31 @@ import de.learnlib.api.query.DefaultQuery; import net.automatalib.words.Alphabet; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; import net.automatalib.words.impl.Alphabets; import net.automatalib.words.impl.DefaultProceduralInputAlphabet; -import net.automatalib.words.impl.DefaultProceduralOutputAlphabet; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class ATManagerTest { - private static final ProceduralInputAlphabet INPUT_ALPHABET; - private static final ProceduralOutputAlphabet OUTPUT_ALPHABET; + private static final ProceduralInputAlphabet ALPHABET; + private static final Character ERROR_OUTPUT; static { final Alphabet callAlphabet = Alphabets.characters('A', 'C'); final Alphabet internalAlphabet = Alphabets.characters('a', 'b'); final char returnSymbol = 'R'; - INPUT_ALPHABET = new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); - OUTPUT_ALPHABET = new DefaultProceduralOutputAlphabet<>(Alphabets.characters('x', 'z'), '✗'); + ALPHABET = new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); + ERROR_OUTPUT = '✗'; } @DataProvider public static Object[] atManager() { - return new Object[] {new DefaultATManager<>(INPUT_ALPHABET, OUTPUT_ALPHABET), new OptimizingATManager<>(INPUT_ALPHABET, OUTPUT_ALPHABET)}; + return new Object[] {new DefaultATManager<>(ALPHABET, ERROR_OUTPUT), + new OptimizingATManager<>(ALPHABET, ERROR_OUTPUT)}; } @Test(dataProvider = "atManager") diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java index 598eb01b2a..965ff70aff 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java @@ -37,18 +37,17 @@ import de.learnlib.testsupport.it.learner.LearnerVariantList.SPMMLearnerVariantList; import net.automatalib.SupportsGrowingAlphabet; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; public class SPMMIT extends AbstractSPMMLearnerIT { @Override protected void addLearnerVariants(ProceduralInputAlphabet alphabet, - ProceduralOutputAlphabet outputAlphabet, + O errorOutput, MembershipOracle> mqOracle, SPMMLearnerVariantList variants) { - final Builder builder = new Builder<>(alphabet, outputAlphabet, mqOracle, variants); + final Builder builder = new Builder<>(alphabet, errorOutput, mqOracle, variants); builder.addLearnerVariant(DiscriminationTreeAdapterMealy::new); builder.addLearnerVariant(MealyDHC::new); @@ -61,18 +60,18 @@ protected void addLearnerVariants(ProceduralInputAlphabet alphabet, private static class Builder { - private final ProceduralInputAlphabet inputAlphabet; - private final ProceduralOutputAlphabet outputAlphabet; + private final ProceduralInputAlphabet alphabet; + private final O errorOutput; private final MembershipOracle> mqOracle; private final SPMMLearnerVariantList variants; - private final List, ProceduralOutputAlphabet, ATManager>> atProviders; + private final List, O, ATManager>> atProviders; - Builder(ProceduralInputAlphabet inputAlphabet, - ProceduralOutputAlphabet outputAlphabet, + Builder(ProceduralInputAlphabet alphabet, + O errorOutput, MembershipOracle> mqOracle, SPMMLearnerVariantList variants) { - this.inputAlphabet = inputAlphabet; - this.outputAlphabet = outputAlphabet; + this.alphabet = alphabet; + this.errorOutput = errorOutput; this.mqOracle = mqOracle; this.variants = variants; this.atProviders = Arrays.asList(DefaultATManager::new, OptimizingATManager::new); @@ -81,12 +80,12 @@ private static class Builder { , O> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> void addLearnerVariant( LearnerConstructor, Word> provider) { - for (BiFunction, ProceduralOutputAlphabet, ATManager> atProvider : atProviders) { - final SPMMLearner learner = new SPMMLearner<>(inputAlphabet, - outputAlphabet, + for (BiFunction, O, ATManager> atProvider : atProviders) { + final SPMMLearner learner = new SPMMLearner<>(alphabet, + errorOutput, mqOracle, (i) -> provider, - atProvider.apply(inputAlphabet, outputAlphabet)); + atProvider.apply(alphabet, errorOutput)); final String name = String.format("adapter=%s,manager=%s", provider, atProvider); variants.addLearnerVariant(name, learner); } diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java index 4feb03dac7..d4ea5bf33a 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java @@ -25,8 +25,8 @@ import de.learnlib.oracle.membership.SimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.SPMMLearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SPMMLearnerVariantListImpl; +import net.automatalib.automata.procedural.SPMM; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.Word; import org.testng.annotations.Factory; @@ -51,30 +51,29 @@ public Object[] createExampleITCases() { private List> createAllVariantsITCase(SPMMLearningExample example) { - final MembershipOracle> mqOracle = new SimulatorOracle<>(example.getReferenceAutomaton()); + final SPMM reference = example.getReferenceAutomaton(); + final MembershipOracle> mqOracle = new SimulatorOracle<>(reference); final SPMMLearnerVariantListImpl variants = new SPMMLearnerVariantListImpl<>(); - addLearnerVariants(example.getAlphabet(), example.getOutputAlphabet(), mqOracle, variants); + addLearnerVariants(example.getAlphabet(), reference.getErrorOutput(), mqOracle, variants); - return LearnerITUtil.createExampleITCases(example, - variants, - new SimulatorEQOracle<>(example.getReferenceAutomaton())); + return LearnerITUtil.createExampleITCases(example, variants, new SimulatorEQOracle<>(reference)); } /** * Adds, for a given setup, all the variants of the DFA learner to be tested to the specified * {@link LearnerVariantList variant list}. * - * @param inputAlphabet + * @param alphabet * the input alphabet - * @param outputAlphabet - * the output alphabet + * @param errorOutput + * the erroneous output symbol * @param mqOracle * the membership oracle * @param variants * list to add the learner variants to */ - protected abstract void addLearnerVariants(ProceduralInputAlphabet inputAlphabet, - ProceduralOutputAlphabet outputAlphabet, + protected abstract void addLearnerVariants(ProceduralInputAlphabet alphabet, + O errorOutput, MembershipOracle> mqOracle, SPMMLearnerVariantList variants); } 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 8871e563ea..2c804c94ca 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 @@ -28,7 +28,6 @@ import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Alphabet; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.VPDAlphabet; import net.automatalib.words.Word; @@ -191,11 +190,6 @@ public DefaultSPMMLearningExample(SPMM referenceAutomaton) { public ProceduralInputAlphabet getAlphabet() { return this.referenceAutomaton.getInputAlphabet(); } - - @Override - public ProceduralOutputAlphabet getOutputAlphabet() { - return this.referenceAutomaton.getOutputAlphabet(); - } } } 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 c6b581c159..7ce4197052 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 @@ -27,7 +27,6 @@ import net.automatalib.automata.vpda.OneSEVPA; import net.automatalib.words.Alphabet; import net.automatalib.words.ProceduralInputAlphabet; -import net.automatalib.words.ProceduralOutputAlphabet; import net.automatalib.words.VPDAlphabet; public interface LearningExample { @@ -79,8 +78,6 @@ interface SPMMLearningExample extends LearningExample> @Override ProceduralInputAlphabet getAlphabet(); - - ProceduralOutputAlphabet getOutputAlphabet(); } interface OneSEVPALearningExample extends LearningExample> { 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 73d8f66589..b3a3a12f7b 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 @@ -61,9 +61,9 @@ public final class LearningExamples { private static final Alphabet RANDOM_ALPHABET = Alphabets.characters('a', 'c'); - private static final ProceduralInputAlphabet SPA_INPUT_ALPHABET = + private static final ProceduralInputAlphabet PROCEDURAL_INPUT_ALPHABET = new DefaultProceduralInputAlphabet<>(Alphabets.characters('A', 'F'), Alphabets.characters('a', 'f'), 'R'); - private static final ProceduralOutputAlphabet SPA_OUTPUT_ALPHABET = + private static final ProceduralOutputAlphabet PROCEDURAL_OUTPUT_ALPHABET = new DefaultProceduralOutputAlphabet<>(Alphabets.characters('u', 'z'), '✗'); private static final VPDAlphabet VPD_ALPHABET = new DefaultVPDAlphabet<>(Alphabets.characters('a', 'f'), Alphabets.characters('1', '3'), @@ -132,20 +132,20 @@ public static List> createDFAExamples() { public static List> createSPAExamples() { return Arrays.asList(ExamplePalindrome.createExample(), ExampleRandomSPA.createExample(new Random(RANDOM_SEED), - SPA_INPUT_ALPHABET, + PROCEDURAL_INPUT_ALPHABET, PROCEDURE_SIZE)); } public static List> createSBAExamples() { return Collections.singletonList(ExampleRandomSBA.createExample(new Random(RANDOM_SEED), - SPA_INPUT_ALPHABET, + PROCEDURAL_INPUT_ALPHABET, PROCEDURE_SIZE)); } public static List> createSPMMExamples() { return Collections.singletonList(ExampleRandomSPMM.createExample(new Random(RANDOM_SEED), - SPA_INPUT_ALPHABET, - SPA_OUTPUT_ALPHABET, + PROCEDURAL_INPUT_ALPHABET, + PROCEDURAL_OUTPUT_ALPHABET, PROCEDURE_SIZE)); } From 1bf6c05444f56e6f35358bf601c971a3c0e45ef8 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 7 Sep 2023 22:42:15 +0200 Subject: [PATCH 11/15] add documentation --- .../algorithms/procedural/SymbolWrapper.java | 8 +++ .../algorithms/procedural/sba/ATManager.java | 55 +++++++++++++++- .../algorithms/procedural/sba/MappingSBA.java | 7 --- .../sba/ProceduralMembershipOracle.java | 5 +- .../algorithms/procedural/sba/SBALearner.java | 16 ++++- .../sba/manager/DefaultATManager.java | 15 ++++- .../sba/manager/OptimizingATManager.java | 16 ++++- .../algorithms/procedural/spa/ATRManager.java | 63 ++++++++++++++++++- .../spa/ProceduralMembershipOracle.java | 5 +- .../algorithms/procedural/spa/SPALearner.java | 12 ++-- .../spa/manager/DefaultATRManager.java | 15 ++++- .../spa/manager/OptimizingATRManager.java | 15 ++++- .../algorithms/procedural/spmm/ATManager.java | 57 ++++++++++++++++- .../procedural/spmm/MappingSPMM.java | 7 --- .../spmm/ProceduralMembershipOracle.java | 5 +- .../procedural/spmm/SPMMLearner.java | 18 +++++- .../spmm/manager/DefaultATManager.java | 17 ++++- .../spmm/manager/OptimizingATManager.java | 17 ++++- 18 files changed, 297 insertions(+), 56 deletions(-) diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java index f05ebbf08e..ba3b2b847e 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java @@ -15,6 +15,14 @@ */ package de.learnlib.algorithms.procedural; +/** + * A utility class to annotate an input symbol with a (boolean) continuable flag. + * + * @param + * input symbol type + * + * @author frohme + */ public class SymbolWrapper { private final I delegate; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java index eec8b1e29e..2d83060147 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java @@ -22,19 +22,68 @@ import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.procedural.SBA; import net.automatalib.commons.util.Pair; import net.automatalib.words.Word; +/** + * A manager of access and terminating sequences of {@link SBA}s during the learning process. + * + * @param + * input symbol type + * + * @author frohme + */ public interface ATManager { + /** + * Returns an access sequence for the given procedure. + * + * @param procedure + * the call symbol that identifies the procedure + * + * @return the access sequence for the given procedure + */ Word getAccessSequence(I procedure); + /** + * Returns a terminating sequence for the given procedure. + * + * @param procedure + * the call symbol that identifies the procedure + * + * @return the terminating sequence for the given procedure + */ Word getTerminatingSequence(I procedure); + /** + * Extracts from a positive counterexample (potentially new) access and terminating sequences. + * + * @param counterexample + * the counterexample + * + * @return a {@link Pair} of {@link Set}s of procedures (identified by their respective call symbols) for which new + * access and terminating sequences could be extracted and for which previously none of the sequences were + * available. + */ Pair, Set> scanPositiveCounterexample(Word counterexample); - Set scanRefinedProcedures(Map>> procedures, - Map>> providers, - Collection> inputs); + /** + * Scans a set of (hypothesis) procedures in order to potentially extract new access and terminating sequences. + * + * @param procedures + * a {@link Map} from call symbols to the respective procedural (hypothesis) models + * @param providers + * a {@link Map} from call symbols to {@link AccessSequenceTransformer}s + * @param inputs + * a {@link Collection} of input symbols which should be used for finding new access, terminating, and + * return sequences + * + * @return a {@link Set} of procedures (identified by their respective call symbols) for which terminating sequences + * could be extracted and for which previously no such sequences were available. + */ + Set scanProcedures(Map>> procedures, + Map>> providers, + Collection> inputs); } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java index c70941b789..116551f785 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/MappingSBA.java @@ -27,13 +27,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** - * A stack-based implementation for the (instrumented) semantics of a System of Procedural Automata. - * - * @param - * hypotheses state type - * @param - * input symbol type - * * @author frohme */ class MappingSBA implements SBA { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java index ed31196b28..378289f39c 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ProceduralMembershipOracle.java @@ -27,7 +27,10 @@ import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; -final class ProceduralMembershipOracle implements MembershipOracle, Boolean> { +/** + * @author frohme + */ +class ProceduralMembershipOracle implements MembershipOracle, Boolean> { private final ProceduralInputAlphabet alphabet; private final MembershipOracle delegate; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java index 9b724c57cf..ea2ad865c3 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java @@ -53,6 +53,16 @@ import net.automatalib.words.impl.DefaultProceduralInputAlphabet; import net.automatalib.words.impl.GrowingMapAlphabet; +/** + * A learning algorithm for {@link SBA}s. + * + * @param + * input symbol type + * @param + * sub-learner type + * + * @author frohme + */ public class SBALearner> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> implements LearningAlgorithm, I, Boolean> { @@ -230,9 +240,9 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery newTS = - this.atManager.scanRefinedProcedures(Collections.singletonMap(sym, newLearner.getHypothesisModel()), - learners, - mapping.values()); + this.atManager.scanProcedures(Collections.singletonMap(sym, newLearner.getHypothesisModel()), + learners, + mapping.values()); for (I call : newTS) { final SymbolWrapper wrapper = new SymbolWrapper<>(call, true); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java index 5f6d7a17ef..85e3a7917a 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java @@ -30,6 +30,15 @@ import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; +/** + * A default {@link ATManager} that only extracts initial access and terminating sequences from positive + * counterexamples. + * + * @param + * input symbol type + * + * @author frohme + */ public class DefaultATManager implements ATManager { private final Map> accessSequences; @@ -84,9 +93,9 @@ public Pair, Set> scanPositiveCounterexample(Word input) { } @Override - public Set scanRefinedProcedures(Map>> procedures, - Map>> providers, - Collection> inputs) { + public Set scanProcedures(Map>> procedures, + Map>> providers, + Collection> inputs) { return Collections.emptySet(); } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java index 33de297aaa..760a861ac0 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java @@ -37,6 +37,16 @@ import net.automatalib.words.WordBuilder; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * An optimizing {@link ATManager} that continuously scans positive counterexamples and procedural models in order to + * find shorter access and terminating sequences. + * + * @param + * input symbol type + * + * @author frohme + */ + public class OptimizingATManager implements ATManager { private final Map> accessSequences; @@ -77,9 +87,9 @@ public Pair, Set> scanPositiveCounterexample(Word counterexample) { } @Override - public Set scanRefinedProcedures(Map>> procedures, - Map>> providers, - Collection> inputs) { + public Set scanProcedures(Map>> procedures, + Map>> providers, + Collection> inputs) { final Set newTS = new HashSet<>(); if (!procedures.isEmpty()) { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java index 90d0caf199..304bcc4f7a 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java @@ -21,20 +21,77 @@ import de.learnlib.api.AccessSequenceTransformer; import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.procedural.SPA; import net.automatalib.words.Word; +/** + * A manager of access, terminating, and return sequences of {@link SPA}s during the learning process. + * + * @param + * input symbol type + * + * @author frohme + */ public interface ATRManager { + /** + * Returns an access sequence for the given procedure. + * + * @param procedure + * the call symbol that identifies the procedure + * + * @return the access sequence for the given procedure + */ Word getAccessSequence(I procedure); + /** + * Returns a terminating sequence for the given procedure. + * + * @param procedure + * the call symbol that identifies the procedure + * + * @return the terminating sequence for the given procedure + */ Word getTerminatingSequence(I procedure); + /** + * Returns a return sequence for the given procedure. Note that the sequence must match the + * {@link #getAccessSequence(Object) access sequence} in order to provide an admissible context for query + * expansion. + * + * @param procedure + * the call symbol that identifies the procedure + * + * @return the return sequence for the given procedure + */ Word getReturnSequence(I procedure); + /** + * Extracts from a positive counterexample (potentially new) access, terminating, and return sequences. + * + * @param counterexample + * the counterexample + * + * @return a {@link Set} of procedures (identified by their respective call symbols) for which new access, + * terminating, and return sequences could be extracted and for which previously none of the sequences were + * available. + */ Set scanPositiveCounterexample(Word counterexample); - void scanRefinedProcedures(Map> procedures, - Map> providers, - Collection inputs); + /** + * Scans a set of (hypothesis) procedures in order to potentially extract new access, terminating, and return + * sequences. + * + * @param procedures + * a {@link Map} from call symbols to the respective procedural (hypothesis) models + * @param providers + * a {@link Map} from call symbols to {@link AccessSequenceTransformer}s + * @param inputs + * a {@link Collection} of input symbols which should be used for finding new access, terminating, and + * return sequences + */ + void scanProcedures(Map> procedures, + Map> providers, + Collection inputs); } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java index 5c27c6c553..69b61bc593 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ProceduralMembershipOracle.java @@ -25,7 +25,10 @@ import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; -final class ProceduralMembershipOracle implements MembershipOracle { +/** + * @author frohme + */ +class ProceduralMembershipOracle implements MembershipOracle { private final ProceduralInputAlphabet alphabet; private final MembershipOracle delegate; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java index 108b788913..73944d864c 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java @@ -51,7 +51,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; /** - * The learning algorithm for {@link StackSPA}s. + * A learning algorithm for {@link SPA}s. * * @param * input symbol type @@ -200,9 +200,9 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery hypothesis) { while (checkAndEnsureTSConformance(subModels)) { refinement = true; subModels = getSubModels(); - this.atrManager.scanRefinedProcedures(subModels, subLearners, activeAlphabet); + this.atrManager.scanProcedures(subModels, subLearners, activeAlphabet); } return refinement; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java index 5284bfa229..c772a1eece 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java @@ -27,6 +27,15 @@ import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; +/** + * A default {@link ATRManager} that only extracts initial access, terminating, and return sequences from positive + * counterexamples. + * + * @param + * input symbol type + * + * @author frohme + */ public class DefaultATRManager implements ATRManager { private final Map> accessSequences; @@ -84,9 +93,9 @@ public Set scanPositiveCounterexample(Word input) { } @Override - public void scanRefinedProcedures(Map> procedures, - Map> providers, - Collection inputs) { + public void scanProcedures(Map> procedures, + Map> providers, + Collection inputs) { // do nothing } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java index 8ec8bc4bca..c066c77579 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java @@ -34,6 +34,15 @@ import net.automatalib.words.WordBuilder; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * An optimizing {@link ATRManager} that continuously scans positive counterexamples and procedural models in order to + * find shorter access, terminating, and return sequences. + * + * @param + * input symbol type + * + * @author frohme + */ public class OptimizingATRManager implements ATRManager { private final Map> accessSequences; @@ -80,9 +89,9 @@ public Set scanPositiveCounterexample(Word input) { } @Override - public void scanRefinedProcedures(Map> procedures, - Map> providers, - Collection inputs) { + public void scanProcedures(Map> procedures, + Map> providers, + Collection inputs) { if (!procedures.isEmpty()) { boolean foundImprovements = false; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java index 2d6beec2ee..78e64c42d7 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java @@ -22,20 +22,71 @@ import de.learnlib.algorithms.procedural.SymbolWrapper; import de.learnlib.api.AccessSequenceTransformer; import de.learnlib.api.query.DefaultQuery; +import net.automatalib.automata.procedural.SPMM; import net.automatalib.automata.transducers.MealyMachine; import net.automatalib.commons.util.Pair; import net.automatalib.words.Word; +/** + * A manager of access and terminating sequences of {@link SPMM}s during the learning process. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ public interface ATManager { + /** + * Returns an access sequence for the given procedure. + * + * @param procedure + * the call symbol that identifies the procedure + * + * @return the access sequence for the given procedure + */ Word getAccessSequence(I procedure); + /** + * Returns a terminating sequence for the given procedure. + * + * @param procedure + * the call symbol that identifies the procedure + * + * @return the terminating sequence for the given procedure + */ Word getTerminatingSequence(I procedure); + /** + * Extracts from a positive counterexample (potentially new) access and terminating sequences. + * + * @param counterexample + * the counterexample + * + * @return a {@link Pair} of {@link Set}s of procedures (identified by their respective call symbols) for which new + * access and terminating sequences could be extracted and for which previously none of the sequences were + * available. + */ Pair, Set> scanCounterexample(DefaultQuery> counterexample); - Set scanRefinedProcedures(Map, ?, O>> procedures, - Map>> providers, - Collection> inputs); + /** + * Scans a set of (hypothesis) procedures in order to potentially extract new access and terminating sequences. + * + * @param procedures + * a {@link Map} from call symbols to the respective procedural (hypothesis) models + * @param providers + * a {@link Map} from call symbols to {@link AccessSequenceTransformer}s + * @param inputs + * a {@link Collection} of input symbols which should be used for finding new access, terminating, and + * return sequences + * + * @return a {@link Set} of procedures (identified by their respective call symbols) for which terminating sequences + * could be extracted and for which previously no such sequences were available. + */ + Set scanProcedures(Map, ?, O>> procedures, + Map>> providers, + Collection> inputs); } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java index 9a741f09a8..764332c4d5 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/MappingSPMM.java @@ -27,13 +27,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** - * A stack-based implementation for the (instrumented) semantics of a System of Procedural Automata. - * - * @param - * hypotheses state type - * @param - * input symbol type - * * @author frohme */ class MappingSPMM implements SPMM { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java index 8f345a91d2..d7ffc6accc 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ProceduralMembershipOracle.java @@ -29,7 +29,10 @@ import net.automatalib.words.Word; import net.automatalib.words.WordBuilder; -final class ProceduralMembershipOracle implements MembershipOracle, Word> { +/** + * @author frohme + */ +class ProceduralMembershipOracle implements MembershipOracle, Word> { private final ProceduralInputAlphabet alphabet; private final MembershipOracle> delegate; diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java index 32aed39a7d..15c5e54e35 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java @@ -50,6 +50,18 @@ import net.automatalib.words.impl.DefaultProceduralInputAlphabet; import net.automatalib.words.impl.GrowingMapAlphabet; +/** + * A learning algorithm for {@link SPMM}s. + * + * @param + * input symbol type + * @param + * output symbol type + * @param + * sub-learner type + * + * @author frohme + */ public class SPMMLearner, O> & SupportsGrowingAlphabet> & AccessSequenceTransformer>> implements LearningAlgorithm, I, Word> { @@ -232,9 +244,9 @@ private boolean extractUsefulInformationFromCounterExample(DefaultQuery newTS = - this.atManager.scanRefinedProcedures(Collections.singletonMap(sym, newLearner.getHypothesisModel()), - learners, - mapping.values()); + this.atManager.scanProcedures(Collections.singletonMap(sym, newLearner.getHypothesisModel()), + learners, + mapping.values()); for (I call : newTS) { final SymbolWrapper wrapper = new SymbolWrapper<>(call, true); diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java index e7c286dd45..694a01ef11 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java @@ -32,6 +32,17 @@ import net.automatalib.words.ProceduralInputAlphabet; import net.automatalib.words.Word; +/** + * A default {@link ATManager} that only extracts initial access and terminating sequences from positive + * counterexamples. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ public class DefaultATManager implements ATManager { private final Map> accessSequences; @@ -93,9 +104,9 @@ public Pair, Set> scanCounterexample(DefaultQuery> countere } @Override - public Set scanRefinedProcedures(Map, ?, O>> procedures, - Map>> providers, - Collection> inputs) { + public Set scanProcedures(Map, ?, O>> procedures, + Map>> providers, + Collection> inputs) { return Collections.emptySet(); } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java index a2dd6d29f5..b9c00a87df 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java @@ -39,6 +39,17 @@ import net.automatalib.words.WordBuilder; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * An optimizing {@link ATManager} that continuously scans positive counterexamples and procedural models in order to + * find shorter access and terminating sequences. + * + * @param + * input symbol type + * @param + * output symbol type + * + * @author frohme + */ public class OptimizingATManager implements ATManager { private final Map> accessSequences; @@ -81,9 +92,9 @@ public Pair, Set> scanCounterexample(DefaultQuery> countere } @Override - public Set scanRefinedProcedures(Map, ?, O>> procedures, - Map>> providers, - Collection> inputs) { + public Set scanProcedures(Map, ?, O>> procedures, + Map>> providers, + Collection> inputs) { final Set newTS = new HashSet<>(); if (!procedures.isEmpty()) { From f1769bef8a1051114e6acb45eb3e254b6280af6d Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 21 Sep 2023 17:42:26 +0200 Subject: [PATCH 12/15] add some assertions for convenience --- .../java/de/learnlib/algorithms/procedural/sba/SBALearner.java | 2 ++ .../java/de/learnlib/algorithms/procedural/spa/SPALearner.java | 2 ++ .../de/learnlib/algorithms/procedural/spmm/SPMMLearner.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java index ea2ad865c3..93fcb3f96f 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/SBALearner.java @@ -118,6 +118,8 @@ public void startLearning() { @Override public boolean refineHypothesis(DefaultQuery defaultQuery) { + assert this.alphabet.isReturnMatched(defaultQuery.getInput()); + boolean changed = this.extractUsefulInformationFromCounterExample(defaultQuery); while (refineHypothesisInternal(defaultQuery)) { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java index 73944d864c..7f7f36e76c 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java @@ -113,6 +113,8 @@ public void startLearning() { @Override public boolean refineHypothesis(DefaultQuery defaultQuery) { + assert this.alphabet.isWellMatched(defaultQuery.getInput()); + boolean changed = this.extractUsefulInformationFromCounterExample(defaultQuery); while (refineHypothesisInternal(defaultQuery)) { diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java index 15c5e54e35..6fbcaac824 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java @@ -119,6 +119,8 @@ public void startLearning() { @Override public boolean refineHypothesis(DefaultQuery> defaultQuery) { + assert this.alphabet.isReturnMatched(defaultQuery.getInput()); + boolean changed = this.extractUsefulInformationFromCounterExample(defaultQuery); while (refineHypothesisInternal(defaultQuery)) { From 5017f6882cafec8c5c7abdb8f24edc859b939b8a Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 25 Sep 2023 15:13:36 +0200 Subject: [PATCH 13/15] add SBA-based palindrome learning example --- .../learnlib/examples/LearningExamples.java | 7 +- .../examples/sba/ExamplePalindrome.java | 106 ++++++++++++++++++ 2 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExamplePalindrome.java 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 b3a3a12f7b..4195fafdc3 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 @@ -137,9 +137,10 @@ public static List> createSPAExamples() { } public static List> createSBAExamples() { - return Collections.singletonList(ExampleRandomSBA.createExample(new Random(RANDOM_SEED), - PROCEDURAL_INPUT_ALPHABET, - PROCEDURE_SIZE)); + return Arrays.asList(de.learnlib.examples.sba.ExamplePalindrome.createExample(), + ExampleRandomSBA.createExample(new Random(RANDOM_SEED), + PROCEDURAL_INPUT_ALPHABET, + PROCEDURE_SIZE)); } public static List> createSPMMExamples() { diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExamplePalindrome.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExamplePalindrome.java new file mode 100644 index 0000000000..9fac2ac0db --- /dev/null +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/sba/ExamplePalindrome.java @@ -0,0 +1,106 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.sba; + +import java.util.HashMap; +import java.util.Map; + +import de.learnlib.examples.DefaultLearningExample.DefaultSBALearningExample; +import net.automatalib.automata.fsa.DFA; +import net.automatalib.automata.fsa.impl.FastDFA; +import net.automatalib.automata.fsa.impl.compact.CompactDFA; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.automata.procedural.StackSBA; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.util.automata.fsa.MutableDFAs; +import net.automatalib.words.Alphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; + +public class ExamplePalindrome extends DefaultSBALearningExample { + + public ExamplePalindrome() { + super(createSBA()); + } + + public static ExamplePalindrome createExample() { + return new ExamplePalindrome(); + } + + private static SBA createSBA() { + final Alphabet internalAlphabet = Alphabets.characters('a', 'c'); + final Alphabet callAlphabet = Alphabets.characters('S', 'T'); + final ProceduralInputAlphabet alphabet = + new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, 'R'); + + final DFA sProcedure = buildSProcedure(alphabet); + final DFA tProcedure = buildTProcedure(alphabet); + + final Map> subModels = new HashMap<>(); + subModels.put('S', sProcedure); + subModels.put('T', tProcedure); + + return new StackSBA<>(alphabet, 'S', subModels); + } + + private static DFA buildSProcedure(ProceduralInputAlphabet alphabet) { + + final CompactDFA result = new CompactDFA<>(alphabet); + + // @formatter:off + AutomatonBuilders.forDFA(result) + .withInitial("s0") + .from("s0").on('T').to("s5") + .from("s0").on('a').to("s1") + .from("s0").on('b').to("s2") + .from("s0").on('R').to("s6") + .from("s1").on('S').to("s3") + .from("s1").on('R').to("s6") + .from("s2").on('S').to("s4") + .from("s2").on('R').to("s6") + .from("s3").on('a').to("s5") + .from("s4").on('b').to("s5") + .from("s5").on('R').to("s6") + .withAccepting("s0", "s1", "s2", "s3", "s4", "s5", "s6") + .create(); + // @formatter:on + + MutableDFAs.complete(result, alphabet); + return result; + } + + private static DFA buildTProcedure(ProceduralInputAlphabet alphabet) { + + final FastDFA result = new FastDFA<>(alphabet); + + // @formatter:off + AutomatonBuilders.forDFA(result) + .withInitial("t0") + .from("t0").on('S').to("t3") + .from("t0").on('c').to("t1") + .from("t1").on('T').to("t2") + .from("t1").on('R').to("t4") + .from("t2").on('c').to("t3") + .from("t3").on('R').to("t4") + .withAccepting("t0", "t1", "t2", "t3", "t4") + .create(); + // @formatter:on + + MutableDFAs.complete(result, alphabet); + return result; + } +} From 48c6a88f99534052806c6c1bb918afbf233fd7b1 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 25 Sep 2023 21:10:33 +0200 Subject: [PATCH 14/15] cleanup (mostly docs) --- CHANGELOG.md | 2 +- algorithms/active/procedural/pom.xml | 2 +- .../algorithms/procedural/SymbolWrapper.java | 2 +- .../adapter/dfa/DiscriminationTreeAdapterDFA.java | 2 +- .../adapter/dfa/KearnsVaziraniAdapterDFA.java | 2 +- .../adapter/dfa/LStarBaseAdapterDFA.java | 2 +- .../adapter/dfa/OptimalTTTAdapterDFA.java | 2 +- .../adapter/dfa/RivestSchapireAdapterDFA.java | 2 +- .../procedural/adapter/dfa/TTTAdapterDFA.java | 2 +- .../mealy/DiscriminationTreeAdapterMealy.java | 2 +- .../adapter/mealy/KearnsVaziraniAdapterMealy.java | 2 +- .../adapter/mealy/LStarBaseAdapterMealy.java | 2 +- .../adapter/mealy/OptimalTTTAdapterMealy.java | 2 +- .../adapter/mealy/RivestSchapireAdapterMealy.java | 2 +- .../procedural/adapter/mealy/TTTAdapterMealy.java | 2 +- .../algorithms/procedural/sba/ATManager.java | 11 ++++++----- .../procedural/sba/manager/DefaultATManager.java | 2 +- .../sba/manager/OptimizingATManager.java | 2 +- .../algorithms/procedural/spa/ATRManager.java | 14 ++++++++------ .../procedural/spa/manager/DefaultATRManager.java | 4 ++-- .../spa/manager/OptimizingATRManager.java | 2 +- .../algorithms/procedural/spmm/ATManager.java | 11 ++++++----- .../algorithms/procedural/spmm/SPMMLearner.java | 2 +- .../procedural/spmm/manager/DefaultATManager.java | 2 +- .../spmm/manager/OptimizingATManager.java | 2 +- .../oracle/equivalence/sba/WMethodEQOracle.java | 4 ++-- .../it/learner/AbstractSBALearnerIT.java | 3 ++- .../it/learner/AbstractSPALearnerIT.java | 7 ++++--- .../it/learner/AbstractSPMMLearnerIT.java | 2 +- 29 files changed, 52 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55c1cb5229..ad242a0d7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,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 systems (SPAs, SBAs, SPMMs). +* Added a new learning algorithm for procedural systems (SPAs, SBAs, SPMMs). * Added Moore versions of the learners `DT`, `TTT`, `LStar`, thanks to [Mohamad Bayram](https://github.com/mohbayram). * Migrated the AAAR algorithm from the old closed-source LearnLib. diff --git a/algorithms/active/procedural/pom.xml b/algorithms/active/procedural/pom.xml index 54e3378d73..9f330febb4 100644 --- a/algorithms/active/procedural/pom.xml +++ b/algorithms/active/procedural/pom.xml @@ -29,7 +29,7 @@ limitations under the License. LearnLib :: Algorithms :: Procedural - Active learning algorithms for procedural systems. Currently, contains learners for SPAs, SBAs, and SPMMs including adapters for orchestrating various regular learners of LearnLib to the context-free learning setup. + Active learning algorithms for procedural systems. Currently, contains learners for SPAs, SBAs, and SPMMs including adapters for integrating various regular learners of LearnLib in the context-free learning setup. diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java index ba3b2b847e..ed40906016 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/SymbolWrapper.java @@ -43,6 +43,6 @@ public boolean isContinuable() { @Override public String toString() { - return String.valueOf(delegate) + '(' + continuable + ')'; + return delegate + " (" + continuable + ')'; } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/DiscriminationTreeAdapterDFA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/DiscriminationTreeAdapterDFA.java index 55b6e786ca..3001360352 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/DiscriminationTreeAdapterDFA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/DiscriminationTreeAdapterDFA.java @@ -23,7 +23,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link DTLearnerDFA} as a sub-procedural learner. + * Adapter for using {@link DTLearnerDFA} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/KearnsVaziraniAdapterDFA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/KearnsVaziraniAdapterDFA.java index cc654004c0..0959a34ab1 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/KearnsVaziraniAdapterDFA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/KearnsVaziraniAdapterDFA.java @@ -24,7 +24,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link KearnsVaziraniDFA} as a sub-procedural learner. + * Adapter for using {@link KearnsVaziraniDFA} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/LStarBaseAdapterDFA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/LStarBaseAdapterDFA.java index eec1553576..b2ce924c2c 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/LStarBaseAdapterDFA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/LStarBaseAdapterDFA.java @@ -27,7 +27,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link ClassicLStarDFA} as a sub-procedural learner. + * Adapter for using {@link ClassicLStarDFA} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/OptimalTTTAdapterDFA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/OptimalTTTAdapterDFA.java index 55ccbd3fdb..aa7ec61e5d 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/OptimalTTTAdapterDFA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/OptimalTTTAdapterDFA.java @@ -25,7 +25,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link OptimalTTTDFA} as a sub-procedural learner. + * Adapter for using {@link OptimalTTTDFA} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/RivestSchapireAdapterDFA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/RivestSchapireAdapterDFA.java index 8985843fa8..b2c50376b1 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/RivestSchapireAdapterDFA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/RivestSchapireAdapterDFA.java @@ -27,7 +27,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link RivestSchapireDFA} as a sub-procedural learner. + * Adapter for using {@link RivestSchapireDFA} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/TTTAdapterDFA.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/TTTAdapterDFA.java index 9dae19589b..d010c2090d 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/TTTAdapterDFA.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/dfa/TTTAdapterDFA.java @@ -24,7 +24,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link TTTLearnerDFA} as a sub-procedural learner. + * Adapter for using {@link TTTLearnerDFA} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DiscriminationTreeAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DiscriminationTreeAdapterMealy.java index 7d0ad571f4..2bcd460c43 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DiscriminationTreeAdapterMealy.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/DiscriminationTreeAdapterMealy.java @@ -23,7 +23,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link DTLearnerMealy} as a sub-procedural learner. + * Adapter for using {@link DTLearnerMealy} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/KearnsVaziraniAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/KearnsVaziraniAdapterMealy.java index b5b4f009d0..b1add988b6 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/KearnsVaziraniAdapterMealy.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/KearnsVaziraniAdapterMealy.java @@ -24,7 +24,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link KearnsVaziraniMealy} as a sub-procedural learner. + * Adapter for using {@link KearnsVaziraniMealy} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java index 7b0b91e617..427ff5b695 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/LStarBaseAdapterMealy.java @@ -29,7 +29,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link ExtensibleLStarMealy} as a sub-procedural learner. + * Adapter for using {@link ExtensibleLStarMealy} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/OptimalTTTAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/OptimalTTTAdapterMealy.java index dd205aeae5..3a6af56a47 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/OptimalTTTAdapterMealy.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/OptimalTTTAdapterMealy.java @@ -25,7 +25,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link OptimalTTTMealy} as a sub-procedural learner. + * Adapter for using {@link OptimalTTTMealy} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java index 773cb874ec..a06a0a0f6f 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/RivestSchapireAdapterMealy.java @@ -26,7 +26,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link RivestSchapireMealy} as a sub-procedural learner. + * Adapter for using {@link RivestSchapireMealy} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/TTTAdapterMealy.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/TTTAdapterMealy.java index a031080621..9935d08218 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/TTTAdapterMealy.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/adapter/mealy/TTTAdapterMealy.java @@ -24,7 +24,7 @@ import net.automatalib.words.Word; /** - * Adapter for using {@link TTTLearnerMealy} as a sub-procedural learner. + * Adapter for using {@link TTTLearnerMealy} as a procedural learner. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java index 2d83060147..7e9ef24b41 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/ATManager.java @@ -27,7 +27,7 @@ import net.automatalib.words.Word; /** - * A manager of access and terminating sequences of {@link SBA}s during the learning process. + * A manager of access sequences and terminating sequences of {@link SBA}s during the learning process. * * @param * input symbol type @@ -57,7 +57,7 @@ public interface ATManager { Word getTerminatingSequence(I procedure); /** - * Extracts from a positive counterexample (potentially new) access and terminating sequences. + * Extracts from a positive counterexample (potentially new) access sequences and terminating sequences. * * @param counterexample * the counterexample @@ -69,15 +69,16 @@ public interface ATManager { Pair, Set> scanPositiveCounterexample(Word counterexample); /** - * Scans a set of (hypothesis) procedures in order to potentially extract new access and terminating sequences. + * Scans a set of (hypothesis) procedures in order to potentially extract new access sequences and terminating + * sequences. * * @param procedures * a {@link Map} from call symbols to the respective procedural (hypothesis) models * @param providers * a {@link Map} from call symbols to {@link AccessSequenceTransformer}s * @param inputs - * a {@link Collection} of input symbols which should be used for finding new access, terminating, and - * return sequences + * a {@link Collection} of input symbols which should be used for finding new access sequences, terminating + * sequences, and return sequences * * @return a {@link Set} of procedures (identified by their respective call symbols) for which terminating sequences * could be extracted and for which previously no such sequences were available. diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java index 85e3a7917a..5ab84eac3e 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/DefaultATManager.java @@ -31,7 +31,7 @@ import net.automatalib.words.Word; /** - * A default {@link ATManager} that only extracts initial access and terminating sequences from positive + * A default {@link ATManager} that only extracts initial access sequences and terminating sequences from positive * counterexamples. * * @param diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java index 760a861ac0..a25f254bbf 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java @@ -39,7 +39,7 @@ /** * An optimizing {@link ATManager} that continuously scans positive counterexamples and procedural models in order to - * find shorter access and terminating sequences. + * find shorter access sequences and terminating sequences. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java index 304bcc4f7a..adb7a527a5 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/ATRManager.java @@ -25,7 +25,8 @@ import net.automatalib.words.Word; /** - * A manager of access, terminating, and return sequences of {@link SPA}s during the learning process. + * A manager of access sequences, terminating sequences, and return sequences of {@link SPA}s during the learning + * process. * * @param * input symbol type @@ -67,7 +68,8 @@ public interface ATRManager { Word getReturnSequence(I procedure); /** - * Extracts from a positive counterexample (potentially new) access, terminating, and return sequences. + * Extracts from a positive counterexample (potentially new) access sequences, terminating sequences, and return + * sequences. * * @param counterexample * the counterexample @@ -79,16 +81,16 @@ public interface ATRManager { Set scanPositiveCounterexample(Word counterexample); /** - * Scans a set of (hypothesis) procedures in order to potentially extract new access, terminating, and return - * sequences. + * Scans a set of (hypothesis) procedures in order to potentially extract new access sequences, terminating + * sequences, and return sequences. * * @param procedures * a {@link Map} from call symbols to the respective procedural (hypothesis) models * @param providers * a {@link Map} from call symbols to {@link AccessSequenceTransformer}s * @param inputs - * a {@link Collection} of input symbols which should be used for finding new access, terminating, and - * return sequences + * a {@link Collection} of input symbols which should be used for finding new access sequences, terminating + * sequences, and return sequences */ void scanProcedures(Map> procedures, Map> providers, diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java index c772a1eece..2f865d5e5f 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/DefaultATRManager.java @@ -28,8 +28,8 @@ import net.automatalib.words.Word; /** - * A default {@link ATRManager} that only extracts initial access, terminating, and return sequences from positive - * counterexamples. + * A default {@link ATRManager} that only extracts initial access sequences, terminating sequences, and return sequences + * from positive counterexamples. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java index c066c77579..98439d2e57 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/manager/OptimizingATRManager.java @@ -36,7 +36,7 @@ /** * An optimizing {@link ATRManager} that continuously scans positive counterexamples and procedural models in order to - * find shorter access, terminating, and return sequences. + * find shorter access sequences, terminating sequences, and return sequences. * * @param * input symbol type diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java index 78e64c42d7..97db2773c5 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/ATManager.java @@ -28,7 +28,7 @@ import net.automatalib.words.Word; /** - * A manager of access and terminating sequences of {@link SPMM}s during the learning process. + * A manager of access sequences and terminating sequences of {@link SPMM}s during the learning process. * * @param * input symbol type @@ -60,7 +60,7 @@ public interface ATManager { Word getTerminatingSequence(I procedure); /** - * Extracts from a positive counterexample (potentially new) access and terminating sequences. + * Extracts from a positive counterexample (potentially new) access sequences and terminating sequences. * * @param counterexample * the counterexample @@ -72,15 +72,16 @@ public interface ATManager { Pair, Set> scanCounterexample(DefaultQuery> counterexample); /** - * Scans a set of (hypothesis) procedures in order to potentially extract new access and terminating sequences. + * Scans a set of (hypothesis) procedures in order to potentially extract new access sequences and terminating + * sequences. * * @param procedures * a {@link Map} from call symbols to the respective procedural (hypothesis) models * @param providers * a {@link Map} from call symbols to {@link AccessSequenceTransformer}s * @param inputs - * a {@link Collection} of input symbols which should be used for finding new access, terminating, and - * return sequences + * a {@link Collection} of input symbols which should be used for finding new access sequences, terminating + * sequences, and return sequences * * @return a {@link Set} of procedures (identified by their respective call symbols) for which terminating sequences * could be extracted and for which previously no such sequences were available. diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java index 6fbcaac824..293c684710 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java @@ -362,6 +362,6 @@ private int detectMismatchingIdx(SPMM spmm, Word input, Wo idx++; } - return -1; + throw new IllegalStateException("Non-counterexamples shouldn't be scanned for a mis-match"); } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java index 694a01ef11..932d6d2a65 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/DefaultATManager.java @@ -33,7 +33,7 @@ import net.automatalib.words.Word; /** - * A default {@link ATManager} that only extracts initial access and terminating sequences from positive + * A default {@link ATManager} that only extracts initial access sequences and terminating sequences from positive * counterexamples. * * @param diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java index b9c00a87df..bed52696b0 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java @@ -41,7 +41,7 @@ /** * An optimizing {@link ATManager} that continuously scans positive counterexamples and procedural models in order to - * find shorter access and terminating sequences. + * find shorter access sequences and terminating sequences sequences. * * @param * input symbol type diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracle.java index a7490cd4de..79313b86c4 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/sba/WMethodEQOracle.java @@ -29,8 +29,8 @@ import net.automatalib.words.Word; /** - * Implements an equivalence test by applying the W-method test on the procedures of the given hypothesis {@link SBA}, - * as described in "Testing software design modeled by finite state machines" by T.S. Chow. + * An {@link SBA} version of {@link de.learnlib.oracle.equivalence.WMethodEQOracle} which generates test sequences based + * on the {@link SBAWMethodTestsIterator W-method} for each procedure. * * @param * input symbol type diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java index 9521f09182..fa93b0a75d 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSBALearnerIT.java @@ -25,11 +25,12 @@ import de.learnlib.oracle.membership.SimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.SBALearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SBALearnerVariantListImpl; +import net.automatalib.automata.procedural.SBA; import net.automatalib.words.ProceduralInputAlphabet; import org.testng.annotations.Factory; /** - * Abstract integration test for VPDA learning algorithms. + * Abstract integration test for {@link SBA} learning algorithms. * * @author frohme */ diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPALearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPALearnerIT.java index 47accb4452..70f0194951 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPALearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPALearnerIT.java @@ -25,11 +25,12 @@ import de.learnlib.oracle.membership.SimulatorOracle; import de.learnlib.testsupport.it.learner.LearnerVariantList.SPALearnerVariantList; import de.learnlib.testsupport.it.learner.LearnerVariantListImpl.SPALearnerVariantListImpl; +import net.automatalib.automata.procedural.SPA; import net.automatalib.words.ProceduralInputAlphabet; import org.testng.annotations.Factory; /** - * Abstract integration test for VPDA learning algorithms. + * Abstract integration test for {@link SPA} learning algorithms. * * @author frohme */ @@ -60,8 +61,8 @@ private List> createAllVariantsITCase(SPALearningExample } /** - * Adds, for a given setup, all the variants of the DFA learner to be tested to the specified {@link - * LearnerVariantList variant list}. + * Adds, for a given setup, all the variants of the DFA learner to be tested to the specified + * {@link LearnerVariantList variant list}. * * @param alphabet * the input alphabet diff --git a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java index d4ea5bf33a..fb5ea3a89f 100644 --- a/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java +++ b/test-support/learner-it-support/src/main/java/de/learnlib/testsupport/it/learner/AbstractSPMMLearnerIT.java @@ -31,7 +31,7 @@ import org.testng.annotations.Factory; /** - * Abstract integration test for VPDA learning algorithms. + * Abstract integration test for {@link SPMM} learning algorithms. * * @author frohme */ From 0a421468411f68812c88ea80befa7de8fa7883e5 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 26 Sep 2023 01:10:06 +0200 Subject: [PATCH 15/15] cleanups + some more tests --- algorithms/active/procedural/pom.xml | 5 + .../sba/manager/OptimizingATManager.java | 3 +- .../algorithms/procedural/spa/SPALearner.java | 8 +- .../procedural/spmm/SPMMLearner.java | 4 +- .../spmm/manager/OptimizingATManager.java | 4 +- .../procedural/sba/OptimizationsTest.java | 70 ++++++++++++ .../procedural/sba/{ => it}/SBAIT.java | 4 +- .../procedural/spa/{ => it}/SPAIT.java | 4 +- .../procedural/spmm/OptimizationsTest.java | 72 ++++++++++++ .../procedural/spmm/{ => it}/SPMMIT.java | 4 +- .../learnlib/examples/LearningExamples.java | 9 +- .../examples/spmm/ExamplePalindrome.java | 107 ++++++++++++++++++ 12 files changed, 274 insertions(+), 20 deletions(-) create mode 100644 algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/OptimizationsTest.java rename algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/{ => it}/SBAIT.java (96%) rename algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/{ => it}/SPAIT.java (96%) create mode 100644 algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/OptimizationsTest.java rename algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/{ => it}/SPMMIT.java (96%) create mode 100644 test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExamplePalindrome.java diff --git a/algorithms/active/procedural/pom.xml b/algorithms/active/procedural/pom.xml index 9f330febb4..166c301a52 100644 --- a/algorithms/active/procedural/pom.xml +++ b/algorithms/active/procedural/pom.xml @@ -120,6 +120,11 @@ limitations under the License. learnlib-drivers-simulator test + + de.learnlib + learnlib-equivalence-oracles + test + de.learnlib.testsupport learnlib-learner-it-support diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java index a25f254bbf..9531ec495c 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/sba/manager/OptimizingATManager.java @@ -17,7 +17,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -91,7 +90,7 @@ public Set scanProcedures(Map>> procedur Map>> providers, Collection> inputs) { - final Set newTS = new HashSet<>(); + final Set newTS = Sets.newHashSetWithExpectedSize(procedures.size()); if (!procedures.isEmpty()) { final SymbolWrapper returnSymbol = inputs.stream() diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java index 7f7f36e76c..2724d3e19c 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spa/SPALearner.java @@ -76,15 +76,9 @@ public class SPALearner & SupportsGrowingAlphabet public SPALearner(ProceduralInputAlphabet alphabet, MembershipOracle oracle, LearnerConstructor learnerConstructor) { - this(alphabet, oracle, (i) -> learnerConstructor); - } - - public SPALearner(ProceduralInputAlphabet alphabet, - MembershipOracle oracle, - Mapping> learnerConstructors) { this(alphabet, oracle, - learnerConstructors, + (i) -> learnerConstructor, AcexAnalyzers.BINARY_SEARCH_FWD, new OptimizingATRManager<>(alphabet)); } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java index 293c684710..81452c3ba4 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/SPMMLearner.java @@ -197,9 +197,9 @@ private boolean refineHypothesisInternal(DefaultQuery> defaultQuery) new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, returnSymbol); final StackSPMM, ?, O> delegate = new StackSPMM<>(mappedAlphabet, - errorOutput, this.mapping.get(initialCallSymbol), initialOutputSymbol, + errorOutput, mappedProcedures); return new MappingSPMM<>(alphabet, errorOutput, mapping, delegate); @@ -362,6 +362,6 @@ private int detectMismatchingIdx(SPMM spmm, Word input, Wo idx++; } - throw new IllegalStateException("Non-counterexamples shouldn't be scanned for a mis-match"); + throw new IllegalArgumentException("Non-counterexamples shouldn't be scanned for a mis-match"); } } diff --git a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java index bed52696b0..b3932553b4 100644 --- a/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java +++ b/algorithms/active/procedural/src/main/java/de/learnlib/algorithms/procedural/spmm/manager/OptimizingATManager.java @@ -17,7 +17,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -95,7 +94,8 @@ public Pair, Set> scanCounterexample(DefaultQuery> countere public Set scanProcedures(Map, ?, O>> procedures, Map>> providers, Collection> inputs) { - final Set newTS = new HashSet<>(); + + final Set newTS = Sets.newHashSetWithExpectedSize(procedures.size()); if (!procedures.isEmpty()) { final SymbolWrapper returnSymbol = inputs.stream() diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/OptimizationsTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/OptimizationsTest.java new file mode 100644 index 0000000000..6b7c1fe9ab --- /dev/null +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/OptimizationsTest.java @@ -0,0 +1,70 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.procedural.sba; + +import java.util.Arrays; + +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.adapter.dfa.TTTAdapterDFA; +import de.learnlib.algorithms.procedural.sba.manager.OptimizingATManager; +import de.learnlib.api.algorithm.LearnerConstructor; +import de.learnlib.examples.sba.ExamplePalindrome; +import de.learnlib.oracle.equivalence.EQOracleChain; +import de.learnlib.oracle.equivalence.SampleSetEQOracle; +import de.learnlib.oracle.equivalence.sba.SimulatorEQOracle; +import de.learnlib.oracle.membership.SimulatorOracle; +import de.learnlib.util.Experiment; +import net.automatalib.automata.procedural.SBA; +import net.automatalib.util.automata.Automata; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.Word; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * A test for checking the optimizations performed by the {@link OptimizingATManager}. This test provides the + * {@link SBALearner} with a long, non-optimal counterexample first, so that following analysis steps should extract + * optimized sequences. + * + * @author frohme + */ +public class OptimizationsTest { + + @Test + public void testOptimizations() { + + final ExamplePalindrome example = ExamplePalindrome.createExample(); + final SBA sba = example.getReferenceAutomaton(); + final ProceduralInputAlphabet alphabet = example.getAlphabet(); + + final SimulatorOracle mqo = new SimulatorOracle<>(sba); + + final SampleSetEQOracle eqo1 = new SampleSetEQOracle<>(false); + eqo1.addAll(mqo, Word.fromString("STcTSaSaRaRRcRR")); + final SimulatorEQOracle eqo2 = new SimulatorEQOracle<>(sba); + final EQOracleChain, Character, Boolean> eqo = new EQOracleChain<>(Arrays.asList(eqo1, eqo2)); + + final LearnerConstructor>, SymbolWrapper, Boolean> cons = + TTTAdapterDFA::new; + final SBALearner learner = new SBALearner<>(alphabet, mqo, cons); + + final Experiment> experiment = new Experiment<>(learner, eqo, alphabet); + + experiment.run(); + + Assert.assertTrue(Automata.testEquivalence(sba, experiment.getFinalHypothesis(), alphabet)); + } +} diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/it/SBAIT.java similarity index 96% rename from algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/it/SBAIT.java index a6408250ba..79fc6c45de 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/SBAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/sba/it/SBAIT.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.procedural.sba; +package de.learnlib.algorithms.procedural.sba.it; import java.util.Arrays; import java.util.List; @@ -28,6 +28,8 @@ import de.learnlib.algorithms.procedural.adapter.dfa.OptimalTTTAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.RivestSchapireAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.TTTAdapterDFA; +import de.learnlib.algorithms.procedural.sba.ATManager; +import de.learnlib.algorithms.procedural.sba.SBALearner; import de.learnlib.algorithms.procedural.sba.manager.DefaultATManager; import de.learnlib.algorithms.procedural.sba.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/it/SPAIT.java similarity index 96% rename from algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/it/SPAIT.java index 6880c69719..9033ef76e3 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/SPAIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spa/it/SPAIT.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.procedural.spa; +package de.learnlib.algorithms.procedural.spa.it; import java.util.Arrays; import java.util.List; @@ -27,6 +27,8 @@ import de.learnlib.algorithms.procedural.adapter.dfa.OptimalTTTAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.RivestSchapireAdapterDFA; import de.learnlib.algorithms.procedural.adapter.dfa.TTTAdapterDFA; +import de.learnlib.algorithms.procedural.spa.ATRManager; +import de.learnlib.algorithms.procedural.spa.SPALearner; import de.learnlib.algorithms.procedural.spa.manager.DefaultATRManager; import de.learnlib.algorithms.procedural.spa.manager.OptimizingATRManager; import de.learnlib.api.AccessSequenceTransformer; diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/OptimizationsTest.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/OptimizationsTest.java new file mode 100644 index 0000000000..1b7ca491db --- /dev/null +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/OptimizationsTest.java @@ -0,0 +1,72 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.algorithms.procedural.spmm; + +import java.util.Arrays; + +import de.learnlib.algorithms.procedural.SymbolWrapper; +import de.learnlib.algorithms.procedural.adapter.mealy.TTTAdapterMealy; +import de.learnlib.algorithms.procedural.spmm.manager.OptimizingATManager; +import de.learnlib.api.algorithm.LearnerConstructor; +import de.learnlib.examples.spmm.ExamplePalindrome; +import de.learnlib.oracle.equivalence.EQOracleChain; +import de.learnlib.oracle.equivalence.SampleSetEQOracle; +import de.learnlib.oracle.equivalence.spmm.SimulatorEQOracle; +import de.learnlib.oracle.membership.SimulatorOracle; +import de.learnlib.util.Experiment; +import net.automatalib.automata.procedural.SPMM; +import net.automatalib.util.automata.Automata; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.Word; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * A test for checking the optimizations performed by the {@link OptimizingATManager}. This test provides the + * {@link SPMMLearner} with a long, non-optimal counterexample first, so that following analysis steps should extract + * optimized sequences. + * + * @author frohme + */ +public class OptimizationsTest { + + @Test + public void testOptimizations() { + + final ExamplePalindrome example = ExamplePalindrome.createExample(); + final SPMM spmm = example.getReferenceAutomaton(); + final ProceduralInputAlphabet alphabet = example.getAlphabet(); + + final SimulatorOracle> mqo = new SimulatorOracle<>(spmm); + + final SampleSetEQOracle> eqo1 = new SampleSetEQOracle<>(false); + eqo1.addAll(mqo, Word.fromString("STcTSaSaRaRRcRR")); + final SimulatorEQOracle eqo2 = new SimulatorEQOracle<>(spmm); + final EQOracleChain, Character, Word> eqo = + new EQOracleChain<>(Arrays.asList(eqo1, eqo2)); + + final LearnerConstructor, Character>, SymbolWrapper, Word> + cons = TTTAdapterMealy::new; + final SPMMLearner, Character>> learner = + new SPMMLearner<>(alphabet, spmm.getErrorOutput(), mqo, cons); + + final Experiment> experiment = new Experiment<>(learner, eqo, alphabet); + + experiment.run(); + + Assert.assertTrue(Automata.testEquivalence(spmm, experiment.getFinalHypothesis(), alphabet)); + } +} diff --git a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/it/SPMMIT.java similarity index 96% rename from algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java rename to algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/it/SPMMIT.java index 965ff70aff..82d81c5562 100644 --- a/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/SPMMIT.java +++ b/algorithms/active/procedural/src/test/java/de/learnlib/algorithms/procedural/spmm/it/SPMMIT.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.learnlib.algorithms.procedural.spmm; +package de.learnlib.algorithms.procedural.spmm.it; import java.util.Arrays; import java.util.List; @@ -27,6 +27,8 @@ import de.learnlib.algorithms.procedural.adapter.mealy.OptimalTTTAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.RivestSchapireAdapterMealy; import de.learnlib.algorithms.procedural.adapter.mealy.TTTAdapterMealy; +import de.learnlib.algorithms.procedural.spmm.ATManager; +import de.learnlib.algorithms.procedural.spmm.SPMMLearner; import de.learnlib.algorithms.procedural.spmm.manager.DefaultATManager; import de.learnlib.algorithms.procedural.spmm.manager.OptimizingATManager; import de.learnlib.api.AccessSequenceTransformer; 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 4195fafdc3..699ba61aea 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 @@ -144,10 +144,11 @@ public static List> createSBAExamples() { } public static List> createSPMMExamples() { - return Collections.singletonList(ExampleRandomSPMM.createExample(new Random(RANDOM_SEED), - PROCEDURAL_INPUT_ALPHABET, - PROCEDURAL_OUTPUT_ALPHABET, - PROCEDURE_SIZE)); + return Arrays.asList(de.learnlib.examples.spmm.ExamplePalindrome.createExample(), + ExampleRandomSPMM.createExample(new Random(RANDOM_SEED), + PROCEDURAL_INPUT_ALPHABET, + PROCEDURAL_OUTPUT_ALPHABET, + PROCEDURE_SIZE)); } public static List> createOneSEVPAExamples() { diff --git a/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExamplePalindrome.java b/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExamplePalindrome.java new file mode 100644 index 0000000000..a8325c83ec --- /dev/null +++ b/test-support/learning-examples/src/main/java/de/learnlib/examples/spmm/ExamplePalindrome.java @@ -0,0 +1,107 @@ +/* Copyright (C) 2013-2023 TU Dortmund + * This file is part of LearnLib, http://www.learnlib.de/. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.learnlib.examples.spmm; + +import java.util.HashMap; +import java.util.Map; + +import de.learnlib.examples.DefaultLearningExample.DefaultSPMMLearningExample; +import net.automatalib.automata.procedural.SPMM; +import net.automatalib.automata.procedural.StackSPMM; +import net.automatalib.automata.transducers.MealyMachine; +import net.automatalib.automata.transducers.impl.FastMealy; +import net.automatalib.automata.transducers.impl.compact.CompactMealy; +import net.automatalib.util.automata.builders.AutomatonBuilders; +import net.automatalib.util.automata.transducers.MutableMealyMachines; +import net.automatalib.words.Alphabet; +import net.automatalib.words.ProceduralInputAlphabet; +import net.automatalib.words.impl.Alphabets; +import net.automatalib.words.impl.DefaultProceduralInputAlphabet; + +public class ExamplePalindrome extends DefaultSPMMLearningExample { + + private static final char ERROR_OUTPUT = '-'; + private static final char SUCCESS_OUTPUT = '✓'; + + public ExamplePalindrome() { + super(createSPMM()); + } + + public static ExamplePalindrome createExample() { + return new ExamplePalindrome(); + } + + private static SPMM createSPMM() { + final Alphabet internalAlphabet = Alphabets.characters('a', 'c'); + final Alphabet callAlphabet = Alphabets.characters('S', 'T'); + final ProceduralInputAlphabet alphabet = + new DefaultProceduralInputAlphabet<>(internalAlphabet, callAlphabet, 'R'); + + final MealyMachine sProcedure = buildSProcedure(alphabet); + final MealyMachine tProcedure = buildTProcedure(alphabet); + + final Map> subModels = new HashMap<>(); + subModels.put('S', sProcedure); + subModels.put('T', tProcedure); + + return new StackSPMM<>(alphabet, 'S', SUCCESS_OUTPUT, ERROR_OUTPUT, subModels); + } + + private static MealyMachine buildSProcedure(ProceduralInputAlphabet alphabet) { + + final CompactMealy result = new CompactMealy<>(alphabet); + + // @formatter:off + AutomatonBuilders.forMealy(result) + .withInitial("s0") + .from("s0").on('T').withOutput(SUCCESS_OUTPUT).to("s5") + .from("s0").on('a').withOutput('x').to("s1") + .from("s0").on('b').withOutput('y').to("s2") + .from("s0").on('R').withOutput(SUCCESS_OUTPUT).to("s6") + .from("s1").on('S').withOutput(SUCCESS_OUTPUT).to("s3") + .from("s1").on('R').withOutput(SUCCESS_OUTPUT).to("s6") + .from("s2").on('S').withOutput(SUCCESS_OUTPUT).to("s4") + .from("s2").on('R').withOutput(SUCCESS_OUTPUT).to("s6") + .from("s3").on('a').withOutput('x').to("s5") + .from("s4").on('b').withOutput('y').to("s5") + .from("s5").on('R').withOutput(SUCCESS_OUTPUT).to("s6") + .create(); + // @formatter:on + + MutableMealyMachines.complete(result, alphabet, ERROR_OUTPUT, true); + return result; + } + + private static MealyMachine buildTProcedure(ProceduralInputAlphabet alphabet) { + + final FastMealy result = new FastMealy<>(alphabet); + + // @formatter:off + AutomatonBuilders.forMealy(result) + .withInitial("t0") + .from("t0").on('S').withOutput(SUCCESS_OUTPUT).to("t3") + .from("t0").on('c').withOutput('z').to("t1") + .from("t1").on('T').withOutput(SUCCESS_OUTPUT).to("t2") + .from("t1").on('R').withOutput(SUCCESS_OUTPUT).to("t4") + .from("t2").on('c').withOutput('z').to("t3") + .from("t3").on('R').withOutput(SUCCESS_OUTPUT).to("t4") + .create(); + // @formatter:on + + MutableMealyMachines.complete(result, alphabet, ERROR_OUTPUT, true); + return result; + } +}