2626import java .util .List ;
2727import java .util .Map ;
2828import java .util .Map .Entry ;
29- import java .util .Optional ;
3029import java .util .Queue ;
3130import java .util .Set ;
32- import java .util .stream .Collectors ;
3331
3432import de .learnlib .Resumable ;
3533import de .learnlib .algorithm .LearningAlgorithm ;
6563import net .automatalib .common .util .HashUtil ;
6664import net .automatalib .common .util .Pair ;
6765import net .automatalib .word .Word ;
66+ import org .checkerframework .checker .nullness .qual .NonNull ;
6867import org .slf4j .Logger ;
6968import 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