Advertisement
Guest User

Untitled

a guest
Nov 18th, 2018
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.93 KB | None | 0 0
  1. import json
  2. from collections import defaultdict
  3.  
  4.  
  5. class Errors:
  6. E1 = 'E1: A state \'{}\' is not in set of states'
  7. E2 = 'E2: Some states are disjoint'
  8. E3 = 'E3: A transition \'{}\' is not represented in the alphabet'
  9. E4 = 'E4: Initial state is not defined'
  10. E6 = 'E6: FSA is nondeterministic'
  11.  
  12.  
  13. def make_array():
  14. return defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: '{}')))
  15.  
  16.  
  17. class FSARegexTranslator:
  18. def __init__(self, fsa):
  19. self.fsa = fsa
  20.  
  21. def translate(self):
  22. dp = make_array()
  23. for i in self.fsa.states:
  24. for a, j in self.fsa.matrix[i].items():
  25. if dp['#'][i][j] == '{}':
  26. dp['#'][i][j] = a
  27. else:
  28. dp['#'][i][j] += '|{}'.format(a)
  29.  
  30. if dp['#'][i][i] != '{}':
  31. dp['#'][i][i] += '|eps'
  32.  
  33. for ki in range(len(self.fsa.states)):
  34. for i in self.fsa.states:
  35. for j in self.fsa.states:
  36. k = self.fsa.states[ki]
  37. if ki > 0:
  38. kp = self.fsa.states[ki - 1]
  39. else:
  40. kp = '#'
  41.  
  42. dp[k][i][j] = \
  43. '({})'.format(dp[kp][i][k]) + \
  44. '({})*'.format(dp[kp][k][k]) + \
  45. '({})'.format(dp[kp][k][j]) + \
  46. '|' + \
  47. '({})'.format(dp[kp][i][j])
  48.  
  49.  
  50. regexs = [dp[self.fsa.states[-1]][self.fsa._initial][f] for f in self.fsa._final]
  51. return '|'.join(regexs) if regexs else '{}'
  52.  
  53.  
  54.  
  55. class FSA:
  56. def __init__(self, states, alphabet, initial, final, transitions):
  57. self.states = states
  58. self._alphabet = alphabet
  59. self._initial = initial
  60. self._final = final
  61.  
  62. self._nfsa = False
  63.  
  64. self._current = initial
  65. self.matrix = {}
  66. for state in states:
  67. self.matrix[state] = {}
  68.  
  69. for transition in transitions:
  70. s1, a, s2 = transition
  71. if s1 not in states:
  72. raise ValueError(Errors.E1.format(s1))
  73. if s2 not in states:
  74. raise ValueError(Errors.E1.format(s2))
  75. if a not in alphabet:
  76. raise ValueError(Errors.E3.format(a))
  77.  
  78. if a in self.matrix[s1]:
  79. self._nfsa = True
  80.  
  81. self.matrix[s1][a] = s2
  82.  
  83. if not initial:
  84. raise ValueError(Errors.E4)
  85.  
  86. if self._has_disjoint_states():
  87. raise ValueError(Errors.E2)
  88.  
  89. for state in final:
  90. if state not in states:
  91. raise ValueError(Errors.E1.format(state))
  92.  
  93. if initial not in states:
  94. raise ValueError(Errors.E1.format(initial))
  95.  
  96. if self._nfsa:
  97. raise ValueError(Errors.E6)
  98.  
  99. def _has_disjoint_states(self):
  100. graph = defaultdict(list)
  101. for s1 in self.states:
  102. for s2 in self.matrix[s1].values():
  103. graph[s1].append(s2)
  104. graph[s2].append(s1)
  105.  
  106. visited = set()
  107. def dfs(state):
  108. visited.add(state)
  109. for next_state in graph[state]:
  110. if next_state not in visited:
  111. dfs(next_state)
  112.  
  113. dfs(self._initial)
  114.  
  115. return len(visited) != len(self.states)
  116.  
  117. def _every_state_reachable(self):
  118. visited = set()
  119. def dfs(state):
  120. visited.add(state)
  121. for next_state in self.matrix[state].values():
  122. if next_state not in visited:
  123. dfs(next_state)
  124.  
  125. dfs(self._initial)
  126.  
  127. return len(visited) == len(self.states)
  128.  
  129. def validate(self):
  130. warnings = []
  131.  
  132. if self._nfsa:
  133. warnings.append(Errors.E6)
  134.  
  135. return warnings
  136.  
  137. def is_complete(self):
  138. for state in self.states:
  139. if len(self.matrix[state].values()) != len(self._alphabet):
  140. return False
  141. return True
  142.  
  143. def as_regex(self):
  144. return FSARegexTranslator(self).translate()
  145.  
  146.  
  147. def validate_lines(lines):
  148. import re
  149. match_1 = re.fullmatch(r'states={([a-zA-Z0-9]*?,)*([a-zA-Z0-9]*?)}', lines[0].strip())
  150. match_2 = re.fullmatch(r'alpha={([a-zA-Z0-9_]*?,)*([a-zA-Z0-9_]*?)}', lines[1].strip())
  151. match_3 = re.fullmatch(r'init\.st={[a-zA-Z0-9]*?}', lines[2].strip())
  152. match_4 = re.fullmatch(r'fin\.st={([a-zA-Z0-9]*?,)*([a-zA-Z0-9]*?)}', lines[3].strip())
  153. match_5 = re.fullmatch(r'trans={([a-zA-Z0-9]*?>[a-zA-Z0-9_]*?>[a-zA-Z0-9]*?,)*([a-zA-Z0-9]*?>[a-zA-Z0-9_]*?>[a-zA-Z0-9]*?)}', lines[4].strip())
  154. return match_1 and match_2 and match_3 and match_4 and match_5
  155.  
  156.  
  157. def main():
  158. with open('fsa.txt', 'r') as f:
  159. lines = f.readlines()
  160.  
  161. states = [state.strip() for state in lines[0].strip()[8:-1].split(',')]
  162. alphabet = [symbol.strip() for symbol in lines[1].strip()[7:-1].split(',')]
  163. initial = lines[2].strip()[9:-1]
  164. final = [state.strip() for state in lines[3].strip()[8:-1].split(',') if state]
  165. transitions = [
  166. [term.strip() for term in transition.split('>')] for transition in lines[4].strip()[7:-1].split(',')
  167. ]
  168.  
  169. out_lines = []
  170.  
  171. if not validate_lines(lines):
  172. out_lines.append('Error:')
  173. out_lines.append('E5: Input is malformed')
  174. with open('result.txt', 'w') as f:
  175. f.write('\n'.join(out_lines))
  176. return
  177.  
  178. try:
  179. fsa = FSA(states, alphabet, initial, final, transitions)
  180. except ValueError as e:
  181. out_lines.append('Error:')
  182. out_lines.append(str(e))
  183. with open('result.txt', 'w') as f:
  184. f.write('\n'.join(out_lines))
  185. return
  186.  
  187. out_lines.append(fsa.as_regex())
  188.  
  189. with open('result.txt', 'w') as f:
  190. f.write('\n'.join(out_lines))
  191.  
  192.  
  193. if __name__ == '__main__':
  194. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement