forked from logpy/logpy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfacts.py
106 lines (82 loc) · 2.65 KB
/
facts.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from unification import unify, reify
from .util import intersection
from toolz import merge
class Relation(object):
_id = 0
def __init__(self, name=None):
self.facts = set()
self.index = dict()
if not name:
name = "_%d" % Relation._id
Relation._id += 1
self.name = name
def add_fact(self, *inputs):
""" Add a fact to the knowledgebase.
See Also:
fact
facts
"""
fact = tuple(inputs)
self.facts.add(fact)
for key in enumerate(inputs):
if key not in self.index:
self.index[key] = set()
self.index[key].add(fact)
def __call__(self, *args):
""" Returns an evaluated (callable) goal, which returns a list of
substitutions which match args against a fact in the knowledge base.
*args: the goal to evaluate. This consists of vars and values to
match facts against.
>>> from kanren.facts import Relation
>>> from unification import var
>>>
>>> x, y = var('x'), var('y')
>>> r = Relation()
>>> r.add_fact(1, 2, 3)
>>> r.add_fact(4, 5, 6)
>>> list(r(x, y, 3)({})) == [{y: 2, x: 1}]
True
>>> list(r(x, 5, y)({})) == [{y: 6, x: 4}]
True
>>> list(r(x, 42, y)({}))
[]
"""
def goal(substitution):
args2 = reify(args, substitution)
subsets = [self.index[key] for key in enumerate(args)
if key in self.index]
if subsets: # we are able to reduce the pool early
facts = intersection(*sorted(subsets, key=len))
else:
facts = self.facts
for fact in facts:
unified = unify(fact, args2, substitution)
if unified != False:
yield merge(unified, substitution)
return goal
def __str__(self):
return "Rel: " + self.name
__repr__ = __str__
def fact(rel, *args):
""" Declare a fact
>>> from kanren import fact, Relation, var, run
>>> parent = Relation()
>>> fact(parent, "Homer", "Bart")
>>> fact(parent, "Homer", "Lisa")
>>> x = var()
>>> run(1, x, parent(x, "Bart"))
('Homer',)
"""
rel.add_fact(*args)
def facts(rel, *lists):
""" Declare several facts
>>> from kanren import fact, Relation, var, run
>>> parent = Relation()
>>> facts(parent, ("Homer", "Bart"),
... ("Homer", "Lisa"))
>>> x = var()
>>> run(1, x, parent(x, "Bart"))
('Homer',)
"""
for l in lists:
fact(rel, *l)