prolog4.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. def val_is_var(val):
  2. return type(val) is str and (val[0].isupper() or val[0] == '_')
  3. def val_is_const(val):
  4. return type(val) is str and val[0].islower()
  5. fake_var_cnt = 0
  6. def fake_var():
  7. global fake_var_cnt
  8. var = '_' + str(fake_var_cnt)
  9. fake_var_cnt += 1
  10. return var
  11. def unify_not_var(left, right, lbinds, rbinds):
  12. if type(left) is not type(right):
  13. return False
  14. # constants
  15. if val_is_const(left):
  16. return left == right
  17. # lists
  18. if type(left) is not list:
  19. return False
  20. if len(left) != len(right):
  21. return False
  22. for new_left, new_right in zip(left, right):
  23. if not unify(new_left, new_right, lbinds, rbinds):
  24. return False
  25. return True
  26. def propgate(var, val, lbinds, rbinds):
  27. if var in lbinds:
  28. propgate(lbinds[var], val, lbinds, rbinds)
  29. del lbinds[var]
  30. if var in rbinds:
  31. propgate(rbinds[var], val, lbinds, rbinds)
  32. del rbinds[var]
  33. for key, value in lbinds.items():
  34. if value == var:
  35. lbinds[key] = val
  36. for key, value in rbinds.items():
  37. if value == var:
  38. rbinds[key] = val
  39. def unify(left, right, lbinds, rbinds):
  40. if not val_is_var(left):
  41. if not val_is_var(right):
  42. return unify_not_var(left, right, lbinds, rbinds)
  43. if not right in rbinds:
  44. rbinds[right] = left
  45. return True
  46. if not val_is_var(rbinds[right]):
  47. return unify_not_var(left, rbinds[right], lbinds, rbinds)
  48. propgate(rbinds[right], left, lbinds, rbinds)
  49. return True
  50. if not left in lbinds:
  51. if not val_is_var(right):
  52. lbinds[left] = right
  53. return True
  54. if not right in rbinds:
  55. lbinds[left] = rbinds[right] = fake_var()
  56. return True
  57. lbinds[left] = rbinds[right]
  58. return True
  59. if not val_is_var(lbinds[left]):
  60. if not val_is_var(right):
  61. return unify_not_var(lbinds[left], right, lbinds, rbinds)
  62. if not right in rbinds:
  63. rbinds[right] = lbinds[left]
  64. return True
  65. if not val_is_var(rbinds[right]):
  66. return unify_not_var(lbinds[left], rbinds[right], lbinds, rbinds)
  67. propgate(rbinds[right], lbinds[left], lbinds, rbinds)
  68. return True
  69. if not val_is_var(right):
  70. propgate(lbinds[left], right, lbinds, rbinds)
  71. return True
  72. if not right in rbinds:
  73. rbinds[right] = lbinds[left]
  74. return True
  75. # if not val_is_var(rbinds[right]):
  76. # return propagate(lbinds[left], rbinds[right], lbinds, rbinds)
  77. propagate(lbinds[left], rbinds[right], lbinds, rbinds)
  78. return True
  79. def options(binds):
  80. for val in binds.values():
  81. if not val_is_var(val):
  82. return True
  83. return False
  84. class Search:
  85. def __init__(self, base, query):
  86. self.query = query
  87. self.place = iter(base)
  88. self.up_binds = None
  89. self.scope = None
  90. def scope_bind(self):
  91. new_binds = {}
  92. for key, value in self.up_binds.items():
  93. new_binds[key] = self.scope.bind(value)
  94. return new_binds
  95. def get(self, base):
  96. if self.scope is not None:
  97. if self.scope.run(base) is True:
  98. return self.scope_bind()
  99. self.up_binds = None
  100. self.scope = None
  101. for fact in self.place:
  102. lbinds = {}
  103. rbinds = {}
  104. if unify(self.query, fact[0], lbinds, rbinds):
  105. if fact[1] is True:
  106. return lbinds
  107. if fact[1] is False:
  108. if options(lbinds):
  109. continue
  110. return False
  111. if fact[1] == 'unknown':
  112. continue
  113. scope = Scope(base, fact[1], rbinds)
  114. if scope.run(base) is True:
  115. self.up_binds = lbinds
  116. self.scope = scope
  117. return self.scope_bind()
  118. return 'unknown'
  119. class Scope:
  120. def __init__(self, base, queries, binds={}):
  121. self.final = None
  122. self.queries = queries
  123. self.sbinds = [binds]
  124. self.searches = [Search(base, self.bind(queries[0]))]
  125. def resl_var(self, var):
  126. for binds in self.sbinds:
  127. if var in binds:
  128. var = binds[var]
  129. if not val_is_var(var):
  130. return self.bind(var)
  131. if self.final is not None:
  132. if var in self.final:
  133. var = self.final[var]
  134. if not val_is_var(var):
  135. return self.bind(var)
  136. return var
  137. def resl_list(self, query):
  138. new = []
  139. for val in query:
  140. new.append(self.bind(val))
  141. return new
  142. def bind(self, query):
  143. if val_is_const(query):
  144. return query
  145. if val_is_var(query):
  146. return self.resl_var(query)
  147. return self.resl_list(query)
  148. def latest_query(self):
  149. return self.bind(self.queries[len(self.searches)])
  150. def run(self, base):
  151. self.final = None
  152. while True:
  153. binds = self.searches[-1].get(base)
  154. if binds is False or binds == 'unknown':
  155. self.sbinds.pop()
  156. self.searches.pop()
  157. if len(self.searches) == 0:
  158. return 'unknown'
  159. elif len(self.searches) == len(self.queries):
  160. self.final = binds
  161. return True
  162. else:
  163. self.sbinds.append(binds)
  164. self.searches.append(Search(base, self.latest_query()))
  165. def unique_binds(val, binds):
  166. if val_is_var(val):
  167. if not val in binds:
  168. binds.add(val)
  169. elif type(val) is list:
  170. for sub_val in val:
  171. unique_binds(sub_val, binds)
  172. def max_binds(val):
  173. binds = set([])
  174. unique_binds(val, binds)
  175. return len(binds)
  176. def base_add(base, fact):
  177. fact_left = fact[0]
  178. left_max = max_binds(fact_left)
  179. for i in range(len(base)):
  180. lbinds = {}
  181. rbinds = {}
  182. if unify(fact_left, base[i][0], lbinds, rbinds):
  183. if len(lbinds) <= len(rbinds):
  184. base.insert(i, fact)
  185. return
  186. else:
  187. right_max = max_binds(base[i][0])
  188. if left_max <= right_max:
  189. base.insert(i, fact)
  190. return
  191. base.append(fact)
  192. base = []
  193. base_add(base, [['human', 'Y'], [['woman', 'Y']] ])
  194. base_add(base, [['cat', 'socrates'], True])
  195. base_add(base, [['man', 'socrates'], False ])
  196. base_add(base, [['human', 'X'], [['man', 'X']] ])
  197. base_add(base, [['likes', 'socrates', 'X'], False])
  198. base_add(base, [['woman', 'ophelia'], True ])
  199. base_add(base, [['mortal', 'Z'], [['human', 'Z']] ])
  200. base_add(base, [['query', 'X'], ['X']])
  201. base_add(base, [['and', 'X', 'Y'], ['X', 'Y']] )
  202. # lbinds = {}
  203. # rbinds = {}
  204. # search = Search(base, ['X', 'socrates'])
  205. # result = search.get(base)
  206. # while result is not False and result != 'unknown':
  207. # print(result)
  208. # result = search.get(base)
  209. # search = Search(base, ['likes', 'socrates', 'X'])
  210. # print(search.get(base))
  211. search = Search(base, ['and', ['cat', 'socrates'], ['man', 'socrates']])
  212. print(search.get(base))