Advertisement
Guest User

Untitled

a guest
Dec 12th, 2023
417
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.86 KB | None | 0 0
  1. from itertools import *
  2. from functools import *
  3. from operator import *
  4. from copy import *
  5.  
  6. class NFA:
  7.     def __init__(self):
  8.         self.trans : list[dict[str, set[int]]] = []
  9.         self.rtrans : list[dict[str, set[int]]] = []
  10.         self.start = 1 << 31
  11.         self.accept =  1 << 31
  12.     def state_count(self) -> int:
  13.         return len(self.trans)
  14.     def add_state(self) -> int:
  15.         state = self.state_count()
  16.         self.trans.append({})
  17.         self.rtrans.append({})
  18.         return state
  19.     def add_transition(self, p : int, c : str, q : int):
  20.         if c in self.trans[p]:
  21.             self.trans[p][c].add(q)
  22.         else:
  23.             self.trans[p][c] = set([q])
  24.         if c in self.rtrans[q]:
  25.             self.rtrans[q][c].add(p)
  26.         else:
  27.             self.rtrans[q][c] = set([p])
  28.         return self
  29.     def remove_transition(self, p : int, c : str, q : int):
  30.         self.trans[p][c].remove(q)
  31.         if len(self.trans[p][c]) == 0:
  32.             del self.trans[p][c]
  33.         self.rtrans[q][c].remove(p)
  34.         if len(self.rtrans[q][c]) == 0:
  35.             del self.rtrans[q][c]
  36.         return self
  37.     def pop_state(self):
  38.         self.trans.pop()
  39.         self.rtrans.pop()
  40.         return self
  41.     def disjoin_state(self, q : int):
  42.         for k in self.trans[q].copy():
  43.             for s in self.trans[q][k].copy():
  44.                 self.remove_transition(q, k, s)
  45.         for k in self.rtrans[q].copy():
  46.             for r in self.rtrans[q][k].copy():
  47.                 self.remove_transition(r, k, q)
  48.         return self
  49.     # merges state p to q, transfering all of the transitions, and disjoining p
  50.     def merge_states(self, p : int, q : int):
  51.         for k in self.trans[p]:
  52.             for s in self.trans[p][k]:
  53.                 self.add_transition(q, k, s)
  54.         for k in self.rtrans[p]:
  55.             for r in self.rtrans[p][k]:
  56.                 self.add_transition(r, k, q)
  57.         self.disjoin_state(p)
  58.         return self
  59.     # returns an automaton that has the same states as self and other, only other's states are shifted by self.state_count()
  60.     def join(self, other):
  61.         otrans = deepcopy(other.trans)
  62.         for d in otrans:
  63.             for k in d:
  64.                 d[k] = set(map(partial(add, self.state_count()), d[k]))
  65.         ortrans = deepcopy(other.rtrans)
  66.         for d in ortrans:
  67.             for k in d:
  68.                 d[k] = set(map(partial(add, self.state_count()), d[k]))
  69.         result = NFA()
  70.         result.trans = self.trans + otrans
  71.         result.rtrans = self.rtrans + ortrans
  72.         return result;
  73.     # vvv these functions aren't quite right when concatenating two closures or alternating with any closrue
  74.     #     fortunately no regexps in this task require doing that
  75.     def concat(self, other):
  76.         result = self.join(other)
  77.         result.merge_states(other.start + self.state_count(), self.accept)
  78.         result.set_start(self.start)
  79.         if other.accept != other.start:
  80.             result.set_accept(other.accept + self.state_count())
  81.         else:
  82.             result.set_accept(self.accept)
  83.         return result
  84.     def alter(self, other):
  85.         result = self.join(other)
  86.         result.merge_states(other.start + self.state_count(), self.start)
  87.         result.merge_states(other.accept + self.state_count(), self.accept)
  88.         result.set_start(self.start)
  89.         result.set_accept(self.accept)
  90.         result.pop_state().pop_state()
  91.         return result
  92.     def closure(self):
  93.         result = deepcopy(self)
  94.         result.merge_states(result.accept, result.start)
  95.         result.set_accept(result.start)
  96.         result.pop_state()
  97.         return result
  98.     def repeat(self, n : int):
  99.         result = deepcopy(self)
  100.         for i in range(1, n):
  101.             result = result.concat(self)
  102.         return result
  103.     def char(c : str):
  104.         nfa = NFA()
  105.         p = nfa.add_state()
  106.         q = nfa.add_state()
  107.         nfa.set_start(p)
  108.         nfa.set_accept(q)
  109.         nfa.add_transition(p, c, q)
  110.         return nfa
  111.     def set_start(self, s : int):
  112.         self.start = s
  113.         return self
  114.     def set_accept(self, f : int):
  115.         self.accept = f
  116.         return self
  117.     def delta(self, p : int, c : str) -> set[int]:
  118.         if c not in self.trans[p]:
  119.             return set()
  120.         return self.trans[p][c]
  121.     def simulate(self, inputstr : str) -> int:
  122.         pset = dict({ self.start : 1 })
  123.         for c in inputstr:
  124.             qset = {}
  125.             for p in pset:
  126.                 for q in self.delta(p, c):
  127.                     if q in qset:
  128.                         qset[q] += pset[p]
  129.                     else:
  130.                         qset[q] = pset[p]
  131.             pset = qset
  132.         result = qset[self.accept]
  133.         return result
  134.     def __repr__(self):
  135.         return f'start = {self.start}\naccept = {self.accept}\ntrans = {self.trans}\nrtrans = {self.rtrans}\n'
  136.  
  137. def mk_nfa(numseq : list[int]):
  138.     head = numseq[0]
  139.     tail = numseq[1:]
  140.     ok_nfa = NFA.char('?').alter(NFA.char('.'))
  141.     many_ok_nfa = ok_nfa.concat(ok_nfa.closure())
  142.     damaged_nfa = NFA.char('?').alter(NFA.char('#'))
  143.     result = ok_nfa.closure()
  144.     result = result.concat(damaged_nfa.repeat(head))
  145.     for i in tail:
  146.         result = result.concat(many_ok_nfa)
  147.         result = result.concat(damaged_nfa.repeat(i))
  148.     result = result.concat(ok_nfa.closure())
  149.     return result
  150. total = 0
  151. for line in filterfalse(str.isspace, open(0).readlines()):
  152.     [inputstr, numseq] = line.split()
  153.     numseq = list(map(int, numseq.split(',')))
  154.     nfa = mk_nfa(numseq)
  155.     total += nfa.simulate(inputstr)
  156. print(total)
  157. for line in filterfalse(str.isspace, open(0).readlines()):
  158.     [inputstr, numseq] = line.split()
  159.     numseq = list(map(int, numseq.split(',')))
  160.     nfa = mk_nfa(numseq * 5)
  161.     total += nfa.simulate('?'.join(repeat(inputstr, 5)))
  162. print(total)
  163.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement