44
55# pylint: disable=cell-var-from-loop
66
7- from typing import Dict , List , Set , FrozenSet , Tuple , Hashable , Any
7+ from typing import Dict , List , Set , FrozenSet , Tuple , Hashable
88
99from pyformlang .cfg import CFGObject , Variable , Terminal
10- from pyformlang .finite_automaton import FiniteAutomaton
11- from pyformlang .regular_expression import Regex
10+ from pyformlang .fst import FST
1211
1312from .rules import Rules
13+ from .reduced_rule import ReducedRule
1414from .duplication_rule import DuplicationRule
1515from .production_rule import ProductionRule
16+ from .consumption_rule import ConsumptionRule
1617from .end_rule import EndRule
1718from .utils import exists , addrec_bis
1819from ..objects .cfg_objects .utils import to_variable
@@ -47,7 +48,7 @@ def __init__(self,
4748 # Mark all end symbols
4849 for non_terminal_a in non_terminals :
4950 if exists (self ._rules .rules ,
50- lambda x : x . is_end_rule ( )
51+ lambda x : isinstance ( x , EndRule )
5152 and x .left_term == non_terminal_a ):
5253 self ._marked [non_terminal_a ].add (frozenset ())
5354
@@ -363,7 +364,7 @@ def remove_useless_rules(self) -> "IndexedGrammar":
363364 rules = Rules (l_rules , self ._rules .optim )
364365 return IndexedGrammar (rules )
365366
366- def intersection (self , other : Any ) -> "IndexedGrammar" :
367+ def intersection (self , other : FST ) -> "IndexedGrammar" :
367368 """ Computes the intersection of the current indexed grammar with the \
368369 other object
369370
@@ -387,14 +388,18 @@ def intersection(self, other: Any) -> "IndexedGrammar":
387388 When trying to intersection with something else than a regular
388389 expression or a finite automaton
389390 """
390- if isinstance (other , Regex ):
391- other = other .to_epsilon_nfa ()
392- if isinstance (other , FiniteAutomaton ):
393- fst = other .to_fst ()
394- return fst .intersection (self )
395- raise NotImplementedError
396-
397- def __and__ (self , other : Any ) -> "IndexedGrammar" :
391+ new_rules : List [ReducedRule ] = [EndRule ("T" , "epsilon" )]
392+ self ._extract_consumption_rules_intersection (other , new_rules )
393+ self ._extract_indexed_grammar_rules_intersection (other , new_rules )
394+ self ._extract_terminals_intersection (other , new_rules )
395+ self ._extract_epsilon_transitions_intersection (other , new_rules )
396+ self ._extract_fst_delta_intersection (other , new_rules )
397+ self ._extract_fst_epsilon_intersection (other , new_rules )
398+ self ._extract_fst_duplication_rules_intersection (other , new_rules )
399+ rules = Rules (new_rules , self .rules .optim )
400+ return IndexedGrammar (rules ).remove_useless_rules ()
401+
402+ def __and__ (self , other : FST ) -> "IndexedGrammar" :
398403 """ Computes the intersection of the current indexed grammar with the
399404 other object
400405
@@ -409,3 +414,110 @@ def __and__(self, other: Any) -> "IndexedGrammar":
409414 The indexed grammar which useless rules
410415 """
411416 return self .intersection (other )
417+
418+ def _extract_fst_duplication_rules_intersection (
419+ self ,
420+ other : FST ,
421+ new_rules : List [ReducedRule ]) \
422+ -> None :
423+ for final_state in other .final_states :
424+ for start_state in other .start_states :
425+ new_rules .append (DuplicationRule (
426+ "S" ,
427+ (start_state , "S" , final_state ),
428+ "T" ))
429+
430+ def _extract_fst_epsilon_intersection (
431+ self ,
432+ other : FST ,
433+ new_rules : List [ReducedRule ]) \
434+ -> None :
435+ for state in other .states :
436+ new_rules .append (EndRule (
437+ (state , "epsilon" , state ),
438+ "epsilon" ))
439+
440+ def _extract_fst_delta_intersection (
441+ self ,
442+ other : FST ,
443+ new_rules : List [ReducedRule ]) \
444+ -> None :
445+ for (s_from , symb_from ), (s_to , symb_to ) in other :
446+ new_rules .append (EndRule (
447+ (s_from , symb_from , s_to ),
448+ symb_to ))
449+
450+ def _extract_epsilon_transitions_intersection (
451+ self ,
452+ other : FST ,
453+ new_rules : List [ReducedRule ]) \
454+ -> None :
455+ for state_p in other .states :
456+ for state_q in other .states :
457+ for state_r in other .states :
458+ new_rules .append (DuplicationRule (
459+ (state_p , "epsilon" , state_q ),
460+ (state_p , "epsilon" , state_r ),
461+ (state_r , "epsilon" , state_q )))
462+
463+ def _extract_indexed_grammar_rules_intersection (
464+ self ,
465+ other : FST ,
466+ new_rules : List [ReducedRule ]) \
467+ -> None :
468+ for rule in self .rules .rules :
469+ if isinstance (rule , DuplicationRule ):
470+ for state_p in other .states :
471+ for state_q in other .states :
472+ for state_r in other .states :
473+ new_rules .append (DuplicationRule (
474+ (state_p , rule .left_term , state_q ),
475+ (state_p , rule .right_terms [0 ], state_r ),
476+ (state_r , rule .right_terms [1 ], state_q )))
477+ elif isinstance (rule , ProductionRule ):
478+ for state_p in other .states :
479+ for state_q in other .states :
480+ new_rules .append (ProductionRule (
481+ (state_p , rule .left_term , state_q ),
482+ (state_p , rule .right_term , state_q ),
483+ rule .production ))
484+ elif isinstance (rule , EndRule ):
485+ for state_p in other .states :
486+ for state_q in other .states :
487+ new_rules .append (DuplicationRule (
488+ (state_p , rule .left_term , state_q ),
489+ (state_p , rule .right_term , state_q ),
490+ "T" ))
491+
492+ def _extract_terminals_intersection (
493+ self ,
494+ other : FST ,
495+ new_rules : List [ReducedRule ]) \
496+ -> None :
497+ for terminal in self .rules .terminals :
498+ for state_p in other .states :
499+ for state_q in other .states :
500+ for state_r in other .states :
501+ new_rules .append (DuplicationRule (
502+ (state_p , terminal , state_q ),
503+ (state_p , "epsilon" , state_r ),
504+ (state_r , terminal , state_q )))
505+ new_rules .append (DuplicationRule (
506+ (state_p , terminal , state_q ),
507+ (state_p , terminal , state_r ),
508+ (state_r , "epsilon" , state_q )))
509+
510+ def _extract_consumption_rules_intersection (
511+ self ,
512+ other : FST ,
513+ new_rules : List [ReducedRule ]) \
514+ -> None :
515+ consumptions = self .rules .consumption_rules
516+ for terminal in consumptions :
517+ for consumption in consumptions [terminal ]:
518+ for state_r in other .states :
519+ for state_s in other .states :
520+ new_rules .append (ConsumptionRule (
521+ consumption .f_parameter ,
522+ (state_r , consumption .left_term , state_s ),
523+ (state_r , consumption .right_term , state_s )))
0 commit comments