Skip to content

Commit 61a188b

Browse files
committed
cleanup some ADT code
1 parent 2fa3fd0 commit 61a188b

File tree

10 files changed

+160
-183
lines changed

10 files changed

+160
-183
lines changed

algorithms/active/adt/src/main/java/de/learnlib/algorithm/adt/adt/ADT.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public void replaceNode(ADTNode<S, I, O> oldNode, ADTNode<S, I, O> newNode) {
7373
this.root = newNode;
7474
} else if (ADTUtil.isResetNode(oldNode)) {
7575
final ADTNode<S, I, O> endOfPreviousADS = oldNode.getParent();
76+
assert endOfPreviousADS != null;
7677
final O outputToReset = ADTUtil.getOutputForSuccessor(endOfPreviousADS, oldNode);
7778

7879
newNode.setParent(endOfPreviousADS);
@@ -83,6 +84,8 @@ public void replaceNode(ADTNode<S, I, O> oldNode, ADTNode<S, I, O> newNode) {
8384
assert ADTUtil.isResetNode(oldNodeParent);
8485

8586
final ADTNode<S, I, O> endOfPreviousADS = oldNodeParent.getParent();
87+
assert endOfPreviousADS != null;
88+
8689
final O outputToReset = ADTUtil.getOutputForSuccessor(endOfPreviousADS, oldNodeParent);
8790
final ADTNode<S, I, O> newResetNode = new ADTResetNode<>(newNode);
8891

@@ -191,30 +194,35 @@ public LCAInfo<S, I, O> findLCA(ADTNode<S, I, O> s1, ADTNode<S, I, O> s2) {
191194
final Map<ADTNode<S, I, O>, ADTNode<S, I, O>> s1ParentsToS1 = new HashMap<>();
192195

193196
ADTNode<S, I, O> s1Iter = s1;
194-
ADTNode<S, I, O> s2Iter = s2;
197+
ADTNode<S, I, O> s1ParentIter = s1.getParent();
195198

196-
while (s1Iter.getParent() != null) {
197-
s1ParentsToS1.put(s1Iter.getParent(), s1Iter);
198-
s1Iter = s1Iter.getParent();
199+
while (s1ParentIter != null) {
200+
s1ParentsToS1.put(s1ParentIter, s1Iter);
201+
s1Iter = s1ParentIter;
202+
s1ParentIter = s1ParentIter.getParent();
199203
}
200204

201205
final Set<ADTNode<S, I, O>> s1Parents = s1ParentsToS1.keySet();
202206

203-
while (s2Iter.getParent() != null) {
207+
ADTNode<S, I, O> s2Iter = s2;
208+
ADTNode<S, I, O> s2ParentIter = s2.getParent();
209+
210+
while (s2ParentIter != null) {
204211

205-
if (s1Parents.contains(s2Iter.getParent())) {
206-
if (!ADTUtil.isSymbolNode(s2Iter.getParent())) {
212+
if (s1Parents.contains(s2ParentIter)) {
213+
if (!ADTUtil.isSymbolNode(s2ParentIter)) {
207214
throw new IllegalStateException("Only Symbol Nodes should be LCAs");
208215
}
209216

210-
final ADTNode<S, I, O> lca = s2Iter.getParent();
217+
final ADTNode<S, I, O> lca = s2ParentIter;
211218
final O s1Out = ADTUtil.getOutputForSuccessor(lca, s1ParentsToS1.get(lca));
212219
final O s2Out = ADTUtil.getOutputForSuccessor(lca, s2Iter);
213220

214221
return new LCAInfo<>(lca, s1Out, s2Out);
215222
}
216223

217-
s2Iter = s2Iter.getParent();
224+
s2Iter = s2ParentIter;
225+
s2ParentIter = s2ParentIter.getParent();
218226
}
219227

220228
throw new IllegalStateException("Nodes do not share a parent node");

algorithms/active/adt/src/main/java/de/learnlib/algorithm/adt/adt/ADTResetNode.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
import java.util.Collections;
1919
import java.util.Map;
2020

21-
import org.checkerframework.checker.nullness.qual.Nullable;
22-
2321
/**
2422
* Reset node implementation.
2523
*
@@ -40,8 +38,8 @@ public ADTResetNode(ADTNode<S, I, O> successor) {
4038
}
4139

4240
@Override
43-
public @Nullable I getSymbol() {
44-
return null;
41+
public I getSymbol() {
42+
throw new UnsupportedOperationException("Reset nodes do not have a symbol");
4543
}
4644

4745
@Override
@@ -65,8 +63,8 @@ public Map<O, ADTNode<S, I, O>> getChildren() {
6563
}
6664

6765
@Override
68-
public @Nullable S getState() {
69-
return null;
66+
public S getState() {
67+
throw new UnsupportedOperationException("Reset nodes cannot reference a hypothesis state");
7068
}
7169

7270
@Override

algorithms/active/adt/src/main/java/de/learnlib/algorithm/adt/config/LeafSplitters.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,11 @@ public static <S, I, O> ADTNode<S, I, O> splitParent(ADTNode<S, I, O> nodeToSpli
162162
adsIter = adsIter.getChild(newSuffixOutput);
163163
}
164164

165-
final ADTNode<S, I, O> continuedADS = new ADTSymbolNode<>(adsIter.getParent(), suffixIter.next());
165+
final ADTNode<S, I, O> parent = adsIter.getParent();
166+
final ADTNode<S, I, O> continuedADS = new ADTSymbolNode<>(parent, suffixIter.next());
166167

167-
adsIter.getParent().getChildren().put(newSuffixOutput, continuedADS);
168+
assert parent != null;
169+
parent.getChildren().put(newSuffixOutput, continuedADS);
168170

169171
return finalizeSplit(nodeToSplit, continuedADS, suffixIter, oldIter, newIter);
170172
}

algorithms/active/adt/src/main/java/de/learnlib/algorithm/adt/config/model/replacer/ExhaustiveReplacer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ public <S, I, O> Set<ReplacementResult<S, I, O>> computeReplacements(MealyMachin
5757
return Collections.singleton(new ReplacementResult<>(adt.getRoot(), potentialResult.get()));
5858
}
5959

60-
final Set<ADTNode<S, I, O>> candidates = ADTUtil.collectADSNodes(adt.getRoot());
61-
candidates.remove(adt.getRoot());
60+
final Set<ADTNode<S, I, O>> candidates = ADTUtil.collectADSNodes(adt.getRoot(), false);
6261

6362
final PriorityQueue<Set<S>> queue = new PriorityQueue<>(candidates.size(), Comparator.comparingInt(Set::size));
6463
for (ADTNode<S, I, O> node : candidates) {

algorithms/active/adt/src/main/java/de/learnlib/algorithm/adt/config/model/replacer/LevelOrderReplacer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import de.learnlib.algorithm.adt.util.ADTUtil;
3131
import net.automatalib.alphabet.Alphabet;
3232
import net.automatalib.automaton.transducer.MealyMachine;
33+
import org.checkerframework.checker.nullness.qual.NonNull;
3334

3435
public class LevelOrderReplacer implements SubtreeReplacer {
3536

@@ -55,7 +56,8 @@ public <S, I, O> Set<ReplacementResult<S, I, O>> computeReplacements(MealyMachin
5556
queue.add(adt.getRoot());
5657

5758
while (!queue.isEmpty()) {
58-
final ADTNode<S, I, O> node = queue.poll();
59+
@SuppressWarnings("nullness") // false positive https://github.com/typetools/checker-framework/issues/399
60+
final @NonNull ADTNode<S, I, O> node = queue.poll();
5961
final Set<S> targetStates = ADTUtil.collectHypothesisStates(node);
6062

6163
// try to extendLeaf the parent ADS

algorithms/active/adt/src/main/java/de/learnlib/algorithm/adt/config/model/replacer/SingleReplacer.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ public <S, I, O> Set<ReplacementResult<S, I, O>> computeReplacements(MealyMachin
5050
Alphabet<I> inputs,
5151
ADT<S, I, O> adt) {
5252

53-
final Set<ADTNode<S, I, O>> candidates = ADTUtil.collectADSNodes(adt.getRoot());
54-
candidates.remove(adt.getRoot());
53+
final Set<ADTNode<S, I, O>> candidates = ADTUtil.collectADSNodes(adt.getRoot(), false);
5554

5655
// cache scores to prevent expensive recalculations during sorting
5756
final List<Pair<ADTNode<S, I, O>, Double>> sortedCandidates = new ArrayList<>(candidates.size());
@@ -111,12 +110,11 @@ public <S, I, O> Set<ReplacementResult<S, I, O>> computeReplacements(MealyMachin
111110
*
112111
* @return a ReplacementResult for the parent (reset) node, if a valid replacement is found. {@code null} otherwise.
113112
*/
114-
@Nullable
115-
static <S, I, O> ReplacementResult<S, I, O> computeParentExtension(MealyMachine<S, I, ?, O> hypothesis,
116-
Alphabet<I> inputs,
117-
ADTNode<S, I, O> node,
118-
Set<S> targetStates,
119-
ADSCalculator adsCalculator) {
113+
static <S, I, O> @Nullable ReplacementResult<S, I, O> computeParentExtension(MealyMachine<S, I, ?, O> hypothesis,
114+
Alphabet<I> inputs,
115+
ADTNode<S, I, O> node,
116+
Set<S> targetStates,
117+
ADSCalculator adsCalculator) {
120118
final ADTNode<S, I, O> parentReset = node.getParent();
121119
assert ADTUtil.isResetNode(parentReset) : "should not happen";
122120

algorithms/active/adt/src/main/java/de/learnlib/algorithm/adt/learner/ADTLearner.java

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@
2626
import java.util.List;
2727
import java.util.Map;
2828
import java.util.Map.Entry;
29-
import java.util.Optional;
3029
import java.util.Queue;
3130
import java.util.Set;
32-
import java.util.stream.Collectors;
3331

3432
import de.learnlib.Resumable;
3533
import de.learnlib.algorithm.LearningAlgorithm;
@@ -65,6 +63,7 @@
6563
import net.automatalib.common.util.HashUtil;
6664
import net.automatalib.common.util.Pair;
6765
import net.automatalib.word.Word;
66+
import org.checkerframework.checker.nullness.qual.NonNull;
6867
import org.slf4j.Logger;
6968
import org.slf4j.LoggerFactory;
7069

@@ -159,7 +158,9 @@ public boolean refineHypothesis(DefaultQuery<I, Word<O>> ce) {
159158
// normal refinement step
160159
while (!this.openCounterExamples.isEmpty()) {
161160

162-
final DefaultQuery<I, Word<O>> currentCE = this.openCounterExamples.poll();
161+
@SuppressWarnings("nullness")
162+
// false positive https://github.com/typetools/checker-framework/issues/399
163+
final @NonNull DefaultQuery<I, Word<O>> currentCE = this.openCounterExamples.poll();
163164
this.allCounterExamples.add(currentCE);
164165

165166
while (this.refineHypothesisInternal(currentCE)) {
@@ -219,35 +220,25 @@ public boolean refineHypothesisInternal(DefaultQuery<I, Word<O>> ceQuery) {
219220
oldTrans.setTarget(newState);
220221
oldTrans.setIsSpanningTreeEdge(true);
221222

222-
final Set<ADTNode<ADTState<I, O>, I, O>> finalNodes = ADTUtil.collectLeaves(this.adt.getRoot());
223-
final ADTNode<ADTState<I, O>, I, O> nodeToSplit = finalNodes.stream()
224-
.filter(n -> uaState.equals(n.getState()))
225-
.findFirst()
226-
.orElseThrow(IllegalStateException::new);
227-
223+
final ADTNode<ADTState<I, O>, I, O> nodeToSplit = findNodeForState(uaState);
228224
final ADTNode<ADTState<I, O>, I, O> newNode;
229225

230226
// directly insert into observation tree, because we use it for finding a splitter
231227
this.observationTree.addState(newState, newState.getAccessSequence(), oldTrans.getOutput());
232228
this.observationTree.addTrace(newState, nodeToSplit);
233229

234230
final Word<I> previousTrace = ADTUtil.buildTraceForNode(nodeToSplit).getFirst();
235-
final Optional<Word<I>> extension = this.observationTree.findSeparatingWord(uaState, newState, previousTrace);
236-
237-
if (extension.isPresent()) {
238-
final Word<I> completeSplitter = previousTrace.concat(extension.get());
239-
final Word<O> oldOutput = this.observationTree.trace(uaState, completeSplitter);
240-
final Word<O> newOutput = this.observationTree.trace(newState, completeSplitter);
231+
final Word<I> extension = this.observationTree.findSeparatingWord(uaState, newState, previousTrace);
241232

242-
newNode = this.adt.extendLeaf(nodeToSplit, completeSplitter, oldOutput, newOutput, this.leafSplitter);
243-
} else {
233+
if (extension == null) {
244234
// directly insert into observation tree, because we use it for finding a splitter
245235
this.observationTree.addTrace(uaState, v, this.mqo.answerQuery(uaAccessSequence, v));
246236
this.observationTree.addTrace(newState, v, this.mqo.answerQuery(uAccessSequenceWithA, v));
247237

248238
// in doubt, we will always find v
249239
final Word<I> otSepWord = this.observationTree.findSeparatingWord(uaState, newState);
250240
final Word<I> splitter;
241+
assert otSepWord != null;
251242

252243
if (otSepWord.length() < v.length()) {
253244
splitter = otSepWord;
@@ -259,6 +250,12 @@ public boolean refineHypothesisInternal(DefaultQuery<I, Word<O>> ceQuery) {
259250
final Word<O> newOutput = this.observationTree.trace(newState, splitter);
260251

261252
newNode = this.adt.splitLeaf(nodeToSplit, splitter, oldOutput, newOutput, this.leafSplitter);
253+
} else {
254+
final Word<I> completeSplitter = previousTrace.concat(extension);
255+
final Word<O> oldOutput = this.observationTree.trace(uaState, completeSplitter);
256+
final Word<O> newOutput = this.observationTree.trace(newState, completeSplitter);
257+
258+
newNode = this.adt.extendLeaf(nodeToSplit, completeSplitter, oldOutput, newOutput, this.leafSplitter);
262259
}
263260
newNode.setState(newState);
264261

@@ -269,11 +266,7 @@ public boolean refineHypothesisInternal(DefaultQuery<I, Word<O>> ceQuery) {
269266
newTransitions.add(this.hypothesis.createOpenTransition(newState, i, this.adt.getRoot()));
270267
}
271268

272-
final List<ADTTransition<I, O>> transitionsToRefine = nodeToSplit.getState()
273-
.getIncomingTransitions()
274-
.stream()
275-
.filter(x -> !x.isSpanningTreeEdge())
276-
.collect(Collectors.toList());
269+
final List<ADTTransition<I, O>> transitionsToRefine = getIncomingNonSpanningTreeTransitions(uaState);
277270

278271
for (ADTTransition<I, O> x : transitionsToRefine) {
279272
x.setTarget(null);
@@ -299,6 +292,18 @@ public boolean refineHypothesisInternal(DefaultQuery<I, Word<O>> ceQuery) {
299292
return true;
300293
}
301294

295+
private ADTNode<ADTState<I, O>, I, O> findNodeForState(ADTState<I, O> state) {
296+
297+
for (ADTNode<ADTState<I, O>, I, O> leaf : ADTUtil.collectLeaves(this.adt.getRoot())) {
298+
if (leaf.getState().equals(state)) {
299+
return leaf;
300+
}
301+
}
302+
303+
throw new IllegalStateException("Cannot find leaf for state " + state);
304+
305+
}
306+
302307
@Override
303308
public MealyMachine<?, I, ?, O> getHypothesisModel() {
304309
return this.hypothesis;
@@ -503,7 +508,8 @@ private ADTNode<ADTState<I, O>, I, O> evaluateAdtExtension(ADTNode<ADTState<I, O
503508
final ADTNode<ADTState<I, O>, I, O> extension = potentialExtension.getReplacement();
504509
final ADTNode<ADTState<I, O>, I, O> nodeToReplace = ads.getParent(); // reset node
505510

506-
assert this.validateADS(nodeToReplace, extension, Collections.emptySet());
511+
assert extension != null && nodeToReplace != null &&
512+
this.validateADS(nodeToReplace, extension, Collections.emptySet());
507513

508514
final ADTNode<ADTState<I, O>, I, O> replacement = this.verifyADS(nodeToReplace,
509515
extension,
@@ -602,7 +608,7 @@ private boolean validateADS(ADTNode<ADTState<I, O>, I, O> oldADS,
602608
if (ADTUtil.isResetNode(oldADS)) {
603609
oldNodes = ADTUtil.collectResetNodes(this.adt.getRoot());
604610
} else {
605-
oldNodes = ADTUtil.collectADSNodes(this.adt.getRoot());
611+
oldNodes = ADTUtil.collectADSNodes(this.adt.getRoot(), true);
606612
}
607613

608614
if (!oldNodes.contains(oldADS)) {
@@ -755,7 +761,6 @@ private void resolveAmbiguities(ADTNode<ADTState<I, O>, I, O> nodeToReplace,
755761

756762
for (ADTNode<ADTState<I, O>, I, O> leaf : cachedLeaves) {
757763
final ADTState<I, O> hypState = leaf.getState();
758-
assert hypState != null;
759764

760765
if (hypState.equals(finalNode.getState())) {
761766
oldReference = leaf;
@@ -768,6 +773,7 @@ private void resolveAmbiguities(ADTNode<ADTState<I, O>, I, O> nodeToReplace,
768773
}
769774
}
770775

776+
assert oldReference != null && newReference != null;
771777
final LCAInfo<ADTState<I, O>, I, O> lcaResult = this.adt.findLCA(oldReference, newReference);
772778
final ADTNode<ADTState<I, O>, I, O> lca = lcaResult.adtNode;
773779
final Pair<Word<I>, Word<O>> lcaTrace = ADTUtil.buildTraceForNode(lca);
@@ -807,20 +813,27 @@ private void resiftAffectedTransitions(Set<ADTNode<ADTState<I, O>, I, O>> states
807813

808814
for (ADTNode<ADTState<I, O>, I, O> state : states) {
809815

810-
final List<ADTTransition<I, O>> transitionsToRefine = state.getState()
811-
.getIncomingTransitions()
812-
.stream()
813-
.filter(x -> !x.isSpanningTreeEdge())
814-
.collect(Collectors.toList());
815-
816-
for (ADTTransition<I, O> trans : transitionsToRefine) {
816+
for (ADTTransition<I, O> trans : getIncomingNonSpanningTreeTransitions(state.getState())) {
817817
trans.setTarget(null);
818818
trans.setSiftNode(finalizedADS);
819819
this.openTransitions.add(trans);
820820
}
821821
}
822822
}
823823

824+
private List<ADTTransition<I, O>> getIncomingNonSpanningTreeTransitions(ADTState<I, O> state) {
825+
final Set<ADTTransition<I, O>> transitions = state.getIncomingTransitions();
826+
final List<ADTTransition<I, O>> result = new ArrayList<>(transitions.size());
827+
828+
for (ADTTransition<I, O> t : transitions) {
829+
if (!t.isSpanningTreeEdge()) {
830+
result.add(t);
831+
}
832+
}
833+
834+
return result;
835+
}
836+
824837
public ADT<ADTState<I, O>, I, O> getADT() {
825838
return adt;
826839
}

0 commit comments

Comments
 (0)