Skip to content

Commit 96f0eb0

Browse files
committed
Added new learning examples, some TTT optimizations
1 parent 4f82adc commit 96f0eb0

11 files changed

Lines changed: 145 additions & 52 deletions

File tree

algorithms/ttt/src/main/java/de/learnlib/algorithms/ttt/base/BaseTTTLearner.java

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Map;
2828
import java.util.Objects;
2929
import java.util.Queue;
30+
import java.util.Set;
3031

3132
import javax.annotation.Nonnull;
3233

@@ -39,6 +40,7 @@
3940
import net.automatalib.words.Word;
4041

4142
import com.google.common.collect.AbstractIterator;
43+
import com.google.common.collect.Sets;
4244

4345
import de.learnlib.algorithms.ttt.base.TTTHypothesis.TTTEdge;
4446
import de.learnlib.api.AccessSequenceTransformer;
@@ -71,6 +73,8 @@ public static class BuilderDefaults {
7173
protected final DiscriminationTree<I,D> dtree;
7274
// private final SuffixTrie<I> suffixTrie = new SuffixTrie<>();
7375

76+
private final Set<Word<I>> finalDiscriminators = Sets.newHashSet(Word.epsilon());
77+
7478
private final Collection<WeakReference<TTTEventListener<I, D>>> eventListeners = new UnorderedCollection<>();
7579

7680
/**
@@ -145,10 +149,10 @@ public boolean refineHypothesis(DefaultQuery<I, D> ceQuery) {
145149

146150
DefaultQuery<I, D> currCe = ceQuery;
147151

148-
while(currCe != null) {
152+
//while(currCe != null) {
149153
while(refineHypothesisSingle(currCe));
150-
currCe = checkHypothesisConsistency();
151-
}
154+
// currCe = checkHypothesisConsistency();
155+
// }
152156

153157
return true;
154158
}
@@ -425,6 +429,10 @@ private GlobalSplitter<I,D> findSplitterGlobal() {
425429
Iterator<DTNode<I,D>> blocksIt = blockList.iterator();
426430
while(blocksIt.hasNext()) {
427431
DTNode<I,D> blockRoot = blocksIt.next();
432+
if (finalDiscriminators.contains(blockRoot.getDiscriminator().subWord(1))) {
433+
declareFinal(blockRoot);
434+
continue;
435+
}
428436
Splitter<I,D> splitter = findSplitter(blockRoot);
429437
if(splitter != null) {
430438
if(bestSplitter == null || splitter.discriminator.length()
@@ -521,38 +529,38 @@ private Splitter<I,D> findSplitter(DTNode<I,D> blockRoot) {
521529
return new Splitter<>(state1, state2, bestI, bestLCA);
522530
}
523531

524-
/**
525-
* Checks whether the hypothesis is consistent with the discrimination tree.
526-
* If an inconsistency is discovered, it is returned in the form of a counterexample.
527-
*
528-
* @return a counterexample uncovering an inconsistency, or {@code null}
529-
* if the hypothesis is consistent with the discrimination tree
530-
*/
531-
// TODO can be removed
532-
private DefaultQuery<I, D> checkHypothesisConsistency() {
533-
for(DTNode<I,D> leaf : dtree.getRoot().subtreeLeaves()) {
534-
TTTState<I,D> state = leaf.state;
535-
if(state == null) {
536-
continue;
537-
}
538-
539-
DTNode<I,D> curr = state.dtLeaf;
540-
DTNode<I,D> next = curr.getParent();
541-
542-
while(next != null) {
543-
Word<I> discr = next.getDiscriminator();
544-
D expected = curr.getParentEdgeLabel();
545-
546-
if(!Objects.equals(computeHypothesisOutput(state, discr), expected)) {
547-
return new DefaultQuery<>(state.getAccessSequence(), discr, expected);
548-
}
549-
curr = next;
550-
next = curr.getParent();
551-
}
552-
}
553-
554-
return null;
555-
}
532+
// /**
533+
// * Checks whether the hypothesis is consistent with the discrimination tree.
534+
// * If an inconsistency is discovered, it is returned in the form of a counterexample.
535+
// *
536+
// * @return a counterexample uncovering an inconsistency, or {@code null}
537+
// * if the hypothesis is consistent with the discrimination tree
538+
// */
539+
// // TODO can be removed
540+
// private DefaultQuery<I, D> checkHypothesisConsistency() {
541+
// for(DTNode<I,D> leaf : dtree.getRoot().subtreeLeaves()) {
542+
// TTTState<I,D> state = leaf.state;
543+
// if(state == null) {
544+
// continue;
545+
// }
546+
//
547+
// DTNode<I,D> curr = state.dtLeaf;
548+
// DTNode<I,D> next = curr.getParent();
549+
//
550+
// while(next != null) {
551+
// Word<I> discr = next.getDiscriminator();
552+
// D expected = curr.getParentEdgeLabel();
553+
//
554+
// if(!Objects.equals(computeHypothesisOutput(state, discr), expected)) {
555+
// return new DefaultQuery<>(state.getAccessSequence(), discr, expected);
556+
// }
557+
// curr = next;
558+
// next = curr.getParent();
559+
// }
560+
// }
561+
//
562+
// return null;
563+
// }
556564

557565
/**
558566
* Creates a state in the hypothesis. This method cannot be used for the initial
@@ -581,8 +589,7 @@ protected TTTState<I,D> getTarget(TTTTransition<I,D> trans) {
581589
if(trans.isTree()) {
582590
return trans.getTreeTarget();
583591
}
584-
DTNode<I,D> dtTarget = updateDTTarget(trans);
585-
return dtTarget.state;
592+
return updateTarget(trans);
586593
}
587594

588595
/**
@@ -628,15 +635,15 @@ private void finalizeDiscriminator(DTNode<I,D> blockRoot, Splitter<I,D> splitter
628635
notifyPreFinalizeDiscriminator(blockRoot, splitter);
629636

630637
Word<I> finalDiscriminator = prepareSplit(blockRoot, splitter);
631-
632638
Map<D,DTNode<I,D>> repChildren = createMap();
633-
639+
634640
for (D label : blockRoot.splitData.getLabels()) {
635641
repChildren.put(label, extractSubtree(blockRoot, label));
636642
}
637643
blockRoot.replaceChildren(repChildren);
638-
644+
639645
blockRoot.setDiscriminator(finalDiscriminator);
646+
640647
declareFinal(blockRoot);
641648

642649
notifyPostFinalizeDiscriminator(blockRoot, splitter);
@@ -647,6 +654,7 @@ protected void declareFinal(DTNode<I,D> blockRoot) {
647654
blockRoot.splitData = null;
648655

649656
blockRoot.removeFromBlockList();
657+
finalDiscriminators.add(blockRoot.getDiscriminator());
650658

651659
for (DTNode<I,D> subtree : blockRoot.getChildren()) {
652660
assert subtree.splitData == null;
@@ -668,13 +676,14 @@ protected void declareFinal(DTNode<I,D> blockRoot) {
668676
* @return the discriminator to use for splitting
669677
*/
670678
private Word<I> prepareSplit(DTNode<I,D> node, Splitter<I,D> splitter) {
679+
int symbolIdx = splitter.symbolIdx;
680+
I symbol = alphabet.getSymbol(symbolIdx);
681+
Word<I> discriminator = splitter.discriminator.prepend(symbol);
682+
671683
Deque<DTNode<I,D>> dfsStack = new ArrayDeque<>();
672684

673685
DTNode<I,D> succSeparator = splitter.succSeparator;
674-
int symbolIdx = splitter.symbolIdx;
675-
I symbol = alphabet.getSymbol(symbolIdx);
676686

677-
Word<I> discriminator = splitter.discriminator.prepend(symbol);
678687

679688
dfsStack.push(node);
680689
assert node.splitData == null;
@@ -1027,13 +1036,7 @@ private void closeTransition(TTTTransition<I,D> trans) {
10271036
return;
10281037
}
10291038

1030-
DTNode<I,D> dtTarget = updateDTTarget(trans);
1031-
1032-
if(dtTarget.state == null) {
1033-
TTTState<I,D> state = createState(trans);
1034-
link(dtTarget, state);
1035-
initializeState(state);
1036-
}
1039+
updateTarget(trans);
10371040
}
10381041

10391042
/**
@@ -1047,6 +1050,19 @@ private DTNode<I,D> updateDTTarget(TTTTransition<I,D> transition) {
10471050
return updateDTTarget(transition, true);
10481051
}
10491052

1053+
private TTTState<I, D> updateTarget(TTTTransition<I, D> trans) {
1054+
DTNode<I,D> node = updateDTTarget(trans);
1055+
1056+
TTTState<I,D> state = node.state;
1057+
if (state == null) {
1058+
state = createState(trans);
1059+
link(node, state);
1060+
initializeState(state);
1061+
}
1062+
1063+
return state;
1064+
}
1065+
10501066
/**
10511067
* Updates the transition to point to either a leaf in the discrimination tree,
10521068
* or---if the {@code hard} parameter is set to {@code false}---to a block

core/src/main/java/de/learnlib/mealy/MealyLearnerWrapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import de.learnlib.oracles.DefaultQuery;
2626

2727
@ParametersAreNonnullByDefault
28-
final class MealyLearnerWrapper<M extends MealyMachine<?, I, ?, O>, I, O> implements LearningAlgorithm<M, I, Word<O>> {
28+
final class MealyLearnerWrapper<M extends MealyMachine<?, I, ?, O>, I, O> implements LearningAlgorithm.MealyLearner<I, O> {
2929

3030
private final LearningAlgorithm<M, I, O> learner;
3131

core/src/main/java/de/learnlib/mealy/MealyUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public static <I,O> DefaultQuery<I,O> reduceCounterExample(
120120

121121
@Nonnull
122122
public static <M extends MealyMachine<?,I,?,O>,I,O>
123-
LearningAlgorithm<M,I,Word<O>> wrapSymbolLearner(LearningAlgorithm<M,I,O> learner) {
123+
LearningAlgorithm.MealyLearner<I,O> wrapSymbolLearner(LearningAlgorithm<M,I,O> learner) {
124124
return new MealyLearnerWrapper<>(learner);
125125
}
126126

test-support/learning-examples/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ http://www.gnu.de/documents/lgpl.en.html.
4949
<groupId>net.automatalib</groupId>
5050
<artifactId>automata-util</artifactId>
5151
</dependency>
52+
<dependency>
53+
<groupId>net.automatalib</groupId>
54+
<artifactId>automata-serialization-learnlibv2</artifactId>
55+
</dependency>
5256
</dependencies>
5357

5458
</project>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package de.learnlib.examples.dfa;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
6+
import net.automatalib.automata.fsa.impl.compact.CompactDFA;
7+
import net.automatalib.serialization.learnlibv2.LearnLibV2Serialization;
8+
import de.learnlib.examples.DefaultLearningExample.DefaultDFALearningExample;
9+
import de.learnlib.examples.LearningExample.DFALearningExample;
10+
11+
public class DFABenchmarks {
12+
13+
public static DFALearningExample<Integer> loadLearnLibV2Benchmark(String name) {
14+
String resourceName = "/automata/learnlibv2/" + name + ".dfa";
15+
DFABenchmarks.class.getResource(resourceName);
16+
if (DFABenchmarks.class.getResource(resourceName) == null) {
17+
resourceName += ".gz"; // look for GZip compressed resource
18+
if (DFABenchmarks.class.getResource(resourceName) == null) {
19+
return null;
20+
}
21+
}
22+
23+
try (InputStream is = DFABenchmarks.class.getResourceAsStream(resourceName)) {
24+
CompactDFA<Integer> dfa = LearnLibV2Serialization.getInstance().readGenericDFA(is);
25+
return new DefaultDFALearningExample<>(dfa);
26+
}
27+
catch (IOException ex) {
28+
ex.printStackTrace();
29+
return null;
30+
}
31+
}
32+
33+
34+
public static DFALearningExample<Integer> loadPots2() {
35+
return loadLearnLibV2Benchmark("pots2");
36+
}
37+
38+
public static DFALearningExample<Integer> loadPots3() {
39+
return loadLearnLibV2Benchmark("pots3");
40+
}
41+
42+
public static DFALearningExample<Integer> loadPeterson2() {
43+
return loadLearnLibV2Benchmark("peterson2");
44+
}
45+
46+
public static DFALearningExample<Integer> loadPeterson3() {
47+
return loadLearnLibV2Benchmark("peterson3");
48+
}
49+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package de.learnlib.examples.dfa;
2+
3+
import java.util.Random;
4+
5+
import net.automatalib.util.automata.random.RandomAutomata;
6+
import net.automatalib.words.impl.Alphabets;
7+
import de.learnlib.examples.DefaultLearningExample.DefaultDFALearningExample;
8+
9+
public class ExampleRandomDFA extends DefaultDFALearningExample<Integer> {
10+
11+
public ExampleRandomDFA(Random rand, int numInputs, int size) {
12+
super(RandomAutomata.randomDFA(rand, size, Alphabets.integers(0, numInputs - 1)));
13+
}
14+
15+
public ExampleRandomDFA(int numInputs, int size) {
16+
this(new Random(), numInputs, size);
17+
}
18+
19+
}

test-support/learning-examples/src/main/java/de/learnlib/examples/mealy/ExampleRandomMealy.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,10 @@ ExampleRandomMealy<I,O> createExample(Random random, Alphabet<I> alphabet, int s
3838
public ExampleRandomMealy(Random random, Alphabet<I> alphabet, int size, O... outputs) {
3939
super(RandomAutomata.randomDeterministic(random, size, alphabet, null, Arrays.asList(outputs), new CompactMealy<I,O>(alphabet)));
4040
}
41+
42+
@SafeVarargs
43+
public ExampleRandomMealy(Alphabet<I> alphabet, int size, O... outputs) {
44+
this(new Random(), alphabet, size, outputs);
45+
}
4146

4247
}
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)