From e5d202615bff375aa33cd34bab4e98a20eed5da4 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 28 Jul 2025 22:31:51 +0200 Subject: [PATCH 01/10] initial work on kWayOracles --- .../KWayStateCoverageEQOracle.java | 89 ++++++++++++++++++ .../KWayTransitionCoverageEqOracle.java | 92 +++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverageEqOracle.java diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java new file mode 100644 index 000000000..f44fe6c2f --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java @@ -0,0 +1,89 @@ +/* Copyright (C) 2013-2025 TU Dortmund University + * This file is part of LearnLib . + * + * 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; + +import de.learnlib.oracle.MembershipOracle; +import java.util.Collection; +import java.util.Random; +import java.util.stream.Stream; +import net.automatalib.automaton.UniversalDeterministicAutomaton; +import net.automatalib.automaton.concept.Output; +import net.automatalib.common.util.collection.IteratorUtil; +import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator; +import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator.CombinationMethod; +import net.automatalib.word.Word; + +/** + * A test case will be computed for every k-combination or k-permutation of states with additional random walk at the + * end. + */ +public class KWayStateCoverageEQOracle & Output, S, I, T, D> + extends AbstractTestWordEQOracle { + + private final Random random; + private final int k; + private final int randomWalkLen; + private final CombinationMethod method; + + public KWayStateCoverageEQOracle(MembershipOracle oracle) { + this(oracle, new Random(), 1); + } + + /** + * Initializes the KWayStateCoverageEqOracle. + * + * @param oracle + * system under learning + */ + public KWayStateCoverageEQOracle(MembershipOracle oracle, Random random, int batchSize) { + this(oracle, random, batchSize, 2, 20, CombinationMethod.Permutations); + } + + /** + * Initializes the KWayStateCoverageEqOracle. + * + * @param oracle + * system under learning + * @param k + * k value used for k-wise combinations/permutations of states + * @param randomWalkLen + * length of random walk performed at the end of each combination/permutation + * @param method + * either 'combinations' or 'permutations' + */ + public KWayStateCoverageEQOracle(MembershipOracle oracle, + Random random, + int batchSize, + int k, + int randomWalkLen, + CombinationMethod method) { + super(oracle, batchSize); + this.random = random; + this.k = k; + this.randomWalkLen = randomWalkLen; + this.method = method; + } + + @Override + protected Stream> generateTestWords(A hypothesis, Collection inputs) { + return IteratorUtil.stream(new KWayStateCoverTestsIterator<>(hypothesis, + inputs, + random, + k, + randomWalkLen, + method)); + } +} \ No newline at end of file diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverageEqOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverageEqOracle.java new file mode 100644 index 000000000..d5ac59f58 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverageEqOracle.java @@ -0,0 +1,92 @@ +package de.learnlib.oracle.equivalence; + +import de.learnlib.oracle.MembershipOracle; +import java.util.Collection; +import java.util.Random; +import java.util.stream.Stream; +import net.automatalib.automaton.UniversalDeterministicAutomaton; +import net.automatalib.automaton.concept.Output; +import net.automatalib.common.util.collection.IteratorUtil; +import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator; +import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator.Method; +import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator.Optimize; +import net.automatalib.word.Word; + +/** + * This Equivalence oracle selects test cases based on k-way transitions coverage. It does that by generating random + * queries and finding the smallest subset with the highest coverage. In other words, this oracle finds counter examples + * by running random paths that cover all pairwise / k-way transitions. + */ +public class KWayTransitionCoverageEqOracle & Output, S, I, T, D> + extends AbstractTestWordEQOracle { + + private final int k; + private final Method method; + private final int numGeneratePaths; + private final int maxPathLen; + private final int maxNumberOfSteps; + private final Optimize optimize; + private final int randomWalkLen; + private final Random random; + + /** + * Initializes the KWayTransitionCoverageEqOracle. + * + * @param batchSize + * batch size + * @param oracle + * system under learning + * @param random + * random + * @param k + * k value used for K-Way transitions, i.e., number of steps between start and end of a transition + * @param method + * defines how the queries are generated 'random' or 'prefix' + * @param numGeneratePaths + * number of random queries used to find the optimal subset + * @param maxPathLen + * maximum step size of a generated path + * @param maxNumberOfSteps + * maximum number of steps executed on the SUL (0 = no limit) + * @param optimize + * minimize either the number of 'steps' or 'queries' executed + * @param randomWalkLen + * number of steps added by 'prefix' generated paths + */ + public KWayTransitionCoverageEqOracle(MembershipOracle oracle, + Random random, + int batchSize, + int k, + Method method, + int numGeneratePaths, + int maxPathLen, + int maxNumberOfSteps, + Optimize optimize, + int randomWalkLen) { + super(oracle, batchSize); + assert k > 1; + + this.random = random; + this.k = k; + this.method = method; + this.numGeneratePaths = numGeneratePaths; + this.maxPathLen = maxPathLen; + this.maxNumberOfSteps = maxNumberOfSteps; + this.optimize = optimize; + this.randomWalkLen = randomWalkLen; + } + + @Override + protected Stream> generateTestWords(A hypothesis, Collection inputs) { + return IteratorUtil.stream(new KWayTransitionCoverTestsIterator<>(hypothesis, + inputs, + random, + k, + method, + numGeneratePaths, + maxPathLen, + maxNumberOfSteps, + optimize, + randomWalkLen)); + } +} From f7e632a14482578223d2dbc4ff5200b10635f2e2 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Tue, 29 Jul 2025 14:25:53 +0200 Subject: [PATCH 02/10] cleanups --- .../KWayStateCoverageEQOracle.java | 28 +++--------- .../KWayTransitionCoverageEqOracle.java | 43 ++++++++----------- 2 files changed, 24 insertions(+), 47 deletions(-) diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java index f44fe6c2f..8d79d5853 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java @@ -15,10 +15,11 @@ */ package de.learnlib.oracle.equivalence; -import de.learnlib.oracle.MembershipOracle; import java.util.Collection; import java.util.Random; import java.util.stream.Stream; + +import de.learnlib.oracle.MembershipOracle; import net.automatalib.automaton.UniversalDeterministicAutomaton; import net.automatalib.automaton.concept.Output; import net.automatalib.common.util.collection.IteratorUtil; @@ -33,6 +34,9 @@ public class KWayStateCoverageEQOracle & Output, S, I, T, D> extends AbstractTestWordEQOracle { + private static final int DEFAULT_K = 2; + private static final int DEFAULT_RANDOM_WALK_LENGTH = 20; + private final Random random; private final int k; private final int randomWalkLen; @@ -42,28 +46,10 @@ public KWayStateCoverageEQOracle(MembershipOracle oracle) { this(oracle, new Random(), 1); } - /** - * Initializes the KWayStateCoverageEqOracle. - * - * @param oracle - * system under learning - */ public KWayStateCoverageEQOracle(MembershipOracle oracle, Random random, int batchSize) { - this(oracle, random, batchSize, 2, 20, CombinationMethod.Permutations); + this(oracle, random, batchSize, DEFAULT_K, DEFAULT_RANDOM_WALK_LENGTH, CombinationMethod.PERMUTATIONS); } - /** - * Initializes the KWayStateCoverageEqOracle. - * - * @param oracle - * system under learning - * @param k - * k value used for k-wise combinations/permutations of states - * @param randomWalkLen - * length of random walk performed at the end of each combination/permutation - * @param method - * either 'combinations' or 'permutations' - */ public KWayStateCoverageEQOracle(MembershipOracle oracle, Random random, int batchSize, @@ -86,4 +72,4 @@ protected Stream> generateTestWords(A hypothesis, Collection. + * + * 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; -import de.learnlib.oracle.MembershipOracle; import java.util.Collection; import java.util.Random; import java.util.stream.Stream; + +import de.learnlib.oracle.MembershipOracle; import net.automatalib.automaton.UniversalDeterministicAutomaton; import net.automatalib.automaton.concept.Output; import net.automatalib.common.util.collection.IteratorUtil; @@ -29,30 +45,6 @@ public class KWayTransitionCoverageEqOracle oracle, Random random, int batchSize, @@ -64,7 +56,6 @@ public KWayTransitionCoverageEqOracle(MembershipOracle oracle, Optimize optimize, int randomWalkLen) { super(oracle, batchSize); - assert k > 1; this.random = random; this.k = k; From 6c1aeabfc0c9b68866f413926620128b0b1d4395 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 7 Aug 2025 01:06:10 +0200 Subject: [PATCH 03/10] adjust to AutomataLib + consolidations --- .../equivalence/KWayStateCoverEQOracle.java | 119 +++++++++++++ .../KWayStateCoverageEQOracle.java | 75 -------- .../KWayTransitionCoverEQOracle.java | 162 ++++++++++++++++++ .../KWayTransitionCoverageEqOracle.java | 83 --------- .../KWayStateCoverEQOracleTest.java | 53 ++++++ .../KWayTransitionCoverEQOracleTest.java | 53 ++++++ 6 files changed, 387 insertions(+), 158 deletions(-) create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java delete mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java create mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java delete mode 100644 oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverageEqOracle.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java create mode 100644 oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java new file mode 100644 index 000000000..ef56b02e6 --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java @@ -0,0 +1,119 @@ +/* Copyright (C) 2013-2025 TU Dortmund University + * This file is part of LearnLib . + * + * 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; + +import java.util.Collection; +import java.util.Random; +import java.util.stream.Stream; + +import de.learnlib.oracle.EquivalenceOracle; +import de.learnlib.oracle.MembershipOracle; +import de.learnlib.tooling.annotation.builder.GenerateBuilder; +import net.automatalib.automaton.UniversalDeterministicAutomaton; +import net.automatalib.automaton.concept.Output; +import net.automatalib.common.util.collection.IteratorUtil; +import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator; +import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator.CombinationMethod; +import net.automatalib.word.Word; + +/** + * An {@link EquivalenceOracle} based on the concepts of mutation testing as described in the paper Learning from Faults: Mutation Testing in Active Automata + * Learning by Bernhard K. Aichernig and Martin Tappler. + *

+ * A test case will be computed for every k-combination or k-permutation of states with additional random walk at the + * end. + * + * @see KWayStateCoverTestsIterator + */ +public class KWayStateCoverEQOracle & Output, S, I, T, D> + extends AbstractTestWordEQOracle { + + private final Random random; + private final int k; + private final int randomWalkLen; + private final CombinationMethod combinationMethod; + + /** + * Constructor. + * + * @param oracle + * the oracle for accessing the system under learning + * @param random + * the random number generator to use + * @param randomWalkLen + * length of random walk performed at the end of each combination/permutation + * @param k + * k value used for k-wise combinations/permutations of states + * @param combinationMethod + * the method for computing combinations + * @param batchSize + * size of the batches sent to the membership oracle + * + * @see KWayStateCoverTestsIterator#KWayStateCoverTestsIterator(UniversalDeterministicAutomaton, Collection, Random, + * int, int, CombinationMethod) + */ + @GenerateBuilder(defaults = BuilderDefaults.class) + public KWayStateCoverEQOracle(MembershipOracle oracle, + Random random, + int randomWalkLen, + int k, + CombinationMethod combinationMethod, + int batchSize) { + super(oracle, batchSize); + this.random = random; + this.k = k; + this.randomWalkLen = randomWalkLen; + this.combinationMethod = combinationMethod; + } + + @Override + protected Stream> generateTestWords(A hypothesis, Collection inputs) { + return IteratorUtil.stream(new KWayStateCoverTestsIterator<>(hypothesis, + inputs, + random, + randomWalkLen, + k, + combinationMethod)); + } + + static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } + + static Random random() { + return new Random(); + } + + static int batchSize() { + return 1; + } + + static int k() { + return KWayStateCoverTestsIterator.DEFAULT_K; + } + + static int randomWalkLen() { + return KWayStateCoverTestsIterator.DEFAULT_R_WALK_LEN; + } + + static CombinationMethod combinationMethod() { + return CombinationMethod.PERMUTATIONS; + } + } +} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java deleted file mode 100644 index 8d79d5853..000000000 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverageEQOracle.java +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (C) 2013-2025 TU Dortmund University - * This file is part of LearnLib . - * - * 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; - -import java.util.Collection; -import java.util.Random; -import java.util.stream.Stream; - -import de.learnlib.oracle.MembershipOracle; -import net.automatalib.automaton.UniversalDeterministicAutomaton; -import net.automatalib.automaton.concept.Output; -import net.automatalib.common.util.collection.IteratorUtil; -import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator; -import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator.CombinationMethod; -import net.automatalib.word.Word; - -/** - * A test case will be computed for every k-combination or k-permutation of states with additional random walk at the - * end. - */ -public class KWayStateCoverageEQOracle & Output, S, I, T, D> - extends AbstractTestWordEQOracle { - - private static final int DEFAULT_K = 2; - private static final int DEFAULT_RANDOM_WALK_LENGTH = 20; - - private final Random random; - private final int k; - private final int randomWalkLen; - private final CombinationMethod method; - - public KWayStateCoverageEQOracle(MembershipOracle oracle) { - this(oracle, new Random(), 1); - } - - public KWayStateCoverageEQOracle(MembershipOracle oracle, Random random, int batchSize) { - this(oracle, random, batchSize, DEFAULT_K, DEFAULT_RANDOM_WALK_LENGTH, CombinationMethod.PERMUTATIONS); - } - - public KWayStateCoverageEQOracle(MembershipOracle oracle, - Random random, - int batchSize, - int k, - int randomWalkLen, - CombinationMethod method) { - super(oracle, batchSize); - this.random = random; - this.k = k; - this.randomWalkLen = randomWalkLen; - this.method = method; - } - - @Override - protected Stream> generateTestWords(A hypothesis, Collection inputs) { - return IteratorUtil.stream(new KWayStateCoverTestsIterator<>(hypothesis, - inputs, - random, - k, - randomWalkLen, - method)); - } -} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java new file mode 100644 index 000000000..71113d41d --- /dev/null +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java @@ -0,0 +1,162 @@ +/* Copyright (C) 2013-2025 TU Dortmund University + * This file is part of LearnLib . + * + * 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; + +import java.util.Collection; +import java.util.Random; +import java.util.stream.Stream; + +import de.learnlib.oracle.EquivalenceOracle; +import de.learnlib.oracle.MembershipOracle; +import de.learnlib.tooling.annotation.builder.GenerateBuilder; +import net.automatalib.automaton.UniversalDeterministicAutomaton; +import net.automatalib.automaton.concept.Output; +import net.automatalib.common.util.collection.IteratorUtil; +import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator; +import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator.GenerationMethod; +import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator.OptimizationMetric; +import net.automatalib.word.Word; + +/** + * An {@link EquivalenceOracle} based on the concepts of mutation testing as described in the paper Learning from Faults: Mutation Testing in Active Automata + * Learning by Bernhard K. Aichernig and Martin Tappler. + *

+ * This Equivalence oracle selects test cases based on k-way transitions coverage. It does that by generating random + * queries and finding the smallest subset with the highest coverage. In other words, this oracle finds counter examples + * by running random paths that cover all pairwise / k-way transitions. + * + * @see KWayTransitionCoverTestsIterator + */ +public class KWayTransitionCoverEQOracle & Output, S, I, T, D> + extends AbstractTestWordEQOracle { + + private final int k; + private final GenerationMethod generationMethod; + private final int numGeneratePaths; + private final int maxPathLen; + private final int maxNumberOfSteps; + private final OptimizationMetric optimizationMetric; + private final int randomWalkLen; + private final Random random; + + /** + * Constructor. + * + * @param oracle + * the oracle for accessing the system under learning + * @param random + * the random number generator to use + * @param randomWalkLen + * the number of steps that are added by 'prefix' generated paths + * @param numGeneratePaths + * number of random queries used to find the optimal subset + * @param maxPathLen + * the maximum step size of a generated path + * @param maxNumberOfSteps + * maximum number of steps that will be executed on the automaton (<=0 = no limit) + * @param k + * k value used for K-Way transitions, i.e the number of steps between the start and the end of a + * transition + * @param generationMethod + * defines how the queries are generated 'random' or 'prefix' + * @param optimizationMetric + * minimize either the number of 'steps' or 'queries' that are executed + * @param batchSize + * size of the batches sent to the membership oracle + * + * @see KWayTransitionCoverTestsIterator#KWayTransitionCoverTestsIterator(UniversalDeterministicAutomaton, + * Collection, Random, int, int, int, int, int, GenerationMethod, OptimizationMetric) + */ + @GenerateBuilder(defaults = BuilderDefaults.class) + public KWayTransitionCoverEQOracle(MembershipOracle oracle, + Random random, + int randomWalkLen, + int numGeneratePaths, + int maxPathLen, + int maxNumberOfSteps, + int k, + GenerationMethod generationMethod, + OptimizationMetric optimizationMetric, + int batchSize) { + super(oracle, batchSize); + this.random = random; + this.k = k; + this.generationMethod = generationMethod; + this.numGeneratePaths = numGeneratePaths; + this.maxPathLen = maxPathLen; + this.maxNumberOfSteps = maxNumberOfSteps; + this.optimizationMetric = optimizationMetric; + this.randomWalkLen = randomWalkLen; + } + + @Override + protected Stream> generateTestWords(A hypothesis, Collection inputs) { + return IteratorUtil.stream(new KWayTransitionCoverTestsIterator<>(hypothesis, + inputs, + random, + randomWalkLen, + numGeneratePaths, + maxPathLen, + maxNumberOfSteps, + k, + generationMethod, + optimizationMetric)); + } + + static final class BuilderDefaults { + + private BuilderDefaults() { + // prevent instantiation + } + + static Random random() { + return new Random(); + } + + static int batchSize() { + return 1; + } + + static int k() { + return KWayTransitionCoverTestsIterator.DEFAULT_K; + } + + static GenerationMethod generationMethod() { + return GenerationMethod.RANDOM; + } + + static int numGeneratePaths() { + return KWayTransitionCoverTestsIterator.DEFAULT_NUM_GEN_PATHS; + } + + static int maxPathLen() { + return KWayTransitionCoverTestsIterator.DEFAULT_MAX_PATH_LENGTH; + } + + static int maxNumberOfSteps() { + return KWayTransitionCoverTestsIterator.DEFAULT_MAX_NUM_STEPS; + } + + static OptimizationMetric optimizationMetric() { + return OptimizationMetric.STEPS; + } + + static int randomWalkLen() { + return KWayTransitionCoverTestsIterator.DEFAULT_R_WALK_LEN; + } + } +} diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverageEqOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverageEqOracle.java deleted file mode 100644 index d6e23163d..000000000 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverageEqOracle.java +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (C) 2013-2025 TU Dortmund University - * This file is part of LearnLib . - * - * 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; - -import java.util.Collection; -import java.util.Random; -import java.util.stream.Stream; - -import de.learnlib.oracle.MembershipOracle; -import net.automatalib.automaton.UniversalDeterministicAutomaton; -import net.automatalib.automaton.concept.Output; -import net.automatalib.common.util.collection.IteratorUtil; -import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator; -import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator.Method; -import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator.Optimize; -import net.automatalib.word.Word; - -/** - * This Equivalence oracle selects test cases based on k-way transitions coverage. It does that by generating random - * queries and finding the smallest subset with the highest coverage. In other words, this oracle finds counter examples - * by running random paths that cover all pairwise / k-way transitions. - */ -public class KWayTransitionCoverageEqOracle & Output, S, I, T, D> - extends AbstractTestWordEQOracle { - - private final int k; - private final Method method; - private final int numGeneratePaths; - private final int maxPathLen; - private final int maxNumberOfSteps; - private final Optimize optimize; - private final int randomWalkLen; - private final Random random; - - public KWayTransitionCoverageEqOracle(MembershipOracle oracle, - Random random, - int batchSize, - int k, - Method method, - int numGeneratePaths, - int maxPathLen, - int maxNumberOfSteps, - Optimize optimize, - int randomWalkLen) { - super(oracle, batchSize); - - this.random = random; - this.k = k; - this.method = method; - this.numGeneratePaths = numGeneratePaths; - this.maxPathLen = maxPathLen; - this.maxNumberOfSteps = maxNumberOfSteps; - this.optimize = optimize; - this.randomWalkLen = randomWalkLen; - } - - @Override - protected Stream> generateTestWords(A hypothesis, Collection inputs) { - return IteratorUtil.stream(new KWayTransitionCoverTestsIterator<>(hypothesis, - inputs, - random, - k, - method, - numGeneratePaths, - maxPathLen, - maxNumberOfSteps, - optimize, - randomWalkLen)); - } -} diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java new file mode 100644 index 000000000..8e6a82860 --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2013-2025 TU Dortmund University + * This file is part of LearnLib . + * + * 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; + +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +import net.automatalib.alphabet.Alphabet; +import net.automatalib.alphabet.impl.Alphabets; +import net.automatalib.automaton.fsa.DFA; +import net.automatalib.automaton.fsa.impl.CompactDFA; +import net.automatalib.common.util.collection.IteratorUtil; +import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator; +import net.automatalib.util.automaton.random.RandomAutomata; +import net.automatalib.word.Word; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class KWayStateCoverEQOracleTest { + + private static final int SIZE = 10; + + @Test + public void testOracle() { + final int seed = 42; + final Alphabet alphabet = Alphabets.characters('a', 'c'); + final CompactDFA dfa = RandomAutomata.randomDFA(new Random(seed), SIZE, alphabet); + + final KWayStateCoverEQOracle, Integer, Character, Integer, Boolean> oracle = + new KWayStateCoverEQOracleBuilder, Integer, Character, Integer, Boolean>().withRandom( + new Random(seed)).create(); + + List> tests = oracle.generateTestWords(dfa, alphabet).collect(Collectors.toList()); + List> iter = + IteratorUtil.list(new KWayStateCoverTestsIterator<>(dfa, alphabet, new Random(seed))); + + Assert.assertEquals(tests, iter); + } +} diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java new file mode 100644 index 000000000..b0dda9f1f --- /dev/null +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2013-2025 TU Dortmund University + * This file is part of LearnLib . + * + * 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; + +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +import net.automatalib.alphabet.Alphabet; +import net.automatalib.alphabet.impl.Alphabets; +import net.automatalib.automaton.fsa.DFA; +import net.automatalib.automaton.fsa.impl.CompactDFA; +import net.automatalib.common.util.collection.IteratorUtil; +import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator; +import net.automatalib.util.automaton.random.RandomAutomata; +import net.automatalib.word.Word; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class KWayTransitionCoverEQOracleTest { + + private static final int SIZE = 10; + + @Test + public void testOracle() { + final int seed = 42; + final Alphabet alphabet = Alphabets.characters('a', 'c'); + final CompactDFA dfa = RandomAutomata.randomDFA(new Random(seed), SIZE, alphabet); + + final KWayStateCoverEQOracle, Integer, Character, Integer, Boolean> oracle = + new KWayStateCoverEQOracleBuilder, Integer, Character, Integer, Boolean>().withRandom( + new Random(seed)).create(); + + List> tests = oracle.generateTestWords(dfa, alphabet).collect(Collectors.toList()); + List> iter = + IteratorUtil.list(new KWayStateCoverTestsIterator<>(dfa, alphabet, new Random(seed))); + + Assert.assertEquals(tests, iter); + } +} From 267ea1754d40be237481f6e852d9aca36bf57000 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 7 Aug 2025 14:56:15 +0200 Subject: [PATCH 04/10] adjust to upstream changes --- .../de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java | 2 +- .../oracle/equivalence/KWayTransitionCoverEQOracle.java | 2 +- .../oracle/equivalence/KWayStateCoverEQOracleTest.java | 3 ++- .../oracle/equivalence/KWayTransitionCoverEQOracleTest.java | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java index ef56b02e6..fe9a06e99 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java @@ -81,7 +81,7 @@ public KWayStateCoverEQOracle(MembershipOracle oracle, } @Override - protected Stream> generateTestWords(A hypothesis, Collection inputs) { + public Stream> generateTestWords(A hypothesis, Collection inputs) { return IteratorUtil.stream(new KWayStateCoverTestsIterator<>(hypothesis, inputs, random, diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java index 71113d41d..95ec7888a 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java @@ -104,7 +104,7 @@ public KWayTransitionCoverEQOracle(MembershipOracle oracle, } @Override - protected Stream> generateTestWords(A hypothesis, Collection inputs) { + public Stream> generateTestWords(A hypothesis, Collection inputs) { return IteratorUtil.stream(new KWayTransitionCoverTestsIterator<>(hypothesis, inputs, random, diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java index 8e6a82860..01a1c66ee 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java @@ -19,6 +19,7 @@ import java.util.Random; import java.util.stream.Collectors; +import de.learnlib.TestWordGenerator; import net.automatalib.alphabet.Alphabet; import net.automatalib.alphabet.impl.Alphabets; import net.automatalib.automaton.fsa.DFA; @@ -40,7 +41,7 @@ public void testOracle() { final Alphabet alphabet = Alphabets.characters('a', 'c'); final CompactDFA dfa = RandomAutomata.randomDFA(new Random(seed), SIZE, alphabet); - final KWayStateCoverEQOracle, Integer, Character, Integer, Boolean> oracle = + final TestWordGenerator, Character> oracle = new KWayStateCoverEQOracleBuilder, Integer, Character, Integer, Boolean>().withRandom( new Random(seed)).create(); diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java index b0dda9f1f..08b45cd8f 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java @@ -19,6 +19,7 @@ import java.util.Random; import java.util.stream.Collectors; +import de.learnlib.TestWordGenerator; import net.automatalib.alphabet.Alphabet; import net.automatalib.alphabet.impl.Alphabets; import net.automatalib.automaton.fsa.DFA; @@ -40,7 +41,7 @@ public void testOracle() { final Alphabet alphabet = Alphabets.characters('a', 'c'); final CompactDFA dfa = RandomAutomata.randomDFA(new Random(seed), SIZE, alphabet); - final KWayStateCoverEQOracle, Integer, Character, Integer, Boolean> oracle = + final TestWordGenerator, Character> oracle = new KWayStateCoverEQOracleBuilder, Integer, Character, Integer, Boolean>().withRandom( new Random(seed)).create(); From a128d7b64e8cf62a83bb5910d17ee6c26c5762f9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sun, 10 Aug 2025 02:55:14 +0200 Subject: [PATCH 05/10] reorder attributes --- .../equivalence/KWayStateCoverEQOracle.java | 2 +- .../KWayTransitionCoverEQOracle.java | 36 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java index fe9a06e99..cce4ad5a7 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java @@ -43,8 +43,8 @@ public class KWayStateCoverEQOracle { private final Random random; - private final int k; private final int randomWalkLen; + private final int k; private final CombinationMethod combinationMethod; /** diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java index 95ec7888a..f8f8885ab 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java @@ -44,14 +44,14 @@ public class KWayTransitionCoverEQOracle & Output, S, I, T, D> extends AbstractTestWordEQOracle { - private final int k; - private final GenerationMethod generationMethod; + private final Random random; + private final int randomWalkLen; private final int numGeneratePaths; private final int maxPathLen; private final int maxNumberOfSteps; + private final int k; private final OptimizationMetric optimizationMetric; - private final int randomWalkLen; - private final Random random; + private final GenerationMethod generationMethod; /** * Constructor. @@ -61,25 +61,25 @@ public class KWayTransitionCoverEQOracle oracle, @@ -89,18 +89,18 @@ public KWayTransitionCoverEQOracle(MembershipOracle oracle, int maxPathLen, int maxNumberOfSteps, int k, - GenerationMethod generationMethod, OptimizationMetric optimizationMetric, + GenerationMethod generationMethod, int batchSize) { super(oracle, batchSize); this.random = random; - this.k = k; - this.generationMethod = generationMethod; + this.randomWalkLen = randomWalkLen; this.numGeneratePaths = numGeneratePaths; this.maxPathLen = maxPathLen; this.maxNumberOfSteps = maxNumberOfSteps; + this.k = k; this.optimizationMetric = optimizationMetric; - this.randomWalkLen = randomWalkLen; + this.generationMethod = generationMethod; } @Override @@ -113,8 +113,8 @@ public Stream> generateTestWords(A hypothesis, Collection i maxPathLen, maxNumberOfSteps, k, - generationMethod, - optimizationMetric)); + optimizationMetric, + generationMethod)); } static final class BuilderDefaults { From 10274b098095b78cf0abe99d3407ee7b537b6bb3 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sun, 10 Aug 2025 14:34:30 +0200 Subject: [PATCH 06/10] test the correct oracle --- .../oracle/equivalence/KWayTransitionCoverEQOracleTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java index 08b45cd8f..0e4e6b981 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java @@ -25,7 +25,7 @@ import net.automatalib.automaton.fsa.DFA; import net.automatalib.automaton.fsa.impl.CompactDFA; import net.automatalib.common.util.collection.IteratorUtil; -import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator; +import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator; import net.automatalib.util.automaton.random.RandomAutomata; import net.automatalib.word.Word; import org.testng.Assert; @@ -42,12 +42,12 @@ public void testOracle() { final CompactDFA dfa = RandomAutomata.randomDFA(new Random(seed), SIZE, alphabet); final TestWordGenerator, Character> oracle = - new KWayStateCoverEQOracleBuilder, Integer, Character, Integer, Boolean>().withRandom( + new KWayTransitionCoverEQOracleBuilder, Integer, Character, Integer, Boolean>().withRandom( new Random(seed)).create(); List> tests = oracle.generateTestWords(dfa, alphabet).collect(Collectors.toList()); List> iter = - IteratorUtil.list(new KWayStateCoverTestsIterator<>(dfa, alphabet, new Random(seed))); + IteratorUtil.list(new KWayTransitionCoverTestsIterator<>(dfa, alphabet, new Random(seed))); Assert.assertEquals(tests, iter); } From a8be5a1dfc3d443326dfa5edeba962db67280370 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Sat, 23 Aug 2025 01:17:29 +0200 Subject: [PATCH 07/10] hide some type variables --- .../equivalence/KWayStateCoverEQOracle.java | 22 +++++++++++-- .../KWayTransitionCoverEQOracle.java | 33 ++++++++++++++++++- .../KWayStateCoverEQOracleTest.java | 4 +-- .../KWayTransitionCoverEQOracleTest.java | 4 +-- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java index cce4ad5a7..ef057ef17 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java @@ -37,9 +37,16 @@ * A test case will be computed for every k-combination or k-permutation of states with additional random walk at the * end. * + * @param + * automaton type + * @param + * input symbol type + * @param + * output domain + * * @see KWayStateCoverTestsIterator */ -public class KWayStateCoverEQOracle & Output, S, I, T, D> +public class KWayStateCoverEQOracle & Output, I, D> extends AbstractTestWordEQOracle { private final Random random; @@ -75,13 +82,24 @@ public KWayStateCoverEQOracle(MembershipOracle oracle, int batchSize) { super(oracle, batchSize); this.random = random; - this.k = k; this.randomWalkLen = randomWalkLen; + this.k = k; this.combinationMethod = combinationMethod; } @Override public Stream> generateTestWords(A hypothesis, Collection inputs) { + final UniversalDeterministicAutomaton casted = hypothesis; + return doGenerateTestWords(casted, inputs, this.random, this.randomWalkLen, this.k, this.combinationMethod); + } + + private static , S, I, T> Stream> doGenerateTestWords( + A hypothesis, + Collection inputs, + Random random, + int randomWalkLen, + int k, + CombinationMethod combinationMethod) { return IteratorUtil.stream(new KWayStateCoverTestsIterator<>(hypothesis, inputs, random, diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java index f8f8885ab..8df306012 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java @@ -39,9 +39,16 @@ * queries and finding the smallest subset with the highest coverage. In other words, this oracle finds counter examples * by running random paths that cover all pairwise / k-way transitions. * + * @param + * automaton type + * @param + * input symbol type + * @param + * output domain + * * @see KWayTransitionCoverTestsIterator */ -public class KWayTransitionCoverEQOracle & Output, S, I, T, D> +public class KWayTransitionCoverEQOracle & Output, I, D> extends AbstractTestWordEQOracle { private final Random random; @@ -105,6 +112,30 @@ public KWayTransitionCoverEQOracle(MembershipOracle oracle, @Override public Stream> generateTestWords(A hypothesis, Collection inputs) { + final UniversalDeterministicAutomaton casted = hypothesis; + return doGenerateTestWords(casted, + inputs, + this.random, + this.randomWalkLen, + this.numGeneratePaths, + this.maxPathLen, + this.maxNumberOfSteps, + this.k, + this.optimizationMetric, + this.generationMethod); + } + + private static , S, I, T> Stream> doGenerateTestWords( + A hypothesis, + Collection inputs, + Random random, + int randomWalkLen, + int numGeneratePaths, + int maxPathLen, + int maxNumberOfSteps, + int k, + OptimizationMetric optimizationMetric, + GenerationMethod generationMethod) { return IteratorUtil.stream(new KWayTransitionCoverTestsIterator<>(hypothesis, inputs, random, diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java index 01a1c66ee..0977a2e0f 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracleTest.java @@ -42,8 +42,8 @@ public void testOracle() { final CompactDFA dfa = RandomAutomata.randomDFA(new Random(seed), SIZE, alphabet); final TestWordGenerator, Character> oracle = - new KWayStateCoverEQOracleBuilder, Integer, Character, Integer, Boolean>().withRandom( - new Random(seed)).create(); + new KWayStateCoverEQOracleBuilder, Character, Boolean>().withRandom(new Random( + seed)).create(); List> tests = oracle.generateTestWords(dfa, alphabet).collect(Collectors.toList()); List> iter = diff --git a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java index 0e4e6b981..f527f446a 100644 --- a/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java +++ b/oracles/equivalence-oracles/src/test/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracleTest.java @@ -42,8 +42,8 @@ public void testOracle() { final CompactDFA dfa = RandomAutomata.randomDFA(new Random(seed), SIZE, alphabet); final TestWordGenerator, Character> oracle = - new KWayTransitionCoverEQOracleBuilder, Integer, Character, Integer, Boolean>().withRandom( - new Random(seed)).create(); + new KWayTransitionCoverEQOracleBuilder, Character, Boolean>().withRandom(new Random( + seed)).create(); List> tests = oracle.generateTestWords(dfa, alphabet).collect(Collectors.toList()); List> iter = From 3e26a5f699bd45a6565cc0362b4a95437ab005b9 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Thu, 13 Nov 2025 14:27:37 +0100 Subject: [PATCH 08/10] add additional documentation --- .../learnlib/oracle/equivalence/KWayStateCoverEQOracle.java | 5 +++++ .../oracle/equivalence/KWayTransitionCoverEQOracle.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java index ef057ef17..019a99a4e 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java @@ -36,6 +36,11 @@ *

* A test case will be computed for every k-combination or k-permutation of states with additional random walk at the * end. + *

+ * Implementation detail: Note that this test generator heavily relies on the sampling of states. If the given + * automaton has very few or very many states, the number of generated test cases may be very low or high, respectively. + * As a result, it may be advisable to {@link EQOracleChain combine} this generator with other generators or limit the + * number of generated test cases. * * @param * automaton type diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java index 8df306012..74dec83b9 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java @@ -38,6 +38,11 @@ * This Equivalence oracle selects test cases based on k-way transitions coverage. It does that by generating random * queries and finding the smallest subset with the highest coverage. In other words, this oracle finds counter examples * by running random paths that cover all pairwise / k-way transitions. + *

+ * Implementation detail: Note that this test generator heavily relies on the sampling of states. If the given + * automaton has very few or very many states, the number of generated test cases may be very low or high, respectively. + * As a result, it may be advisable to {@link EQOracleChain combine} this generator with other generators or limit the + * number of generated test cases. * * @param * automaton type From bb45703ce2e375048bb3a8dc2e334607dd62f45f Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 15 Dec 2025 17:52:55 +0100 Subject: [PATCH 09/10] cleanups * adjust configs * declutter type information --- build-parent/pom.xml | 1 + .../equivalence/KWayStateCoverEQOracle.java | 23 +++++++------- .../KWayTransitionCoverEQOracle.java | 31 +++++++++---------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 73bfdf7f3..b1b2e8f64 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -62,6 +62,7 @@ limitations under the License. de/learnlib/filter/reuse/**/Reuse*Builder.class + de/learnlib/oracle/equivalence/KWay*Builder.class de/learnlib/filter/cache/**/*Interning*.class diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java index 019a99a4e..ee2c31dcf 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayStateCoverEQOracle.java @@ -22,7 +22,7 @@ import de.learnlib.oracle.EquivalenceOracle; import de.learnlib.oracle.MembershipOracle; import de.learnlib.tooling.annotation.builder.GenerateBuilder; -import net.automatalib.automaton.UniversalDeterministicAutomaton; +import net.automatalib.automaton.DeterministicAutomaton; import net.automatalib.automaton.concept.Output; import net.automatalib.common.util.collection.IteratorUtil; import net.automatalib.util.automaton.conformance.KWayStateCoverTestsIterator; @@ -51,7 +51,7 @@ * * @see KWayStateCoverTestsIterator */ -public class KWayStateCoverEQOracle & Output, I, D> +public class KWayStateCoverEQOracle & Output, I, D> extends AbstractTestWordEQOracle { private final Random random; @@ -75,8 +75,8 @@ public class KWayStateCoverEQOracle oracle, @@ -94,17 +94,16 @@ public KWayStateCoverEQOracle(MembershipOracle oracle, @Override public Stream> generateTestWords(A hypothesis, Collection inputs) { - final UniversalDeterministicAutomaton casted = hypothesis; + final DeterministicAutomaton casted = hypothesis; return doGenerateTestWords(casted, inputs, this.random, this.randomWalkLen, this.k, this.combinationMethod); } - private static , S, I, T> Stream> doGenerateTestWords( - A hypothesis, - Collection inputs, - Random random, - int randomWalkLen, - int k, - CombinationMethod combinationMethod) { + private static , S, I> Stream> doGenerateTestWords(A hypothesis, + Collection inputs, + Random random, + int randomWalkLen, + int k, + CombinationMethod combinationMethod) { return IteratorUtil.stream(new KWayStateCoverTestsIterator<>(hypothesis, inputs, random, diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java index 74dec83b9..e64fd3170 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java @@ -22,7 +22,7 @@ import de.learnlib.oracle.EquivalenceOracle; import de.learnlib.oracle.MembershipOracle; import de.learnlib.tooling.annotation.builder.GenerateBuilder; -import net.automatalib.automaton.UniversalDeterministicAutomaton; +import net.automatalib.automaton.DeterministicAutomaton; import net.automatalib.automaton.concept.Output; import net.automatalib.common.util.collection.IteratorUtil; import net.automatalib.util.automaton.conformance.KWayTransitionCoverTestsIterator; @@ -53,7 +53,7 @@ * * @see KWayTransitionCoverTestsIterator */ -public class KWayTransitionCoverEQOracle & Output, I, D> +public class KWayTransitionCoverEQOracle & Output, I, D> extends AbstractTestWordEQOracle { private final Random random; @@ -90,8 +90,8 @@ public class KWayTransitionCoverEQOracle oracle, @@ -117,7 +117,7 @@ public KWayTransitionCoverEQOracle(MembershipOracle oracle, @Override public Stream> generateTestWords(A hypothesis, Collection inputs) { - final UniversalDeterministicAutomaton casted = hypothesis; + final DeterministicAutomaton casted = hypothesis; return doGenerateTestWords(casted, inputs, this.random, @@ -130,17 +130,16 @@ public Stream> generateTestWords(A hypothesis, Collection i this.generationMethod); } - private static , S, I, T> Stream> doGenerateTestWords( - A hypothesis, - Collection inputs, - Random random, - int randomWalkLen, - int numGeneratePaths, - int maxPathLen, - int maxNumberOfSteps, - int k, - OptimizationMetric optimizationMetric, - GenerationMethod generationMethod) { + private static , S, I> Stream> doGenerateTestWords(A hypothesis, + Collection inputs, + Random random, + int randomWalkLen, + int numGeneratePaths, + int maxPathLen, + int maxNumberOfSteps, + int k, + OptimizationMetric optimizationMetric, + GenerationMethod generationMethod) { return IteratorUtil.stream(new KWayTransitionCoverTestsIterator<>(hypothesis, inputs, random, From 3b815a28830ff5d8b2c2f8d12dc42f08fa94fe23 Mon Sep 17 00:00:00 2001 From: Markus Frohme Date: Mon, 15 Dec 2025 18:03:01 +0100 Subject: [PATCH 10/10] do not use special characters in documentation --- .../oracle/equivalence/KWayTransitionCoverEQOracle.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java index e64fd3170..d8cf93e1d 100644 --- a/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java +++ b/oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/KWayTransitionCoverEQOracle.java @@ -79,7 +79,8 @@ public class KWayTransitionCoverEQOracle