Skip to content

Commit d0749ae

Browse files
committed
cleanups, parallel timed oracles, test cases
1 parent 1500902 commit d0749ae

File tree

29 files changed

+1740
-109
lines changed

29 files changed

+1740
-109
lines changed

algorithms/active/lstar/src/test/java/de/learnlib/algorithm/lstar/it/ExtensibleLStarMMLTIT.java

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.nio.file.Path;
2323
import java.nio.file.Paths;
2424
import java.util.ArrayList;
25+
import java.util.Arrays;
2526
import java.util.List;
2627
import java.util.Random;
2728
import java.util.stream.Stream;
@@ -60,30 +61,27 @@ protected <I, O> void addLearnerVariants(Alphabet<I> alphabet,
6061
MMLTLearnerVariantList<I, O> variants) {
6162

6263
var mmlt = example.getReferenceAutomaton();
63-
int counters = countTimers(mmlt);
64+
var counters = countTimers(mmlt);
6465

6566
List<Word<TimedInput<I>>> suffixes = new ArrayList<>();
6667
alphabet.forEach(s -> suffixes.add(Word.fromLetter(TimedInput.input(s))));
6768
suffixes.add(Word.fromLetter(new TimeoutSymbol<>()));
6869

69-
for (FilterMode filterMode : FilterMode.values()) {
70+
var filters = Arrays.asList(new MMLTPerfectSymbolFilter<>(mmlt),
71+
new MMLTRandomSymbolFilter<>(mmlt, 0.1, new Random(42)),
72+
new IgnoreAllSymbolFilter<TimedInput<I>, InputSymbol<I>>(),
73+
new AcceptAllSymbolFilter<TimedInput<I>, InputSymbol<I>>());
7074

71-
SymbolFilter<TimedInput<I>, InputSymbol<I>> filter = switch (filterMode) {
72-
case perfect -> new MMLTPerfectSymbolFilter<>(mmlt);
73-
case random -> new MMLTRandomSymbolFilter<>(mmlt, 0.1, new Random(42));
74-
case ignore_all -> new IgnoreAllSymbolFilter<>();
75-
case none -> new AcceptAllSymbolFilter<>();
76-
};
75+
for (SymbolFilter<TimedInput<I>, InputSymbol<I>> filter : filters) {
7776

7877
var cachedFilter = new CachedSymbolFilter<>(filter); // need to wrap to enable updates to responses
79-
8078
var learner = new ExtensibleLStarMMLTBuilder<I, O>().withAlphabet(alphabet)
8179
.withModelParams(example.getParams())
8280
.withTimeOracle(mqOracle)
8381
.withInitialSuffixes(suffixes)
8482
.withSymbolFilter(cachedFilter)
8583
.create();
86-
variants.addLearnerVariant("system=" + example + ",filter=" + filterMode, learner, counters + mmlt.size());
84+
variants.addLearnerVariant("system=" + example + ",filter=" + filter, learner, counters + mmlt.size());
8785
}
8886
}
8987

@@ -126,13 +124,6 @@ private static List<String> listModelFiles() {
126124
return models;
127125
}
128126

129-
private enum FilterMode {
130-
none,
131-
random,
132-
ignore_all,
133-
perfect
134-
}
135-
136127
public static class Example implements MMLTLearningExample<String, String> {
137128

138129
private final String name;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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.oracle;
17+
18+
/**
19+
* {@link ParallelOracle} equivalent for {@link OmegaMembershipOracle}s.
20+
*
21+
* @param <S>
22+
* oracle state type
23+
* @param <I>
24+
* input symbol type
25+
* @param <D>
26+
* output domain type
27+
*/
28+
public interface ParallelTimedQueryOracle<I, O> extends ThreadPool, TimedQueryOracle<I, O> {}

api/src/main/java/de/learnlib/oracle/SingleQueryOracle.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.util.Collection;
1919

2020
import de.learnlib.query.Query;
21+
import net.automatalib.symbol.time.TimedInput;
22+
import net.automatalib.symbol.time.TimedOutput;
2123
import net.automatalib.word.Word;
2224

2325
/**
@@ -58,4 +60,7 @@ interface SingleQueryOracleMealy<I, O> extends SingleQueryOracle<I, Word<O>>, Me
5860
@FunctionalInterface
5961
interface SingleQueryOracleMoore<I, O> extends SingleQueryOracle<I, Word<O>>, MooreMembershipOracle<I, O> {}
6062

63+
interface SingleQueryOracleMMLT<I, O>
64+
extends SingleQueryOracle<TimedInput<I>, Word<TimedOutput<O>>>, TimedQueryOracle<I, O> {}
65+
6166
}

drivers/simulator/pom.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,31 @@ limitations under the License.
4343
<artifactId>automata-api</artifactId>
4444
</dependency>
4545

46+
<!-- build -->
4647
<dependency>
4748
<groupId>org.checkerframework</groupId>
4849
<artifactId>checker-qual</artifactId>
4950
</dependency>
51+
52+
<!-- test -->
53+
<dependency>
54+
<groupId>de.learnlib.testsupport</groupId>
55+
<artifactId>learnlib-learning-examples</artifactId>
56+
</dependency>
57+
58+
<dependency>
59+
<groupId>net.automatalib</groupId>
60+
<artifactId>automata-core</artifactId>
61+
</dependency>
62+
63+
<dependency>
64+
<groupId>org.mockito</groupId>
65+
<artifactId>mockito-core</artifactId>
66+
</dependency>
67+
<dependency>
68+
<groupId>org.testng</groupId>
69+
<artifactId>testng</artifactId>
70+
</dependency>
71+
5072
</dependencies>
5173
</project>
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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.driver.simulator;
17+
18+
import de.learnlib.testsupport.example.mealy.ExampleCoffeeMachine;
19+
import de.learnlib.testsupport.example.mealy.ExampleCoffeeMachine.Input;
20+
import de.learnlib.testsupport.example.mmlt.MMLTExamples;
21+
import net.automatalib.symbol.time.TimedInput;
22+
import net.automatalib.symbol.time.TimedOutput;
23+
import net.automatalib.word.Word;
24+
import org.mockito.Mockito;
25+
import org.testng.Assert;
26+
import org.testng.annotations.Test;
27+
28+
public class ForkTest {
29+
30+
@Test
31+
public void testMealy() {
32+
var sul = new MealySimulatorSUL<>(ExampleCoffeeMachine.constructMachine());
33+
34+
Assert.assertTrue(sul.canFork());
35+
36+
// check delegation
37+
var spy = Mockito.spy(sul);
38+
var fork = spy.fork();
39+
40+
Assert.assertNotNull(fork);
41+
42+
fork.pre();
43+
fork.step(Input.CLEAN);
44+
fork.post();
45+
fork.canFork();
46+
fork.fork();
47+
48+
Mockito.verify(spy, Mockito.only()).fork();
49+
50+
// check independency
51+
spy.pre();
52+
spy.step(Input.WATER);
53+
spy.step(Input.POD);
54+
55+
fork.pre();
56+
fork.post();
57+
58+
var out = spy.step(Input.BUTTON);
59+
Assert.assertEquals(out, ExampleCoffeeMachine.OUT_COFFEE);
60+
61+
spy.post();
62+
}
63+
64+
@Test
65+
public void testMMLT() {
66+
var mmlt = MMLTExamples.sensorCollector().getReferenceAutomaton();
67+
var alphabet = mmlt.getInputAlphabet();
68+
var sul = new MMLTSimulatorSUL<>(mmlt);
69+
var input = TimedInput.input(alphabet.getSymbol(0));
70+
71+
Assert.assertTrue(sul.canFork());
72+
73+
// check delegation
74+
var spy = Mockito.spy(sul);
75+
var fork = spy.fork();
76+
77+
Assert.assertNotNull(fork);
78+
79+
fork.pre();
80+
fork.step(input);
81+
fork.follow(Word.fromLetter(input));
82+
fork.timeoutStep(2);
83+
fork.post();
84+
fork.canFork();
85+
fork.fork();
86+
87+
Mockito.verify(spy, Mockito.only()).fork();
88+
89+
// check independency
90+
spy.pre();
91+
spy.step(input);
92+
93+
fork.pre();
94+
fork.post();
95+
96+
var out = spy.timeoutStep(3);
97+
Assert.assertEquals(out, new TimedOutput<>("part", 3));
98+
99+
spy.post();
100+
}
101+
102+
@Test
103+
public void testObservable() {
104+
var sul = new ObservableMealySimulatorSUL<>(ExampleCoffeeMachine.constructMachine());
105+
106+
Assert.assertTrue(sul.canFork());
107+
108+
// check delegation
109+
var spy = Mockito.spy(sul);
110+
var fork = spy.fork();
111+
112+
Assert.assertNotNull(fork);
113+
114+
fork.pre();
115+
fork.step(Input.CLEAN);
116+
fork.deepCopies();
117+
fork.getState();
118+
fork.post();
119+
fork.canFork();
120+
fork.fork();
121+
122+
Mockito.verify(spy, Mockito.only()).fork();
123+
124+
// check independency
125+
spy.pre();
126+
spy.step(Input.WATER);
127+
spy.step(Input.POD);
128+
129+
fork.pre();
130+
fork.post();
131+
132+
var out = spy.step(Input.BUTTON);
133+
Assert.assertEquals(out, ExampleCoffeeMachine.OUT_COFFEE);
134+
135+
spy.post();
136+
}
137+
138+
@Test
139+
public void testSLI() {
140+
var sul = new StateLocalInputMealySimulatorSUL<>(ExampleCoffeeMachine.constructMachine());
141+
142+
Assert.assertTrue(sul.canFork());
143+
144+
// check delegation
145+
var spy = Mockito.spy(sul);
146+
var fork = spy.fork();
147+
148+
Assert.assertNotNull(fork);
149+
150+
fork.pre();
151+
fork.step(Input.CLEAN);
152+
fork.currentlyEnabledInputs();
153+
fork.post();
154+
fork.canFork();
155+
fork.fork();
156+
157+
Mockito.verify(spy, Mockito.only()).fork();
158+
159+
// check independency
160+
spy.pre();
161+
spy.step(Input.WATER);
162+
spy.step(Input.POD);
163+
164+
fork.pre();
165+
fork.post();
166+
167+
var out = spy.step(Input.BUTTON);
168+
Assert.assertEquals(out, ExampleCoffeeMachine.OUT_COFFEE);
169+
170+
spy.post();
171+
}
172+
}
173+
174+

filters/cache/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ limitations under the License.
109109
<scope>test</scope>
110110
</dependency>
111111

112+
<dependency>
113+
<groupId>org.mockito</groupId>
114+
<artifactId>mockito-core</artifactId>
115+
</dependency>
112116
<dependency>
113117
<groupId>org.testng</groupId>
114118
<artifactId>testng</artifactId>

filters/cache/src/main/java/de/learnlib/filter/cache/mmlt/TimeoutReducerSUL.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* Assume we waited maxDelay for a timeout and observed no expiration. Then any consecutive timeout-input must also show
2727
* no timer (assuming sufficient maxDelay). Hence, we do not need to query the SUL for these.
2828
* <p>
29-
* We may observe a timeout again after any non-delaying input, as this may trigger a location-change.
29+
* We may observe a timeout again after any non-delaying input, as this may trigger a change of location.
3030
*
3131
* @param <I>
3232
* input symbol type (of non-delaying inputs)

filters/cache/src/test/java/de/learnlib/filter/cache/CacheTestUtils.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import net.automatalib.alphabet.Alphabet;
3434
import net.automatalib.alphabet.impl.Alphabets;
3535
import net.automatalib.automaton.fsa.impl.CompactDFA;
36-
import net.automatalib.automaton.mmlt.MMLT;
3736
import net.automatalib.automaton.mmlt.impl.CompactMMLT;
3837
import net.automatalib.automaton.mmlt.impl.StringSymbolCombiner;
3938
import net.automatalib.automaton.transducer.MealyMachine;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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.filter.cache.mmlt;
17+
18+
import de.learnlib.driver.simulator.MMLTSimulatorSUL;
19+
import de.learnlib.filter.cache.CacheTestUtils;
20+
import net.automatalib.symbol.time.TimedInput;
21+
import org.mockito.ArgumentMatchers;
22+
import org.mockito.Mockito;
23+
import org.testng.Assert;
24+
import org.testng.annotations.Test;
25+
26+
public class TimeoutReducerSULTest {
27+
28+
@Test
29+
public void testCaching() {
30+
31+
var mmlt = CacheTestUtils.MMLT;
32+
var sul = new MMLTSimulatorSUL<>(mmlt);
33+
34+
var mock = Mockito.spy(sul);
35+
var toSUL = new TimeoutReducerSUL<>(mock, 1);
36+
37+
toSUL.pre();
38+
toSUL.step(TimedInput.input("p1"));
39+
var output = toSUL.timeStep();
40+
41+
Assert.assertNull(output);
42+
Mockito.verify(mock, Mockito.times(1)).timeoutStep(ArgumentMatchers.anyLong());
43+
44+
output = toSUL.timeStep();
45+
46+
Assert.assertNull(output);
47+
Mockito.verify(mock, Mockito.times(1)).timeoutStep(ArgumentMatchers.anyLong());
48+
49+
toSUL.step(TimedInput.input("p2"));
50+
output = toSUL.timeoutStep(4);
51+
52+
Assert.assertNotNull(output);
53+
Mockito.verify(mock, Mockito.times(2)).timeoutStep(ArgumentMatchers.anyLong());
54+
55+
toSUL.post();
56+
}
57+
}

0 commit comments

Comments
 (0)