Loading grammars_cfg.py +39 −28 Original line number Original line Diff line number Diff line Loading @@ -529,7 +529,7 @@ class CFG: return word return word if full_cmp_cnt is None: if full_cmp_cnt is None: full_cmp_cnt = pow(2, 12) full_cmp_cnt = pow(2, 16) if max_cmp_len is None: if max_cmp_len is None: max_cmp_len = min(max(pow(2, len(left.nonterminals) + 1), max_cmp_len = min(max(pow(2, len(left.nonterminals) + 1), Loading Loading @@ -764,8 +764,10 @@ class WordGenerator: def __init__(self, cfg: CFG): def __init__(self, cfg: CFG): self.cfg = cfg.cnf() self.cfg = cfg.cnf() self.seen: Set[CFG.Symbols] = set() self._seen: Set[CFG.Symbols] = set() self.queue: Deque[CFG.Symbols] = deque([(self.cfg.init,)]) self._stack: List[CFG.Symbols] = [(self.cfg.init,)] self._cur_lenght = 1 self._next_length: Optional[int] = 2 self.last: Optional[CFG.Word] = None \ self.last: Optional[CFG.Word] = None \ if Eps() not in self.cfg.rules.get(self.cfg.init, []) \ if Eps() not in self.cfg.rules.get(self.cfg.init, []) \ else () else () Loading @@ -781,20 +783,21 @@ class WordGenerator: return self.last return self.last def _next(self) -> Optional[CFG.Word]: def _next(self) -> Optional[CFG.Word]: # Walk in BFS order so the the sentences are explored from shorter # Iterative-Deepening DFS (as a generator) # to longer for CNF. while self._stack or self._next_length is not None: # As we yield a word immediatelly on finding it between the sentences while self._stack: # (i.e., when we find a sentence with no nonterminals), we also yield sentence = self._stack.pop() # words from shorter to longer for CNF grammars (because a word of if len(sentence) > self._cur_lenght: # cutoff # length N needs exactly N + (N - 1) derivations in CNF and therefore self._next_length = len(sentence) \ # shorter words preceed longer once in BFS order. if self._next_length is None \ while self.queue: else min(self._next_length, len(sentence)) sentence = self.queue.popleft() if sentence in self.seen: continue continue self.seen.add(sentence) if sentence in self._seen: continue self._seen.add(sentence) if CFG.all_terminal(sentence): if CFG.all_terminal(sentence): if len(sentence) == self._cur_lenght: self.last = typing.cast(CFG.Word, sentence) self.last = typing.cast(CFG.Word, sentence) return self.last return self.last else: else: Loading @@ -805,6 +808,14 @@ class WordGenerator: if isinstance(p, Eps): if isinstance(p, Eps): continue continue new_sentence = sentence[:i] + p + sentence[i + 1:] new_sentence = sentence[:i] + p + sentence[i + 1:] self.queue.append(new_sentence) self._stack.append(new_sentence) break # it suffices to perform left derivations break # it suffices to perform left derivations if self._next_length is not None \ and self._next_length > self._cur_lenght: self._cur_lenght = self._next_length self._next_length = None self._stack = [(self.cfg.init,)] self._seen = set() return None return None Loading
grammars_cfg.py +39 −28 Original line number Original line Diff line number Diff line Loading @@ -529,7 +529,7 @@ class CFG: return word return word if full_cmp_cnt is None: if full_cmp_cnt is None: full_cmp_cnt = pow(2, 12) full_cmp_cnt = pow(2, 16) if max_cmp_len is None: if max_cmp_len is None: max_cmp_len = min(max(pow(2, len(left.nonterminals) + 1), max_cmp_len = min(max(pow(2, len(left.nonterminals) + 1), Loading Loading @@ -764,8 +764,10 @@ class WordGenerator: def __init__(self, cfg: CFG): def __init__(self, cfg: CFG): self.cfg = cfg.cnf() self.cfg = cfg.cnf() self.seen: Set[CFG.Symbols] = set() self._seen: Set[CFG.Symbols] = set() self.queue: Deque[CFG.Symbols] = deque([(self.cfg.init,)]) self._stack: List[CFG.Symbols] = [(self.cfg.init,)] self._cur_lenght = 1 self._next_length: Optional[int] = 2 self.last: Optional[CFG.Word] = None \ self.last: Optional[CFG.Word] = None \ if Eps() not in self.cfg.rules.get(self.cfg.init, []) \ if Eps() not in self.cfg.rules.get(self.cfg.init, []) \ else () else () Loading @@ -781,20 +783,21 @@ class WordGenerator: return self.last return self.last def _next(self) -> Optional[CFG.Word]: def _next(self) -> Optional[CFG.Word]: # Walk in BFS order so the the sentences are explored from shorter # Iterative-Deepening DFS (as a generator) # to longer for CNF. while self._stack or self._next_length is not None: # As we yield a word immediatelly on finding it between the sentences while self._stack: # (i.e., when we find a sentence with no nonterminals), we also yield sentence = self._stack.pop() # words from shorter to longer for CNF grammars (because a word of if len(sentence) > self._cur_lenght: # cutoff # length N needs exactly N + (N - 1) derivations in CNF and therefore self._next_length = len(sentence) \ # shorter words preceed longer once in BFS order. if self._next_length is None \ while self.queue: else min(self._next_length, len(sentence)) sentence = self.queue.popleft() if sentence in self.seen: continue continue self.seen.add(sentence) if sentence in self._seen: continue self._seen.add(sentence) if CFG.all_terminal(sentence): if CFG.all_terminal(sentence): if len(sentence) == self._cur_lenght: self.last = typing.cast(CFG.Word, sentence) self.last = typing.cast(CFG.Word, sentence) return self.last return self.last else: else: Loading @@ -805,6 +808,14 @@ class WordGenerator: if isinstance(p, Eps): if isinstance(p, Eps): continue continue new_sentence = sentence[:i] + p + sentence[i + 1:] new_sentence = sentence[:i] + p + sentence[i + 1:] self.queue.append(new_sentence) self._stack.append(new_sentence) break # it suffices to perform left derivations break # it suffices to perform left derivations if self._next_length is not None \ and self._next_length > self._cur_lenght: self._cur_lenght = self._next_length self._next_length = None self._stack = [(self.cfg.init,)] self._seen = set() return None return None