Commits

Pierre Carbonnelle  committed da7eaa6

use python engine if no Lua engine.
profiling + use Zip.
Bug: up-scope variables in datalog programs are not recognized (globals are)

  • Participants
  • Parent commits faadd92

Comments (0)

Files changed (3)

File pyDatalog/pyDatalog.py

 * program : decorator function to create datalog programs
 
 """
-import lupa
 import os
 import string
-from lupa import LuaRuntime
 import six
 from six.moves import builtins
 
+try:
+    import lupa
+    from lupa import LuaRuntime
+    Engine = 'Lua'
+except:
+    Engine = 'Python'
+#Engine = 'Python'
+print('Using %s engine for Datalog.' % Engine)
+
 from pyEngine import *
 
 default_datalog_engine = None # will contain the default datalog engine
         "time to create a literal !"
         if self.name == 'ask':
             # TODO check that there is only one argument
-            fast = kwargs['_fast'] if '_fast' in kwargs.keys() else False
+            fast = kwargs['_fast'] if '_fast' in list(kwargs.keys()) else False
             return self.datalog_engine._ask_literal(args[0], fast)
         elif self.type == 'variable':
             raise TypeError("predicate name must start with a lower case : %s" % self.name)
         self.body.append(literal) 
         return self
 
-def Datalog_engine(implementation='Lua'): # factory
-    if implementation == 'Lua':
+def Datalog_engine(implementation=None): # factory
+    if (implementation or Engine) == 'Lua':
         return Lua_engine()
     else:
         return Python_engine()

File pyDatalog/pyEngine.py

 def unify(literal, other):
     if literal.pred != other.pred: return None
     env = {}
-    for i, term in enumerate(literal.terms):
+    for term, otherterm in zip(literal.terms, other.terms):
         literal_i = term.chase(env)
-        other_i = other.terms[i].chase(env)
+        other_i = otherterm.chase(env)
         if literal_i != other_i:
             env = literal_i.unify(other_i, env)
             if env == None: return env
 """
 def fact(subgoal, literal):
     if not is_member(literal, subgoal.facts):
-        if Debug: print ("New fact : %s" % str(literal))
+        if Debug: print("New fact : %s" % str(literal))
         adjoin(literal, subgoal.facts)
         for waiter in reversed(subgoal.waiters):
             resolvent = resolve(waiter.clause, literal)
 def rule(subgoal, clause, selected):
     sg = find(selected)
     if sg != None:
-        if Debug: print ("Rule, subgoal found : %s" % str(sg.literal))
+        if Debug: print("Rule, subgoal found : %s" % str(sg.literal))
         sg.waiters.append(Waiter(subgoal, clause))
         todo = []
-        for fact in sg.facts.values():
+        for fact in list(sg.facts.values()):
             resolvent = resolve(clause, fact)
             if resolvent != None: 
                 todo.append(resolvent)
         for t in todo:
             sched(lambda subgoal=subgoal, t=t: add_clause(subgoal, t))
     else:
-        if Debug: print ("Rule, subgoal not found : %s" % str(subgoal.literal))
+        if Debug: print("Rule, subgoal not found : %s" % str(subgoal.literal))
         sg = make_subgoal(selected)
         sg.waiters.append(Waiter(subgoal, clause))
         merge(sg)
 """
 
 def search(subgoal):
-    if Debug: print ("search : %s" % str(subgoal.literal))
+    if Debug: print("search : %s" % str(subgoal.literal))
     literal = subgoal.literal
     if literal.pred.prim:
         return literal.pred.prim(literal, subgoal)
     else:
-        for clause in literal.pred.db.values():
+        for clause in list(literal.pred.db.values()):
             renamed = rename_clause(clause)
             env = unify(literal, renamed.head)
             if env != None: # lua considers {} as true
     merge(subgoal)
     invoke(lambda subgoal=subgoal: search(subgoal))
     subgoals = None
-    answers = [ tuple([term.id for term in literal.terms]) for literal in subgoal.facts.values()]
+    answers = [ tuple([term.id for term in literal.terms]) for literal in list(subgoal.facts.values())]
     if 0 < len(answers):
-        print answers # TODO
         answer = Answer(get_name(literal.pred), get_arity(literal.pred), answers)
         return answer
     return None
 """
 def match(literal, fact):
     env = {}
-    for i, term in enumerate(literal.terms):
-        if term != fact.terms[i]:
+    for term, factterm in zip(literal.terms, fact.terms):
+        if term != factterm:
             try:
-                if eval(term.id) == eval(fact.terms[i].id):
+                if eval(term.id) == eval(factterm.id):
                     continue
             except:
                 pass
-            env = term.match(fact.terms[i], env)
+            env = term.match(factterm, env)
             if env == None: return env
     return env
 """

File pyDatalog/test.py

 USA
 
 """
+import cProfile
 import math
 import time
 
 import pyDatalog
 
-if __name__ == "__main__":
+def test():
 
     # instantiate a pyDatalog engine
     datalog_engine = pyDatalog.Datalog_engine()
     datalog_engine.load('+ p(a)')
     assert datalog_engine.ask('p(a)') == set([('a',)])
     
-    datalog_engine = None
-    
     # a decorator is used to create a program on the pyDatalog engine
     @pyDatalog.program()
     def _(): # the function name is ignored
         - p(b) # retract a unary fact
         assert ask(p(X)) == set([('a',)])
         
+    # a program can be entered piecemeal
+    @pyDatalog.program(datalog_engine)
+    def _(): # the function name is ignored
+        # spaces and uppercase in strings
+        + farmer('Moshe dayan')
+        + farmer('omar')
+        assert ask(farmer(X)) == set([('Moshe dayan',), ('omar',)])
+
+    # execute queries in a python program
+    moshe_is_a_farmer = datalog_engine.ask("farmer('Moshe dayan')")
+    assert moshe_is_a_farmer == set([('Moshe dayan',)])
+
+    @pyDatalog.program()
+    def _(): # the function name is ignored
         # strings and integers
         + p('c')
         assert ask(p(c)) == set([('c',)])
 
         # integer
         + integer(1)
-        print(ask(integer(1)))
         assert ask(integer(1)) == set([(1,)])
         
         # integer variable
         # s <= (X == Y)   
         # assert ask(s(X,Y)) == set([('a', 'a'),('c', 'c'),('1', '1')])
 
-    pyDatalog.ask('p(a)') == set([('a',)])
+    assert pyDatalog.ask('p(a)') == set([('a',)])
     
     # reset the engine
     datalog_engine = pyDatalog.Datalog_engine()
         assert ask(even(5)) == None
         #assert ask(odd(1099)) == set([(1099,)])
         
-    # a program can be entered piecemeal
+    """ TODO up-scope variables should be recognized, even if not global
+    _parents = (('edward', 'albert'), ('edward', 'victoria'))
     @pyDatalog.program(datalog_engine)
     def _(): # the function name is ignored
-        # performance
-        for _i in range(2000):
-            + successor(_i+1, _i)
-        assert ask(successor(1801,1800)) == set([(1801, 1800)])
-        #assert ask(successor(99001,99000)) == set([('99001', '99000')])
-        assert ask(odd(299)) == set([(299,)]) 
-        #assert ask(odd(999)) == set([('999',)]) 
-        # assert ask(odd(1999), _fast=False) == set([(1999,)])
-        
-        # TODO why is this much much slower ??
-        # odd(N) <= even(N1) & successor(N, N1)
-
-    # populate facts from python variables
-    _farmers = ('Moshe dayan', 'omar')
-    @pyDatalog.program(datalog_engine)
-    def _(): # the function name is ignored
-        # unary plus defines a fact
-        for _farmer in _farmers:
-            + farmer(_farmer)
-        assert ask(farmer(X)) == set([('Moshe dayan',), ('omar',)])
-
-    # execute queries in a python program
-    moshe_is_a_farmer = datalog_engine.ask("farmer('Moshe dayan')")
-    assert moshe_is_a_farmer == set([('Moshe dayan',)])
+        for _parent in _parents:
+            + parent(_parent[0], unicode(_parent[1]))       
+    
+    """
 
     # can't call a pyDatalog program
     error = False
     def _(): # the function name is ignored
         + parent(bill,mary)
         + parent(mary,john) 
-    print(datalog_engine.ask('parent(X,john)'))
     @pyDatalog.program(datalog_engine)
     def _(): # the function name is ignored
         ancestor(X,Y) <=  parent(X,Y)
         ancestor(X,Y) <= parent(X,Z) & ancestor(Z,Y)
     print(datalog_engine.ask('ancestor(bill,X)'))
     
-    _parents = (('edward', 'albert'), ('edward', 'victoria'))
-    
-    @pyDatalog.program(datalog_engine)
-    def _(): # the function name is ignored
-        for _parent in _parents:
-            + parent(_parent[0], unicode(_parent[1]))       
-    
     # Factorial
     datalog_engine = pyDatalog.Datalog_engine()
     @pyDatalog.program(datalog_engine)
         assert ask(fibonacci(4, F)) == set([(4, 3)])
         assert ask(fibonacci(18, F)) == set([(18, 2584)])
     
+    @pyDatalog.program()
+    def _(): # the function name is ignored
+        # performance
+        for _i in range(2000):
+            + successor(_i+1, _i)
+        assert ask(successor(1801,1800)) == set([(1801, 1800)])
+        #assert ask(successor(99001,99000)) == set([('99001', '99000')])
+        assert ask(odd(299)) == set([(299,)]) 
+        #assert ask(odd(999)) == set([('999',)]) 
+        # assert ask(odd(1999), _fast=False) == set([(1999,)])
+        
+        # TODO why is this much much slower ??
+        # odd(N) <= even(N1) & successor(N, N1)
+
     print("Done.")
+
+if __name__ == "__main__":    
+    cProfile.runctx('test()', globals(), locals())