
    
`iژ                        d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	m
Z
mZmZmZmZmZ ddlmZ  G d de          Ze G d	 d
                      Z e            Zdeeeef                  fdZ ede          Z ede          Z G d deeef                   Z G d de          Z G d d          Zd Zd Z d Z!d Z"d Z#dS )zX
    Finite state machine library, extracted from `greenery.fsm` and adapted by MegaIng
    )deque)defaultdict)total_ordering)AnySetDictUnionNewTypeMappingTupleIterable	soft_reprc                       e Zd ZdS )_MarkerN)__name__
__module____qualname__     c/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/interegular/fsm.pyr   r      s        Dr   r   c                   0    e Zd ZdZd Zd Zd Zd Zd ZdS )_AnythingElseClsa  
        This is a surrogate symbol which you can use in your finite state machines
        to represent "any symbol not in the official alphabet". For example, if your
        state machine's alphabet is {"a", "b", "c", "d", fsm.anything_else}, then
        you can pass "e" in as a symbol and it will be converted to
        fsm.anything_else, then follow the appropriate transition.
    c                     dS Nanything_elser   selfs    r   __str__z_AnythingElseCls.__str__       r   c                     dS r   r   r   s    r   __repr__z_AnythingElseCls.__repr__   r    r   c                     dS )NFr   r   others     r   __lt__z_AnythingElseCls.__lt__    s    ur   c                 
    | |u S Nr   r$   s     r   __eq__z_AnythingElseCls.__eq__#   s    u}r   c                 :    t          t          |                     S r(   )hashidr   s    r   __hash__z_AnythingElseCls.__hash__&   s    BtHH~~r   N)	r   r   r   __doc__r   r"   r&   r)   r-   r   r   r   r   r      si                     r   r   charsc           	         g }g }t          |           D ]}|t          urA|r?t          |d                   dz   t          |          k    r|                    |           Lt	          |          dk    rA|                    t          |d                    dt          |d                               n(|                    t          t
          |                     |g}t	          |          dk    rA|                    t          |d                    dt          |d                               n(|                    t          t
          |                     d                    |          S )N      r   -,)	sortedr   ordappendlenr   extendmapjoin)r/   outcurrent_rangecs       r   nice_char_groupr@   /   sa   
CME]]  M!!m!M"<M8N8NQR8RVYZ[V\V\8\8\  ###}""JJ)M!$455VV	-PRBS8T8TVVWWWWJJs9m44555
=Q

ia 011RRImB>O4P4PRRSSSS

3y-0011188C==r   StateTransitionKeyc                       e Zd Zed             Zd Zd ZdefdZd Z	de
eeef         ef         fdZd	 Zd
 ZddZed             ZddZd ZdS )Alphabetc                     | j         S r(   )_by_transitionr   s    r   by_transitionzAlphabet.by_transitionG   s    ""r   c                 |   g }dt          | j                                                  D ]p\  }}|                    t	          |          t          |          f           t          |d         d                   k    rt          |d         d                   qd                    fd|D                       S )Nr   r1   
c              3   0   K   | ]\  }}| d | V  dS )z | Nr   ).0abwidths      r   	<genexpr>z#Alphabet.__str__.<locals>.<genexpr>R   s:      >>$!QAu---!-->>>>>>r   )r6   rF   itemsr8   r@   strr9   r<   )r   r=   tksymbolsrN   s       @r   r   zAlphabet.__str__K   s    !$"5";";"="=>> 	( 	(KBJJ00#b'':;;;3r71:&&CGAJyy>>>>#>>>>>>r   c                 @    t          |           j         d| j        dS )N())typer   _symbol_mappingr   s    r   r"   zAlphabet.__repr__T   s%    t**%AA(<AAAAr   returnc                 *    t          | j                  S r(   )r9   rX   r   s    r   __len__zAlphabet.__len__W   s    4'(((r   c                 *    t          | j                  S r(   )iterrX   r   s    r   __iter__zAlphabet.__iter__Z   s    D()))r   symbol_mappingc                     || _         t          t                    }| j                                         D ] \  }}||                             |           !t          |          | _        d S r(   )rX   r   listrP   r8   dictrF   )r   r_   rG   sts        r   __init__zAlphabet.__init__]   sk    -#D))(..00 	' 	'DAq!##A&&&&"=11r   c                 r    || j         vr"t          | j         v r| j         t                   S d S | j         |         S r(   )rX   r   r   items     r   __getitem__zAlphabet.__getitem__d   s?    t+++ 444+M::t'--r   c                     || j         v S r(   )rX   rg   s     r   __contains__zAlphabet.__contains__m   s    t+++r   	alphabets?Tuple[Alphabet, Tuple[Dict[TransitionKey, TransitionKey], ...]]c                  $     t                      j        d  D              } fd|D             }t          t                    }|                                D ] \  }}||                             |           !d t          |          D             t          fd|                                D                       }d  D             }                                D ] \  }}t          ||          D ]
\  }	}
|	|
|<   !|t          |          fS )Nc              3   H   K   | ]}|j                                         V  d S r(   )rX   keys)rK   rL   s     r   rO   z!Alphabet.union.<locals>.<genexpr>q   s1      )V)Vq!*;*@*@*B*B)V)V)V)V)V)Vr   c                 J    i | ]t          fd D                       S )c              3   (   K   | ]}|         V  d S r(   r   rK   rL   symbols     r   rO   z,Alphabet.union.<locals>.<dictcomp>.<genexpr>r   s'      'E'Ea&	'E'E'E'E'E'Er   tuple)rK   rt   rl   s    @r   
<dictcomp>z"Alphabet.union.<locals>.<dictcomp>r   s9    ```&&%'E'E'E'E9'E'E'E"E"E```r   c                     i | ]\  }}||	S r   r   rK   iks      r   rw   z"Alphabet.union.<locals>.<dictcomp>v       CCC1q!CCCr   c                 2    i | ]\  }}|D ]}||         S r   r   rK   rp   rS   rt   keys_to_keys       r   rw   z"Alphabet.union.<locals>.<dictcomp>w   I     2 2 2,tW)02 2% ";t#4 2 2 2 2r   c                     g | ]}i S r   r   rK   _s     r   
<listcomp>z"Alphabet.union.<locals>.<listcomp>z   s    555ar555r   )
	frozensetunionr   ra   rP   r8   	enumeraterD   ziprv   )rl   all_symbolssymbol_to_keyskeys_to_symbolsrt   rp   resultnew_to_old_mappingsnew_keyold_key
new_to_oldr   s   `          @r   r   zAlphabet.unionp   s^   'ikk')V)VI)V)V)VW````T_```%d++*0022 	1 	1LFDD!((0000CC	/(B(BCCC 2 2 2 20?0E0E0G0G2 2 2 3 3 659555(..00 	. 	.MD''*41D'E'E . .#&-
7##.u01111r   c                 N    t          d t          |          D                       S )Nc                 >    i | ]\  }}|D ]}|t          |          S r   )rB   )rK   rz   grouprc   s       r   rw   z(Alphabet.from_groups.<locals>.<dictcomp>   s5    ^^^EX]^^STM!,,^^^^r   )rD   r   )clsgroupss     r   from_groupszAlphabet.from_groups   s'    ^^Yv=N=N^^^___r   r%   c                     t           j                                      j                  } fd|D             }t          t                    }|                                D ] \  }}||                             |           !d t          |          D             t          fd|                                D                       }d  fD             }d  fD             }	                                D ]=\  }}
t          |||	          D ]&\  }}}||                             |
           |||
<   '>|t          |	          fS )Nc                 N    i | ] t          fd fD                       !S )c              3   (   K   | ]}|         V  d S r(   r   rs   s     r   rO   z0Alphabet.intersect.<locals>.<dictcomp>.<genexpr>   s'      'I'Ia&	'I'I'I'I'I'Ir   ru   )rK   rt   r%   r   s    @r   rw   z&Alphabet.intersect.<locals>.<dictcomp>   s=    dddf&%'I'I'I'ID%='I'I'I"I"Idddr   c                     i | ]\  }}||	S r   r   ry   s      r   rw   z&Alphabet.intersect.<locals>.<dictcomp>   r|   r   c                 2    i | ]\  }}|D ]}||         S r   r   r~   s       r   rw   z&Alphabet.intersect.<locals>.<dictcomp>   r   r   c                 6    g | ]}t          t                    S r   )r   ra   r   s     r   r   z&Alphabet.intersect.<locals>.<listcomp>   s     HHHQ{400HHHr   c                     g | ]}i S r   r   r   s     r   r   z&Alphabet.intersect.<locals>.<listcomp>   s    999ar999r   )r   rX   intersectionr   ra   rP   r8   r   rD   r   rv   )r   r%   r   r   r   rt   rp   r   old_to_new_mappingsr   r   r   
old_to_newr   r   s   ``            @r   	intersectzAlphabet.intersect   s    455BB5CXYYdddddXcddd%d++*0022 	1 	1LFDD!((0000CC	/(B(BCCC 2 2 2 20?0E0E0G0G2 2 2 3 3 IH4-HHH99D%=999(..00 	. 	.MD'36t=PRe3f3f . ./Z7#**7333&-
7##. u01111r   c                 N    t          | j                                                  S r(   )rD   rX   copyr   s    r   r   zAlphabet.copy   s    ,1133444r   N)rl   rD   rY   rm   )r%   rD   rY   rm   )r   r   r   propertyrG   r   r"   intr[   r^   r   r	   rQ   r   rB   re   ri   rk   r   classmethodr   r   r   r   r   r   rD   rD   F   s       # # X#? ? ?B B B) ) ) ) )* * *2tE#7G2G,H-,W'X 2 2 2 2. . ., , ,2 2 2 2  ` ` [`2 2 2 2$5 5 5 5 5r   rD   c                       e Zd ZdZdS )OblivionErroraJ  
        This exception is thrown while `crawl()`ing an FSM if we transition to the
        oblivion state. For example while crawling two FSMs in parallel we may
        transition to the oblivion state of both FSMs at once. This warrants an
        out-of-bound signal which will reduce the complexity of the new FSM's map.
    N)r   r   r   r.   r   r   r   r   r      s          	Dr   r   c                      e Zd ZU dZeed<   eed<   ee         ed<   ee         ed<   eeee	ef         f         ed<   d Z
dd	defd
ZdefdZd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zdd defdZd  Z d! Z!d" Z"d# Z#d9d%Z$d& Z%d' Z&d( Z'd) Z(d* Z)d+ Z*d, Z+d- Z,d. Z-d/ Z.d0 Z/d1 Z0d2 Z1d3 Z2d4 Z3d5 Z4d6 Z5d7 Z6d8 Z7d$S ):FSMa*  
        A Finite State Machine or FSM has an alphabet and a set of states. At any
        given moment, the FSM is in one state. When passed a symbol from the
        alphabet, the FSM jumps to another state (or possibly the same state).
        A map (Python dictionary) indicates where to jump.
        One state is nominated as a starting state. Zero or more states are
        nominated as final states. If, after consuming a string of symbols,
        the FSM is in a final state, then it is said to "accept" the string.
        This class also has some pretty powerful methods which allow FSMs to
        be concatenated, alternated between, multiplied, looped (Kleene star
        closure), intersected, and simplified.
        The majority of these methods are available using operator overloads.
    alphabetinitialstatesfinalsr;   c                      t          d          )z.Immutability prevents some potential problems.zThis object is immutable.)	Exception)r   namevalues      r   __setattr__zFSM.__setattr__   s    3444r   F)__no_validation__c          	         |s't          |t                    st          d          ||vr2t          dt	          |          z   dz   t	          |          z             |                    |          s2t          dt	          |          z   dz   t	          |          z             |                                D ]q}||         D ]f}||         |         |vrTt          dt	          |          z   dz   t	          |          z   dz   t	          ||         |                   z   d	z             gr|| j        d
<   t          |          | j        d<   || j        d<   t          |          | j        d<   || j        d<   dS )a~  
            `alphabet` is an iterable of symbols the FSM can be fed.
            `states` is the set of states for the FSM
            `initial` is the initial state
            `finals` is the set of accepting states
            `map` may be sparse (i.e. it may omit transitions). In the case of omitted
            transitions, a non-final "oblivion" state is simulated.
        zExpected an Alphabet instancezInitial state z must be one of zFinal states z must be a subset of zTransition for state z and symbol z
 leads to z, which is not a stater   r   r   r   r;   N)	
isinstancerD   	TypeErrorr   reprissubsetrp   __dict__r   )	r   r   r   r   r   r;   r   statert   s	            r   re   zFSM.__init__   s    ! 	Ph11 A ?@@@f$$ 04== @CU UX\]cXdXd deee??6** i$v,, >AX X[_`f[g[g ghhh P P!%j P PFu:f-77'3d5kkANRUYZ`UaUaadppsw #E
6 2t4 t4 46NOP P P 8P %-j!"+F"3"3h#*i "+F"3"3h"er   inputc                     | j         }|D ][}t          | j        v r|| j        vrt          }| j        |         }|| j        v r|| j        |         v s dS | j        |         |         }\|| j        v S )a  
            Test whether the present FSM accepts the supplied string (iterable of
            symbols). Equivalently, consider `self` as a possibly-infinite set of
            strings and test whether `string` is a member of it.
            This is actually mainly used for unit testing purposes.
            If `fsm.anything_else` is in your alphabet, then any symbol not in your
            alphabet will be converted to `fsm.anything_else`.
        F)r   r   r   r;   r   )r   r   r   rt   
transitions        r   acceptszFSM.accepts   s      		0 		0F--f6M6M&v.J TX%%**G*GuuHUOJ/EE##r   c                 ,    |                      |          S )z
            This lets you use the syntax `"a" in fsm1` to see whether the string "a"
            is in the set of strings accepted by `fsm1`.
        r   r   strings     r   rk   zFSM.__contains__   s    
 ||F###r   c                 N    |                                                                   S )z
            A result by Brzozowski (1963) shows that a minimal finite state machine
            equivalent to the original can be obtained by reversing the original
            twice.
        reversedr   s    r   reducez
FSM.reduce   s     }}'')))r   c                    d}|dt          | j                  z   z  }|dt          | j                  z   z  }|dt          | j                  z   z  }|dt          | j                  z   z  }|dt          | j                  z   z  }|dz  }|S )Nzfsm(zalphabet = z, states = z, initial = z, finals = z, map = rV   )r   r   r   r   r   r;   r   s     r   r"   zFSM.__repr__  s    -$t}"5"555-$t{"3"333.4#5#555-$t{"3"333*tDH~~--#r   c                 b   g g d}|                     d t          | j                  D                                            |           | j        D ]3}g }|| j        k    r|                    d           n|                    d           |                    t          |                     || j        v r|                    d           n|                    d           t          | j                                                  D ]f\  }}|| j	        v rC|| j	        |         v r4|                    t          | j	        |         |                              Q|                    d           g                    |           5g }t          t          d                             D ]N|                    t          fdt          t                              D                       d	z              Ot          t                              D ]W}t          t          |                             D ]2|                                      |                   |         <   3X                    d	d
 |D                        d                    d D                       S )N) r   zfinal?c              3   4   K   | ]}t          |          V  d S r(   r   )rK   rt   s     r   rO   zFSM.__str__.<locals>.<genexpr>  s*      II9V$$IIIIIIr   *r   TrueFalser   c              3   h   K   | ],}t          t          |                                      V  -d S r(   )r9   rQ   )rK   yrowsxs     r   rO   zFSM.__str__.<locals>.<genexpr>*  s9       P P!Sa__!5!5 P P P P P Pr   r2   c                     g | ]}d |z  S )r4   r   )rK   colwidths     r   r   zFSM.__str__.<locals>.<listcomp>2  s    AAA8hAAAr   c              3   F   K   | ]}d                      |          dz   V  dS )r   rI   N)r<   )rK   rows     r   rO   zFSM.__str__.<locals>.<genexpr>4  s1      ;;srwws||d*;;;;;;r   )r:   r6   r   r8   r   r   rQ   r   rP   r;   ranger9   maxljustinsertr<   )	r   r   r   rt   r   	colwidthsr   r   r   s	          @@r   r   zFSM.__str__  s    %$$

II6$-3H3HIIIIIIC [ 	 	EC$$

3

2JJs5zz"""##

6""""

7###&,T]-@-@-B-B&C&C # #"
DH$$tx)F)FJJs48E?:#>??@@@@JJrNNNNKK 	s47||$$ 	V 	VAS P P P P PuSYY?O?O P P PPPSTTUUUU s4yy!! 	< 	<A3tAw<<(( < <!!WQZ--il;;Q

< 	AAAyAAABBBww;;d;;;;;;r   c                      t                     dk    rt          t          i                     S t          j        d  D              \  }t                     dz
   d         c fdt	                      }t                     dk    r*|                     d d         j                             t          |          }fd} fd}t          ||||          S )zR
            Concatenate arbitrarily many finite state machines together.
        r   c                     g | ]	}|j         
S r   r   rK   fsms     r   r   z#FSM.concatenate.<locals>.<listcomp><  s    /M/M/M/M/M/Mr   r2   r1   c                     | |fh}| k     rM||          j         v r>| dz  } |          j        }|                    | |f           | k     r||          j         v >|S )a   
                Take a state in the numbered FSM and return a set containing it, plus
                (if it's final) the first state from the next FSM, plus (if that's
                final) the first state from the next but one FSM, plus...
            r2   )r   r   add)rz   substater   fsms
last_indexs      r   connect_allz$FSM.concatenate.<locals>.connect_all?  su     (m_Fj..Xa%?%?Q7?

Ax=))) j..Xa%?%? Mr   c                 <    | D ]\  }}|k    r|j         v r dS dS )z7If you're in a final state of the final FSM, it's finalTFr   )r   rz   r   lastr   s      r   finalzFSM.concatenate.<locals>.finalT  s8    !&    H
??x4;'>'>445r   c           	      0   t                      }| D ]m\  }}|         }||j        v rW|         |         |j        |         v r<|                     ||j        |         |         |                                       n|st          t	          |          S )z
                Follow the collection of states through all FSMs at once, jumping to the
                next FSM if we reach the end of the current one
                TODO: improve all follow() implementations to allow for dead metastates?
            )setr;   updater   r   )	currentnew_transitionnextrz   r   r   r   r   r   s	         r   followzFSM.concatenate.<locals>.follow[  s     55D!( b bH1gsw&&:a=+HCGT\L]+]+]KKAswx/@A~A^/_ ` `aaa $##T??"r   )	r9   epsilonrD   r   r   r   r   r   crawl)	r   r   r   r   r   r   r   r   r   s	   `    @@@@r   concatenatezFSM.concatenate6  s&    t99>>8B<<((('~/M/M/M/M/MN*t99q=$r(
D	 	 	 	 	 	  %%t99q==NN;;q$q'/::;;;G$$	 	 	 	 	 		# 	# 	# 	# 	# 	# 	# Xwv666r   c                 ,    |                      |          S )aK  
            Concatenate two finite state machines together.
            For example, if self accepts "0*" and other accepts "1+(0|1)",
            will return a finite state machine accepting "0*1+(0|1)".
            Accomplished by effectively following non-deterministically.
            Call using "fsm3 = fsm1 + fsm2"
        )r   r$   s     r   __add__zFSM.__add__l  s     &&&r   c                       j         } j        h} fd} fd}t          ||||          }|j        |j        hz  |j        d<   |S )z
            If the present FSM accepts X, returns an FSM accepting X* (i.e. 0 or
            more Xes). This is NOT as simple as naively connecting the final states
            back to the initial state: see (b*ab)* for example.
        c                    t                      }| D ]}|j        v r5|j        |         v r&|                    j        |         |                    |j        v rMj        j        v r?|j        j                 v r+|                    j        j                 |                    |st
          t          |          S r(   )r   r;   r   r   r   r   r   )r   r   r   r   r   s       r   r   zFSM.star.<locals>.follow  s    55D! 	A 	Atx''J$(8:L,L,LHHTXh/
;<<< t{** LDH44&$(4<*@@@HHTXdl3J?@@@ $##T??"r   c                 :    t          fd| D                       S )Nc              3   *   K   | ]}|j         v V  d S r(   r   )rK   r   r   s     r   rO   z*FSM.star.<locals>.final.<locals>.<genexpr>  s*      EE8x4;.EEEEEEr   anyr   r   s    r   r   zFSM.star.<locals>.final  s&    EEEEuEEEEEEr   r   )r   r   r   r   r   )r   r   r   r   r   bases   `     r   starzFSM.starv  s}     =<.	# 	# 	# 	# 	#$	F 	F 	F 	F 	F Xwv66"&+">hr   c                      dk     rt          dt                    z              j        } j        dfh} fd} fd}t	          ||||          S )O
            Given an FSM and a multiplier, return the multiplied FSM.
        r   zCan't multiply an FSM by c                 \    | D ]'\  }}|j         k    rj         j        v s|k    r dS (dS )zAIf the initial state is final then multiplying doesn't alter thatTF)r   r   )r   r   	iteration
multiplierr   s      r   r   zFSM.times.<locals>.final  sJ    ).    %9t|++!\T[88I<S<S445r   c                 h   g }| D ]\  }}|k     ry|j         v rp|j         |         v ra|                    j         |         |         |f           j         |         |         j        v r|                    j        |dz   f           t	          |          dk    rt
          t          |          S )Nr2   r   )r;   r8   r   r   r9   r   r   )r   r   r   r   r  r  r   s        r   r   zFSM.times.<locals>.follow  s    D)0 C C%9z))$00&$(8*<<<KK(!3J!? KLLLx)*5DDT\9q=$ABBB4yyA~~##T??"r   )r   r   r   r   r   )r   r  r   r   r   r   s   ``    r   timesz	FSM.times  s     >>7$z:J:JJKKK= L!$%	 	 	 	 	 		# 	# 	# 	# 	# 	# Xwv666r   c                 ,    |                      |          S )r  )r  )r   r  s     r   __mul__zFSM.__mul__  s     zz*%%%r   c                  ,    t          | t                    S )z
            Treat `fsms` as a collection of arbitrary FSMs and return the union FSM.
            Can be used as `fsm1.union(fsm2, ...)` or `fsm.union(fsm1, ...)`. `fsms`
            may be empty.
        )parallelr   r   s    r   r   z	FSM.union  s     c"""r   c                 ,    |                      |          S )a/  
            Alternation.
            Return a finite state machine which accepts any sequence of symbols
            that is accepted by either self or other. Note that the set of strings
            recognised by the two FSMs undergoes a set union.
            Call using "fsm3 = fsm1 | fsm2"
        )r   r$   s     r   __or__z
FSM.__or__  s     zz%   r   c                  ,    t          | t                    S )al  
            Intersection.
            Take FSMs and AND them together. That is, return an FSM which
            accepts any sequence of symbols that is accepted by both of the original
            FSMs. Note that the set of strings recognised by the two FSMs undergoes
            a set intersection operation.
            Call using "fsm3 = fsm1 & fsm2"
        )r
  allr  s    r   r   zFSM.intersection  s     c"""r   c                 ,    |                      |          S )z
            Treat the FSMs as sets of strings and return the intersection of those
            sets in the form of a new FSM. `fsm1.intersection(fsm2, ...)` or
            `fsm.intersection(fsm1, ...)` are acceptable.
        )r   r$   s     r   __and__zFSM.__and__  s       '''r   c                  $    t          | d           S )a  
            Treat `fsms` as a collection of sets of strings and compute the symmetric
            difference of them all. The python set method only allows two sets to be
            operated on at once, but we go the extra mile since it's not too hard.
        c                 :    |                      d          dz  dk    S )NTr3   r2   )countr   s    r   <lambda>z*FSM.symmetric_difference.<locals>.<lambda>  s    w}}T/B/BQ/F1.L r   r
  r  s    r   symmetric_differencezFSM.symmetric_difference  s     LLMMMr   c                 ,    |                      |          S )z
            Symmetric difference. Returns an FSM which recognises only the strings
            recognised by `self` or `other` but not both.
        )r  r$   s     r   __xor__zFSM.__xor__  s    
 ((///r   c                 \      j         }d j        i} fd} fd}t          ||||          S )a,  
            Return a finite state machine which will accept any string NOT
            accepted by self, and will not accept any string accepted by self.
            This is more complicated if there are missing transitions, because the
            missing "dead" state must now be reified.
        r   c                     i }d| v r@| d         j         v r1|j         | d                  v rj         | d                  |         |d<   |S Nr   )r;   )r   r   r   r   s      r   r   z!FSM.everythingbut.<locals>.follow  sW    DG||
dh 6 6:RYZ[R\I];];](71:.z:QKr   c                 ,    d| v o| d         j         v  S r  r   r   s    r   r   z FSM.everythingbut.<locals>.final	  s     U
>uQx4;'>??r   )r   r   r   )r   r   r   r   r   s   `    r   everythingbutzFSM.everythingbut  se     =dl#	 	 	 	 		@ 	@ 	@ 	@ 	@ Xwv666r   r%   rY   c                       j                             j                   \  } j        j        f} fd} fd}	 t          ||||           dS # t          $ r Y dS w xY w)Nc                 D   | \  }}|j         v r;d         |         j         |         v r j         |         d         |                  }nd }|j         v r;d         |         j         |         v r j         |         d         |                  }nd }|r|st          ||fS Nr   r2   r;   r   )	r   r   ssossnonr   r%   r   s	         r   r   zFSM.isdisjoint.<locals>.follow  s    FBTX~~*Q-
";tx|"K"KXb\*Q-
";<UY:a=#<	"#M#MYr]:a=#<= $R $##r6Mr   c                 V    | d         j         v r| d         j         v r	t          d S d S r!  )r   r   )r   r%   r   s    r   r   zFSM.isdisjoint.<locals>.final"  s7    Qx4;&&58u|+C+C '&+C+Cr   TF)r   r   r   crawl_hash_no_resultr   )r   r%   r   r   r   r   r   s   ``    @r   
isdisjointzFSM.isdisjoint  s    #}66u~FF*</	 	 	 	 	 	 		 	 	 	 	 	
	 7E6BBB 4  	 	 	55	s   A 
A$#A$c                 V   	  j         }t           j                  }i 	 j                                        D ]U\  }}|                                D ];\  }}||f	vrt                      	||f<   	||f                             |           <V	fd} fd}t          ||||          S )
            Return a new FSM such that for every string that self accepts (e.g.
            "beer", the new FSM accepts the reversed string ("reeb").
        c                     t                      }| D ]9}|                                        ||ft                                           :|st          t	          |          S r(   )r   r   getr   r   )r   r   next_statesr   reverse_maps       r   r   zFSM.reversed.<locals>.followD  sg    %%K  P P"";??E:3F#N#NOOOO $##[)))r   c                     j         | v S r(   r   r   s    r   r   zFSM.reversed.<locals>.finalM  s    <5((r   )r   r   r   r;   rP   r   r   r   )
r   r   r   r   transition_mapr   
next_stater   r   r/  s
   `        @r   r   zFSM.reversed.  s    
 =
 DK(( %)X^^%5%5 	A 	A!E>*8*>*>*@*@ A A&
J
+;>><?EEKZ 89Z4599%@@@@A	* 	* 	* 	* 	*	) 	) 	) 	) 	) Xwv666r   c                 *    |                                  S )r+  r   r   s    r   __reversed__zFSM.__reversed__U  s    
 }}r   c                 F   |h}|g}d}|t          |          k     r||         }|| j        v rdS || j        v rQ| j        |         D ]C}| j        |         |         }||vr*|                    |           |                    |           D|dz  }|t          |          k     dS )z:A state is "live" if a final state can be reached from it.r   Tr2   F)r9   r   r;   r8   r   )r   r   seen	reachablerz   r   r   r   s           r   islivez
FSM.islive\  s    wG	#i..  lG$+%%t$("""&(7"3 ' 'J8G,Z8D4''!((...FA #i..   ur   c                 8    |                      | j                   S )a  
            An FSM is empty if it recognises no strings. An FSM may be arbitrarily
            complicated and have arbitrarily many final states while still recognising
            no strings because those final states may all be inaccessible from the
            initial state. Equally, an FSM may be non-empty despite having an empty
            alphabet if the initial state is final.
        )r9  r   r   s    r   emptyz	FSM.emptyn  s     ;;t|,,,,r   Nc              #   Z   K   t           fd j        D                       }t                      } j        }g }||v r$| j        v r|V  |                    ||f           d}|r|                                \  }}|dz  }| j        v rt           j        |                   D ]e} j        |         |         }||v rLt           j	        j
        |                   D ],}	||	gz   }
| j        v r|
V  |                    |
|f           -f|||k    rt          d| d          |dS dS )aH  
            Generate strings (lists of symbols) that this FSM accepts. Since there may
            be infinitely many of these we use a generator instead of constructing a
            static list. Strings will be sorted in order of length and then lexically.
            This procedure uses arbitrary amounts of memory but is very fast. There
            may be more efficient ways to do this, that I haven't investigated yet.
            You can use this in list comprehensions.

            `max_iterations` controls how many attempts will be made to generate strings.
            For complex FSM it can take minutes to actually find something.
            If this isn't acceptable, provide a value to `max_iterations`.
            The approximate time complexity is
            0.15 seconds per 10_000 iterations per 10 symbols
        c              3   F   K   | ]}                     |          |V  d S r(   )r9  )rK   r   r   s     r   rO   zFSM.strings.<locals>.<genexpr>  s4      NN54;;u;M;MNNNNNNNr   r   r2   Nz Couldn't find an example within z iterations)r   r   r   r   r   r8   popleftr;   r6   r   rG   
ValueError)r   max_iterations
livestatesstringscstatecstringrz   r   nstatert   nstrings   `          r   rB  zFSM.stringsx  s     & NNNNDKNNNNN
 '' Z$$NNGV,---  	a ' 1 1WfFA!!"(&)9":": > >J!Xf-j9F++&,T]-H-T&U&U > >F&-&8G%44&-#NNGV+<====)a..@.@ !_N!_!_!_```  	a 	a 	a 	a 	ar   c                 *    |                                  S )zY
            This allows you to do `for string in fsm1` as a list comprehension!
        )rB  r   s    r   r^   zFSM.__iter__  s     ||~~r   c                 0    | |z                                   S )z
            Two FSMs are considered equivalent if they recognise the same strings.
            Or, to put it another way, if their symmetric difference recognises no
            strings.
        r;  r$   s     r   
equivalentzFSM.equivalent  s     u##%%%r   c                 ,    |                      |          S )zv
            You can use `fsm1 == fsm2` to determine whether two FSMs recognise the
            same strings.
        )rJ  r$   s     r   r)   z
FSM.__eq__      
 u%%%r   c                 2    | |z                                    S )zr
            Two FSMs are considered different if they have a non-empty symmetric
            difference.
        rI  r$   s     r   	differentzFSM.different  s    
 5L''))))r   c                 ,    |                      |          S )zo
            Use `fsm1 != fsm2` to determine whether two FSMs recognise different
            strings.
        )rN  r$   s     r   __ne__z
FSM.__ne__  s    
 ~~e$$$r   c                  $    t          | d           S )z
            Difference. Returns an FSM which recognises only the strings
            recognised by the first FSM in the list, but none of the others.
        c                 B    | d         ot          | dd                     S r!  r   r   s    r   r  z FSM.difference.<locals>.<lambda>  s"    gaj.QWQRR[AQAQ=Q r   r  r  s    r   
differencezFSM.difference  s    
 QQRRRr   c                 ,    |                      |          S r(   )rS  r$   s     r   __sub__zFSM.__sub__  s    u%%%r   c                 :     i  fd  j                   S )
            Consider the FSM as a set of strings and return the cardinality of that
            set, or raise an OverflowError if there are infinitely many
        c                 t                        |           r| v r|          t          |           |          S d | <   d}| j        v r|dz  }| j        v rOj        |          D ]A}| j        |          |                   t	          j        j        |                   z  z  }B|| <   nd| <   |          S r!  )r9  OverflowErrorr   r;   r9   r   rG   )r   nr   get_num_stringsnum_stringsr   s      r   r[  z(FSM.cardinality.<locals>.get_num_strings  s    {{5!! 'K''"5)1+E222&u--%)E"DK''FADH$$&*huo y y
__TXe_Z-HIICPTP]PklvPwLxLxxx%&E"" &'E"u%%r   r1  )r   r[  r\  s   `@@r   cardinalityzFSM.cardinality  sC    
 	& 	& 	& 	& 	& 	& 	&0 t|,,,r   c                 *    |                                  S )rW  )r]  r   s    r   r[   zFSM.__len__  s    
 !!!r   c                 0    | |z
                                   S z
            Treat `self` and `other` as sets of strings and see if `self` is a subset
            of `other`... `self` recognises no strings which `other` doesn't.
        rI  r$   s     r   r   zFSM.issubset  s    
 u##%%%r   c                 ,    |                      |          S r`  )r   r$   s     r   __le__z
FSM.__le__
  s    
 }}U###r   c                     | |k    o| |k    S )z~
            Treat `self` and `other` as sets of strings and see if `self` is a proper
            subset of `other`.
        r   r$   s     r   ispropersubsetzFSM.ispropersubset      
 u}..r   c                 ,    |                      |          S )z~
            Treat `self` and `other` as sets of strings and see if `self` is a strict
            subset of `other`.
        )rd  r$   s     r   r&   z
FSM.__lt__  s    
 ""5)))r   c                 0    || z
                                   S zy
            Treat `self` and `other` as sets of strings and see if `self` is a
            superset of `other`.
        rI  r$   s     r   
issupersetzFSM.issuperset  s    
 ##%%%r   c                 ,    |                      |          S rh  )ri  r$   s     r   __ge__z
FSM.__ge__&  rL  r   c                     | |k    o| |k    S )z
            Treat `self` and `other` as sets of strings and see if `self` is a proper
            superset of `other`.
        r   r$   s     r   ispropersupersetzFSM.ispropersuperset-  re  r   c                 ,    |                      |          S )z
            Treat `self` and `other` as sets of strings and see if `self` is a
            strict superset of `other`.
        )rm  r$   s     r   __gt__z
FSM.__gt__4  s    
 $$U+++r   c                     t          | j                                        | j                                        | j        | j                                        | j                                        d          S )z
            For completeness only, since `set.copy()` also exists. FSM objects are
            immutable, so I can see only very odd reasons to need this.
        Tr   r   r   r   r;   r   )r   r   r   r   r   r   r;   r   s    r   r   zFSM.copy;  sc    
 ]''));##%%L;##%%"
 
 
 	
r   c                    	 | j         }|D ]w}|| j        vr$t          | j        vrt          |          t          }|| j        v r| j        |         | j        |         v st
          | j        |         | j        |                  }xt          | j        | j        || j        | j        d          S # t
          $ r t          | j                  cY S w xY w)ao  
            Compute the Brzozowski derivative of this FSM with respect to the input
            string of symbols. <https://en.wikipedia.org/wiki/Brzozowski_derivative>
            If any of the symbols are not members of the alphabet, that's a KeyError.
            If you fall into oblivion, then the derivative is an FSM accepting no
            strings.
        Trq  )
r   r   r   KeyErrorr;   r   r   r   r   null)r   r   r   rt   s       r   derivez
FSM.deriveI  s    	'LE 
? 
?..(DM99&v...*F ))dmF.CtxPU.V.V''f(=> {{H"&     	' 	' 	'&&&&&	's   B)B, ,CCr(   )8r   r   r   r.   rD   __annotations__rA   r   r   rB   r   re   rQ   r   rk   r   r"   r   r   r   r   r  r  r   r  r   r  r  r  r  boolr)  r   r5  r9  r;  rB  r^   rJ  r)   rN  rP  rS  rU  r]  r[   r   rb  rd  r&   ri  rk  rm  ro  r   ru  r   r   r   r   r      s_          NNNJJ	eT-.//	00005 5 5 _d # # # # # # #@$S $ $ $ $,$ $ $* * *  )< )< )<V47 47 47l' ' '! ! !F"7 "7 "7H& & &# # #! ! !	# 	# 	#( ( (N N N0 0 07 7 7. $    @#7 #7 #7N    $- - -4a 4a 4a 4al  & & && & &* * *% % %S S S& & &- - -B" " "& & &$ $ $/ / /* * *& & && & &/ / /, , ,
 
 
$' $' $' $' $'r   r   c                     t          | dhdt                      dt          d | j        D                       id          S )z
        An FSM accepting nothing (not even the empty string). This is
        demonstrates that this is possible, and is also extremely useful
        in some situations
    r   c                     g | ]}|d fS )r   r   )rK   r   s     r   r   znull.<locals>.<listcomp>|  s    NNNj!_NNNr   Trq  )r   r   rb   rG   r   s    r   rt  rt  p  sV     suutNNx7MNNNOO
 	 	 	 	r   c                 0    t          | dhddhi d          S )zn
        Return an FSM matching an empty string, "", only.
        This is very useful in many situations
    r   Trq  )r   r   s    r   r   r     s1    
 ss   r   c                    t          j        d | D              \  }d t          |           D             }t          t          |                     ffd	}t          t          |                     ffd	}t	          ||||          S )z
        Crawl several FSMs in parallel, mapping the states of a larger meta-FSM.
        To determine whether a state in the larger FSM is final, pass all of the
        finality statuses (e.g. [True, False, False] to `test`.
    c                     g | ]	}|j         
S r   r   r   s     r   r   zparallel.<locals>.<listcomp>  s    +I+I+ISCL+I+I+Ir   c                 $    i | ]\  }}||j         S r   r1  )rK   rz   r   s      r   rw   zparallel.<locals>.<dictcomp>  s     >>>(1cq#+>>>r   c                     i }|D ]W\  }}|         |         }|| v r@| |         |j         v r1||j         | |                  v r|j         | |                  |         ||<   X|st          |S r(   r"  )r   r   	fsm_ranger   rz   fold_transitionr   s          r   r   zparallel.<locals>.follow  s     	< 	<DAq']>:NG||
ae++&!%
*;;;%
+N;Q 	 r   c                 8      fd|D             } |          S )Nc                 <    g | ]\  }}|v o|         |j         v S r   r   )rK   rz   r   r   s      r   r   z+parallel.<locals>.final.<locals>.<listcomp>  s1    SSSXa1:8%(cj"8SSSr   r   )r   r  r   tests   `  r   r   zparallel.<locals>.final  s+    SSSSSSStG}}r   )rD   r   r   rv   r   )r   r  r   r   r   r   r   s    `    @r   r
  r
    s     $>+I+ID+I+I+IJHj>>ioo>>>G 38	$2H2H 
 
 
 
 
 
  %Yt__55       7E6222r   c                    |h}t                      }|rx|                                }|                    |            ||           | j        D ]8}	  |||          }||vr|                    |           )# t          $ r Y 5w xY w|vd S d S r(   )r   popr   rG   r   )	r   r   r   r   	unvisitedvisitedr   r   news	            r   r(  r(    s    	IeeG
 'E 	e #0 	' 	'J'fUJ//
 g%%MM#&&& !     ' ' ' ' 's   A88
BBc                 4   |g}t                      }i }d}|t          |          k     r||         } ||          r|                    |           i ||<   | j        D ]u}		  |||	          }
	 |                    |
          }n4# t
          $ r' t          |          }|                    |
           Y nw xY w|||         |	<   f# t          $ r Y rw xY w|dz  }|t          |          k     t          | t          t          |                    d||d          S )a&  
        Given the above conditions and instructions, crawl a new unknown FSM,
        mapping its states, final states and transitions. Return the new FSM.
        This is a pretty powerful procedure which could potentially go on
        forever if you supply an evil version of follow().
    r   r2   Trq  )
r   r9   r   rG   indexr?  r8   r   r   r   )r   r   r   r   r   r   r;   rz   r   r   r   js               r   r   r     sl    YFUUF
C 	
A
c&kk//q	 5<< 	JJqMMM A"0 	' 	'J'veZ00
(T**AA! ( ( (FAMM$'''''( &'Az"" !    	
Q/ c&kk//2 S[[!!   s$    C-B.B43B4
CCN)$r.   _collectionsr   collectionsr   	functoolsr   typingr   r   r   r	   r
   r   r   r   interegular.utilsr   BaseExceptionr   r   r   rQ   r@   r   rA   rB   rD   r   r   r   rt  r   r
  r(  r   r   r   r   <module>r     s@          # # # # # # $ $ $ $ $ $ K K K K K K K K K K K K K K K K K K K K ' ' ' ' ' '	 	 	 	 	m 	 	 	        6 ! ""8E#/?*?$@A    & 	--Q5 Q5 Q5 Q5 Q5wsM)* Q5 Q5 Q5h	 	 	 	 	I 	 	 	I' I' I' I' I' I' I' I'X  $  3 3 3B' ' '.. . . . .r   