1818import java .util .ArrayDeque ;
1919import java .util .Collection ;
2020import java .util .Deque ;
21- import java .util .HashSet ;
2221import java .util .Iterator ;
22+ import java .util .LinkedHashSet ;
2323import java .util .Objects ;
2424import java .util .Queue ;
2525import java .util .Set ;
2626import java .util .function .Consumer ;
2727
2828import net .automatalib .automaton .UniversalDeterministicAutomaton ;
29- import net .automatalib .common .util .Pair ;
3029import net .automatalib .common .util .array .ArrayStorage ;
30+ import org .checkerframework .checker .nullness .qual .MonotonicNonNull ;
3131import org .checkerframework .checker .nullness .qual .Nullable ;
3232
3333public class RedBlueMerge <S extends AbstractBlueFringePTAState <S , SP , TP >, SP , TP > {
@@ -39,7 +39,6 @@ public class RedBlueMerge<S extends AbstractBlueFringePTAState<S, SP, TP>, SP, T
3939 private final int alphabetSize ;
4040 private final S qr ;
4141 private final S qb ;
42- private boolean merged ;
4342
4443 public RedBlueMerge (AbstractBlueFringePTA <S , SP , TP > pta , S qr , S qb ) {
4544 this (pta , qr , qb , validateInputs (pta , qr , qb ));
@@ -79,7 +78,6 @@ public S getBlueState() {
7978 }
8079
8180 public boolean merge () {
82- this .merged = true ;
8381 if (!mergeRedProperties (qr , qb )) {
8482 return false ;
8583 }
@@ -161,9 +159,6 @@ public boolean merge() {
161159
162160 private S cloneTopSucc (S succ , int i , Deque <FoldRecord <S >> stack , @ Nullable ArrayStorage <TP > newTPs ) {
163161 S succClone = (newTPs != null ) ? succ .copy (newTPs ) : succ .copy ();
164- if (succClone == succ ) {
165- return succ ;
166- }
167162 FoldRecord <S > peek = stack .peek ();
168163 assert peek != null ;
169164 S top = peek .q ;
@@ -180,9 +175,6 @@ private S cloneTop(S topState, Deque<FoldRecord<S>> stack) {
180175 assert !topState .isRed ();
181176
182177 S topClone = topState .copy ();
183- if (topClone == topState ) {
184- return topState ;
185- }
186178 S currTgt = topClone ;
187179
188180 Iterator <FoldRecord <S >> it = stack .iterator ();
@@ -198,9 +190,6 @@ private S cloneTop(S topState, Deque<FoldRecord<S>> stack) {
198190 S currSrcClone = currSrc .copy ();
199191 assert currSrcClone .successors != null ;
200192 currSrcClone .successors .set (currRec .i , currTgt );
201- if (currSrcClone == currSrc ) {
202- return topClone ; // we're done
203- }
204193 currRec .q = currSrcClone ;
205194 currTgt = currSrcClone ;
206195
@@ -321,10 +310,12 @@ private boolean mergeRedStateProperty(S qr, S qb) {
321310 }
322311
323312 /**
324- * Merges two non-null transition property arrays. The behavior of this method is as follows: <ul> <li>if {@code
325- * tps1} subsumes {@code tps2}, then {@code tps1} is returned.</li> <li>otherwise, if {@code tps1} and {@code tps2}
326- * can be merged, a new {@link ArrayStorage} containing the result of the merge is returned. <li>otherwise
327- * (i.e., if no merge is possible), {@code null} is returned. </ul>
313+ * Merges two non-null transition property arrays. The behavior of this method is as follows:
314+ * <ul>
315+ * <li>if {@code tps1} subsumes {@code tps2}, then {@code tps1} is returned.</li>
316+ * <li>otherwise, if {@code tps1} and {@code tps2} can be merged, a new {@link ArrayStorage} containing the result of the merge is returned.</li>
317+ * <li>otherwise (i.e., if no merge is possible), {@code null} is returned.</li>
318+ * </ul>
328319 */
329320 @ SuppressWarnings ("PMD.ReturnEmptyCollectionRatherThanNull" ) // null is semantically different from an empty list
330321 private @ Nullable ArrayStorage <TP > mergeTransProperties (ArrayStorage <TP > tps1 , ArrayStorage <TP > tps2 ) {
@@ -432,52 +423,42 @@ private void incorporate(S state) {
432423 }
433424 }
434425
426+ /**
427+ * Returns an automaton-based view of the merge. If the merge was not yet {@link #merge() tried}, this view is equal
428+ * to the unmodified PTA.
429+ *
430+ * @return the automaton-based view of this merge
431+ */
435432 public UniversalDeterministicAutomaton <S , Integer , ?, SP , TP > toMergedAutomaton () {
436- if (!this .merged ) {
437- throw new IllegalStateException ("#merge has not been called yet" );
438- }
439-
440- return new UniversalDeterministicAutomaton <S , Integer , Pair <S , Integer >, SP , TP >() {
433+ return new UniversalDeterministicAutomaton <S , Integer , PTATransition <S >, SP , TP >() {
441434
442- private Set <S > states ;
435+ private @ MonotonicNonNull Set <S > states ;
443436
444437 @ Override
445- public @ Nullable S getSuccessor (Pair <S , Integer > transition ) {
446- final S source = transition .getFirst ();
447- final Integer input = transition .getSecond ();
448-
449- if (source .isRed () && succMod .get (source .id ) != null ) {
450- return succMod .get (source .id ).get (input );
451- }
452-
453- return pta .getSuccessor (source , input );
438+ public S getSuccessor (PTATransition <S > transition ) {
439+ return Objects .requireNonNull (RedBlueMerge .this .getSucc (transition .getSource (), transition .getIndex ()));
454440 }
455441
456442 @ Override
457443 public SP getStateProperty (S state ) {
458- if (state .isRed () && propMod .get (state .id ) != null ) {
459- return propMod .get (state .id );
460- }
461-
462- return state .getStateProperty ();
444+ return RedBlueMerge .this .getStateProperty (state );
463445 }
464446
465447 @ Override
466- public TP getTransitionProperty (Pair <S , Integer > transition ) {
467- final S source = transition .getFirst ();
468- final Integer input = transition .getSecond ();
448+ public TP getTransitionProperty (PTATransition <S > transition ) {
449+ ArrayStorage <TP > properties = RedBlueMerge .this .getTransProperties (transition .getSource ());
469450
470- if (source . isRed () && transPropMod . get ( source . id ) != null ) {
471- return transPropMod .get (source . id ). get ( input );
451+ if (properties != null ) {
452+ return properties .get (transition . getIndex () );
472453 }
473454
474- assert source .transProperties != null ;
475- return source .transProperties .get (input );
455+ return null ;
476456 }
477457
478458 @ Override
479- public Pair <S , Integer > getTransition (S state , Integer input ) {
480- return Pair .of (state , input );
459+ public @ Nullable PTATransition <S > getTransition (S state , Integer input ) {
460+ final S succ = RedBlueMerge .this .getSucc (state , input );
461+ return succ == null ? null : new PTATransition <>(state , input );
481462 }
482463
483464 @ Override
@@ -487,22 +468,21 @@ public Collection<S> getStates() {
487468 return states ;
488469 }
489470
490- states = new HashSet <>();
471+ states = new LinkedHashSet <>();
491472 final Queue <S > discoverQueue = new ArrayDeque <>();
492473
493474 S initialState = getInitialState ();
494475 assert initialState != null ;
495476 discoverQueue .add (initialState );
477+ states .add (initialState );
496478
497479 S iter ;
498480
499481 while ((iter = discoverQueue .poll ()) != null ) {
500- states .add (iter );
501-
502482 for (int i = 0 ; i < alphabetSize ; i ++) {
503483 final S succ = getSuccessor (iter , i );
504484
505- if (succ != null && ! states .contains (succ )) {
485+ if (succ != null && states .add (succ )) {
506486 discoverQueue .add (succ );
507487 }
508488 }
0 commit comments