Skip to content

Commit e5e6d39

Browse files
committed
equivalence-oracles: add EarlyExitEQOracle
1 parent ee368bf commit e5e6d39

19 files changed

+342
-29
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
[Full changelog](https://github.com/LearnLib/learnlib/compare/learnlib-0.18.0...HEAD)
88

9+
### Added
10+
11+
* Added an `EarlyExitEQOracle` which for a given `AdaptiveMembershipOracle` and `TestWordGenerator` stops the evaluation of (potentially long) Mealy-based equivalence tests as soon as a mismatch with the hypothesis is detected, potentially improving the symbol performance of the given equivalence oracle.
12+
913
### Changed
1014

1115
* LearnLib now requires Java 11 at runtime.
16+
* The `generateTestWords` method of `AbstractTestWordEQOracle` now needs to be public.
1217

1318
### Fixed
1419

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* Copyright (C) 2013-2025 TU Dortmund University
2+
* This file is part of LearnLib <https://learnlib.de>.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package de.learnlib;
17+
18+
import java.util.Collection;
19+
import java.util.stream.Stream;
20+
21+
import de.learnlib.oracle.EquivalenceOracle;
22+
import net.automatalib.word.Word;
23+
24+
/**
25+
* A markup interface for generators of testing sequences (such as {@link EquivalenceOracle} implementations).
26+
*
27+
* @param <A>
28+
* automaton type
29+
* @param <I>
30+
* input symbol type
31+
*/
32+
public interface TestWordGenerator<A, I> {
33+
34+
/**
35+
* Generate the stream of words that should be evaluated for the given hypothesis.
36+
*
37+
* @param hypothesis
38+
* the current hypothesis
39+
* @param inputs
40+
* the collection of inputs to consider
41+
*
42+
* @return the stream of test words used for (equivalence) testing
43+
*
44+
* @see EquivalenceOracle#findCounterExample(Object, Collection)
45+
*/
46+
Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs);
47+
}

oracles/equivalence-oracles/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ limitations under the License.
7676
</dependency>
7777

7878
<!-- test -->
79+
<dependency>
80+
<groupId>de.learnlib</groupId>
81+
<artifactId>learnlib-drivers-simulator</artifactId>
82+
<scope>test</scope>
83+
</dependency>
7984
<dependency>
8085
<groupId>de.learnlib</groupId>
8186
<artifactId>learnlib-membership-oracles</artifactId>

oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/AbstractTestWordEQOracle.java

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Objects;
2121
import java.util.stream.Stream;
2222

23+
import de.learnlib.TestWordGenerator;
2324
import de.learnlib.logging.Category;
2425
import de.learnlib.oracle.EquivalenceOracle;
2526
import de.learnlib.oracle.MembershipOracle;
@@ -33,7 +34,7 @@
3334

3435
/**
3536
* An abstract equivalence oracle that takes care of query batching and hypothesis checking and allows extending classes
36-
* to solely focus on test word generation by implementing {@link #generateTestWords(Output, Collection)}.
37+
* to solely focus on test word generation by implementing {@link #generateTestWords(Object, Collection)}}.
3738
* <p>
3839
* Being {@link Stream stream}-based, this oracle encourages the lazy computation of counterexamples, so that all
3940
* counterexamples do not have to be computed upfront, but only until the first valid counterexample is found.
@@ -45,7 +46,8 @@
4546
* @param <D>
4647
* output (domain) type
4748
*/
48-
public abstract class AbstractTestWordEQOracle<A extends Output<I, D>, I, D> implements EquivalenceOracle<A, I, D> {
49+
public abstract class AbstractTestWordEQOracle<A extends Output<I, D>, I, D>
50+
implements EquivalenceOracle<A, I, D>, TestWordGenerator<A, I> {
4951

5052
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTestWordEQOracle.class);
5153

@@ -82,20 +84,6 @@ public AbstractTestWordEQOracle(MembershipOracle<I, D> membershipOracle, int bat
8284
return ceStream.findFirst().orElse(null);
8385
}
8486

85-
/**
86-
* Generate the stream of test words that should be used for the current equivalence check cycle.
87-
*
88-
* @param hypothesis
89-
* the current hypothesis of the learning algorithm
90-
* @param inputs
91-
* the collection of inputs to consider
92-
*
93-
* @return the stream of test words used for equivalence testing
94-
*
95-
* @see EquivalenceOracle#findCounterExample(Object, Collection)
96-
*/
97-
protected abstract Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs);
98-
9987
private Stream<DefaultQuery<I, D>> answerQueries(Stream<DefaultQuery<I, D>> stream) {
10088
if (isBatched()) {
10189
return IteratorUtil.stream(IteratorUtil.batch(stream.iterator(), this.batchSize))

oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/CompleteExplorationEQOracle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public CompleteExplorationEQOracle(MembershipOracle<I, D> sulOracle, int minDept
126126
}
127127

128128
@Override
129-
protected Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
129+
public Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
130130
return IterableUtil.stream(IterableUtil.allTuples(inputs, minDepth, maxDepth)).map(Word::fromList);
131131
}
132132
}

oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/IncrementalWMethodEQOracle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public void setMaxDepth(int maxDepth) {
102102
}
103103

104104
@Override
105-
protected Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
105+
public Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
106106
// FIXME: warn about inputs being ignored?
107107
incrementalWMethodIt.update(hypothesis);
108108

oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWMethodEQOracle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public RandomWMethodEQOracle(MembershipOracle<I, D> sulOracle,
185185
}
186186

187187
@Override
188-
protected Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
188+
public Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
189189
UniversalDeterministicAutomaton<?, I, ?, ?, ?> aut = hypothesis;
190190
return doGenerateTestWords(aut, inputs);
191191
}

oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWordsEQOracle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public RandomWordsEQOracle(MembershipOracle<I, D> mqOracle,
103103
}
104104

105105
@Override
106-
protected Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
106+
public Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
107107

108108
final List<? extends I> symbolList = CollectionUtil.randomAccessList(inputs);
109109

oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/RandomWpMethodEQOracle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ public RandomWpMethodEQOracle(MembershipOracle<I, D> sulOracle,
186186
}
187187

188188
@Override
189-
protected Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
189+
public Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
190190
UniversalDeterministicAutomaton<?, I, ?, ?, ?> aut = hypothesis;
191191
return doGenerateTestWords(aut, inputs);
192192
}

oracles/equivalence-oracles/src/main/java/de/learnlib/oracle/equivalence/WMethodEQOracle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public WMethodEQOracle(MembershipOracle<I, D> sulOracle, int lookahead, int expe
151151
}
152152

153153
@Override
154-
protected Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
154+
public Stream<Word<I>> generateTestWords(A hypothesis, Collection<? extends I> inputs) {
155155
return IteratorUtil.stream(new WMethodTestsIterator<>(hypothesis,
156156
inputs,
157157
Math.max(lookahead, expectedSize - hypothesis.size())));

0 commit comments

Comments
 (0)