44import com .google .common .collect .*;
55
66import java .util .*;
7+ import java .util .stream .Collectors ;
8+ import java .util .stream .Stream ;
79
810/**
911 * Immutable NFA
1012 * <p>
1113 * Created by maarten on 15-6-16.
1214 */
13- public class NFA {
14- public final Map <State , Multimap <Event , Transition >> transitions ;
15- public final Set <State > states ;
16- public final Multimap <Event , State > statesThatAllowEvent ;
15+ @ SuppressWarnings ("WeakerAccess" )
16+ public class NFA <S extends State , E extends Event > {
17+ public final Map <S , Multimap <E , Transition <S , E >>> transitions ;
18+ public final Set <S > states ;
19+ public final Multimap <E , S > statesThatAllowEvent ;
1720
18- private NFA (Builder builder ) {
21+ private NFA (Builder < S , E > builder ) {
1922 this .states = ImmutableSet .copyOf (builder .states );
2023
21- ImmutableMap .Builder <State , Multimap <Event , Transition >> immTransitions = new ImmutableMap .Builder <>();
24+ ImmutableMap .Builder <S , Multimap <E , Transition < S , E > >> immTransitions = new ImmutableMap .Builder <>();
2225
2326 // O(transitions.numberOfBranches())
2427 builder .transitions .forEach ((state , eventToTransitionMap ) -> {
25- final ImmutableMultimap .Builder <Event , Transition > eventToTransitionMapBuilder = new ImmutableMultimap .Builder <>();
28+ final ImmutableMultimap .Builder <E , Transition < S , E > > eventToTransitionMapBuilder = new ImmutableMultimap .Builder <>();
2629 eventToTransitionMap .forEach (eventToTransitionMapBuilder ::putAll );
2730 immTransitions .put (state , eventToTransitionMapBuilder .build ());
2831 });
2932 this .transitions = immTransitions .build ();
3033
3134 // O(transitions.numberOfBranches())
32- ImmutableMultimap .Builder <Event , State > immStatesThatAllowEvent = new ImmutableMultimap .Builder <>();
35+ ImmutableMultimap .Builder <E , S > immStatesThatAllowEvent = new ImmutableMultimap .Builder <>();
3336 builder .transitions .forEach ((state , eventMap ) ->
3437 eventMap .forEach ((event , transitions ) ->
3538 immStatesThatAllowEvent .put (event , state )
@@ -52,48 +55,54 @@ private NFA(Builder builder) {
5255 );
5356 }
5457
55- public PossibleStateTransitionPaths getPathsForInput (State start , LinkedList <Event > events ) {
56- final List <Event > events1 = ImmutableList .copyOf (events ); // O(n)
58+ @ SuppressWarnings ("unused" )
59+ public PossibleStateTransitionPaths <S , E > getTransitions (S start , LinkedList <E > events ) {
60+ final List <E > events1 = ImmutableList .copyOf (events ); // O(n)
5761 return precomputePaths (events )
5862 .get (start )
5963 .get (events1 );
6064 }
6165
66+ public Stream <State > apply (S start , LinkedList <E > events ) {
67+ final PossibleStateTransitionPaths <S , E > transitions = getTransitions (start , events );
68+ return transitions .applyRecursive ();
69+ }
70+
6271 /**
6372 * O(path.numberOfBranches() * states.numberOfBranches() * transitions.numberOfBranches())
6473 *
6574 * @param event Input events to use for computing all possible paths along the NFA
6675 * @return A map from starting states to a map of input events to an enumeration of possible branches
6776 */
68- public Map <State , Map <List <Event >, PossibleStateTransitionPaths >> precomputePaths (LinkedList <Event > event ) {
69- PersistentList <Event > postFixPath = com .github .krukow .clj_lang .PersistentList .create (); // O(1)
70- Map <State , Map <List <Event >, PossibleStateTransitionPaths >> precomputedPaths = new HashMap <>(states .size ());// O(1)
77+ public Map <S , Map <List <E >, PossibleStateTransitionPaths < S , E >>> precomputePaths (LinkedList <E > event ) {
78+ PersistentList <E > postFixPath = com .github .krukow .clj_lang .PersistentList .create (( Iterable <? extends E >) new ArrayList < E >( 0 ) ); // O(1)
79+ Map <S , Map <List <E >, PossibleStateTransitionPaths < S , E > >> precomputedPaths = new HashMap <>(states .size ());// O(1)
7180
7281 while (event .size () > 0 ) { // O(path.numberOfBranches()) *
73- Event lastEvent = event .removeLast (); // O(1)
82+ E lastEvent = event .removeLast (); // O(1)
7483
7584 postFixPath = postFixPath .plus (lastEvent ); // O(1)
7685
7786 // TODO filter only those states that *can* be reached through the previous action
78- for (State state : statesThatAllowEvent .get (lastEvent )) { // O(states.numberOfBranches()) *
79- Map <List <Event >, PossibleStateTransitionPaths > pathsForEvents = precomputedPaths .getOrDefault (state , new HashMap <>());//O(1)
80- final Collection <Transition > possibleTransitions = getTransitions (state , lastEvent ); // O(1)
87+ for (S state : statesThatAllowEvent .get (lastEvent )) { // O(states.numberOfBranches()) *
88+ Map <List <E >, PossibleStateTransitionPaths < S , E > > pathsForEvents = precomputedPaths .getOrDefault (state , new HashMap <>());//O(1)
89+ final Collection <Transition < S , E > > possibleTransitions = getTransitions (state , lastEvent ); // O(1)
8190
82- PossibleStateTransitionPaths possibleBranches ;
91+ PossibleStateTransitionPaths < S , E > possibleBranches ;
8392 if (postFixPath .size () == 1 ) {
84- possibleBranches = new PossibleStateTransitionPaths (state , possibleTransitions , postFixPath , null ); // O(1)
93+ possibleBranches = new PossibleStateTransitionPaths <> (state , possibleTransitions , postFixPath , null ); // O(1)
8594 } else {
86- final PersistentList <Event > furtherEvents = postFixPath .minus ();
87- ImmutableMap .Builder <State , PossibleStateTransitionPaths > restPaths = ImmutableMap .builder (); // O(1)
95+ final PersistentList <E > furtherEvents = postFixPath .minus ();
96+ ImmutableMap .Builder <S , PossibleStateTransitionPaths < S , E > > restPaths = ImmutableMap .builder (); // O(1)
8897 possibleTransitions .stream () // O(possibleTransitions.numberOfBranches())
8998 .map (Transition ::getTo )
9099 .distinct ()
91100 .forEach (possibleTargetState -> {
92- PossibleStateTransitionPaths restBranches = precomputedPaths .get (possibleTargetState ).get (furtherEvents );
101+ PossibleStateTransitionPaths < S , E > restBranches = precomputedPaths .get (possibleTargetState ).get (furtherEvents );
93102 assert restBranches != null : "Possible branches must have been calculated for state " + possibleTargetState ;
94103 restPaths .put (possibleTargetState , restBranches );
95104 });
96- possibleBranches = new PossibleStateTransitionPaths (
105+ possibleBranches = new PossibleStateTransitionPaths <> (
97106 state ,
98107 possibleTransitions ,
99108 postFixPath ,
@@ -108,32 +117,41 @@ public Map<State, Map<List<Event>, PossibleStateTransitionPaths>> precomputePath
108117 return precomputedPaths ;
109118 }
110119
111- public Collection <Transition > getTransitions (State from , Event event ) {
112- final Multimap <Event , Transition > eventTransitionMultimap = transitions .get (from );
113-
120+ public Collection <Transition <S , E >> getTransitions (S from , E event ) {
121+ final Multimap <E , Transition <S , E >> eventTransitionMultimap = transitions .get (from );
114122 if (eventTransitionMultimap != null ) return eventTransitionMultimap .get (event );
115123 else return Collections .emptySet ();
116124 }
117125
118- public Set <State > getStates () {
126+ public Set <S > getStates () {
119127 return states ;
120128 }
121129
122- public static class Builder {
123- private final Set <State > states ;
124- private final Map <State , Map <Event , Set <Transition >>> transitions ;
130+ public StateContainer start (S state ) {
131+ return new StateContainer (Collections .singletonList (state ));
132+ }
133+
134+ @ SuppressWarnings ("unused" )
135+ public Collection <S > getStatesThatAllowEvent (E e ) {
136+ return statesThatAllowEvent .get (e );
137+ }
138+
139+ public static class Builder <S extends State , E extends Event > {
140+ private final Set <S > states ;
141+ private final Map <S , Map <E , Set <Transition <S , E >>>> transitions ;
125142
126143 public Builder () {
127144 this .states = new HashSet <>(50 );
128145 transitions = new HashMap <>(50 );
129146 }
130147
131- public Builder addStates (Collection <State > states ) {
148+ @ SuppressWarnings ("unused" )
149+ public Builder <S , E > addStates (Collection <S > states ) {
132150 this .states .addAll (states );
133151 return this ;
134152 }
135153
136- public Builder addState (State states ) {
154+ public Builder < S , E > addState (S states ) {
137155 this .states .add (states );
138156 return this ;
139157 }
@@ -146,11 +164,11 @@ public Builder addState(State states) {
146164 * @param to To state
147165 * @return This builder
148166 */
149- public Builder addTransition (State from , Event event , State to ) {
167+ public Builder < S , E > addTransition (S from , E event , S to ) {
150168 states .add (from );
151169 states .add (to );
152170
153- addTransition (new Transition (event , from , to ), from , event );
171+ addTransition (new Transition <> (event , from , to ), from , event );
154172
155173 return this ;
156174 }
@@ -161,7 +179,7 @@ public Builder addTransition(State from, Event event, State to) {
161179 * @param transitionsToAdd List of transitions. Implicit states will be added if necessary.
162180 * @return This builder
163181 */
164- public Builder addTransitions (Collection <Transition > transitionsToAdd ) {
182+ public Builder < S , E > addTransitions (Collection <Transition > transitionsToAdd ) {
165183 transitionsToAdd .forEach (this ::addTransition );
166184 return this ;
167185 }
@@ -172,31 +190,48 @@ public Builder addTransitions(Collection<Transition> transitionsToAdd) {
172190 * @param transition Implicit states will be added if necessary.
173191 * @return This builder
174192 */
175- public Builder addTransition (Transition transition ) {
176- State from = transition .from ;
177- State to = transition .to ;
178- Event event = transition .event ;
193+ public Builder < S , E > addTransition (Transition < S , E > transition ) {
194+ S from = transition .from ;
195+ S to = transition .to ;
196+ E event = transition .event ;
179197 states .add (from );
180198 states .add (to );
181199 addTransition (transition , from , event );
182200 return this ;
183201 }
184202
185- private void addTransition (Transition transition , State from , Event event ) {
186- Map <Event , Set <Transition >> eventsForState = transitions .getOrDefault (from , new HashMap <>());
187- Set <Transition > transitionsForEvent = eventsForState .getOrDefault (event , new HashSet <>());
203+ private void addTransition (Transition < S , E > transition , S from , E event ) {
204+ Map <E , Set <Transition < S , E > >> eventsForState = transitions .getOrDefault (from , new HashMap <>());
205+ Set <Transition < S , E > > transitionsForEvent = eventsForState .getOrDefault (event , new HashSet <>());
188206 transitionsForEvent .add (transition );
189207 eventsForState .putIfAbsent (event , transitionsForEvent );
190208 transitions .putIfAbsent (from , eventsForState );
191209 }
192210
193211
194- public NFA build () {
195- return new NFA (this );
212+ public NFA < S , E > build () {
213+ return new NFA <> (this );
196214 }
197215 }
198216
199- public Collection <State > getStatesThatAllowEvent (Event e ) {
200- return statesThatAllowEvent .get (e );
217+ public class StateContainer {
218+ public Collection <S > states ;
219+
220+ public StateContainer (Collection <S > ses ) {
221+ states = ses ;
222+ }
223+
224+ public StateContainer andThen (E e ) {
225+ states = states .stream ()
226+ .flatMap (from -> getTransitions (from , e ).stream ().map (transition -> {//noinspection unchecked
227+ e .accept (transition .getFrom (), transition .getTo ());
228+ return transition ;
229+ })).map (Transition ::getTo ).collect (Collectors .toList ());
230+ return this ;
231+ }
232+
233+ public Stream <S > getState () {
234+ return states .stream ();
235+ }
201236 }
202237}
0 commit comments