Commits

Pierre Carbonnelle committed ad21fb1

use OrderedDict instead of OrderedSet for pred.clauses. Key should be improved though.

Comments (0)

Files changed (3)

pyDatalog/examples/test.py

         assert ask(r(a, c)) == set([()])
         r(X, b) <= p(X)
         assert ask(r(a, b)) == set([()])
+        #TODO r(Y, b) <= p(Y)
         
         - (r(X, b) <= p(X))
         assert ask(r(a, b)) == None
         assert (ask(plus[plus[1,2]+1, 2+plus[2,3]] <  plus[1, plus[2,5]])) == None
 
         (discount[Total] == 100) <= (1000 < Total)
-        (discount[Total] == 10) <= (100 < Total)
+        (discount[Total] == 10)  <= (100  < Total)
+        (discount[Total] == 1)  <=  (10   < Total)
         assert (ask(discount[2000]==Y) == set([(100,)])) 
+        assert (ask(discount[200]==Y) == set([(10,)])) 
                 
     @pyDatalog.program()
     def function_comparison(): 

pyDatalog/pyEngine.py

 * lua variables are global by default, python ones are local by default
 * variable bindings in a closure.  See http://tiny.cc/7837cw, http://tiny.cc/rq47cw
 """
-from collections import deque
+from collections import deque, OrderedDict
 from decimal import Decimal
 import gc
 from itertools import groupby
             o.comparison = words[1] if 1 < len(words) else '' # for f[X]<Y
 
             o.db = {}
-            o.clauses = util.OrderedSet([]) #TODO just use a list. (retract clause is rare)
+            o.clauses = OrderedDict()
             # one index per term. An index is a dictionary of sets
             o.index = [{} for i in range(int(o.arity))]
             o.prim = None
     
     def reset_clauses(self):
         """ clears the database of clauses for the predicate """
-        for clause in list(self.clauses):
+        for clause in self.clauses.values():
             retract(clause)
     
     def __str__(self): 
 def assert_(clause):
     """ Add a safe clause to the database """
     pred = clause.head.pred
+    id_ = get_clause_id(clause)
+
     if not pred.prim:                   # Ignore assertions for primitives.
-        if pred.aggregate and get_clause_id(clause) in pred.db:
+        if pred.aggregate and id_ in pred.db:
             raise util.DatalogError("Error: Duplicate definition of aggregate function.", None, None)
         retract(clause) # to ensure unicity of functions
-        pred.db[get_clause_id(clause)] = clause
+        pred.db[id_] = clause
         if not clause.body: # if it is a fact, update indexes
             for i, term in enumerate(clause.head.terms):
                 clauses = pred.index[i].setdefault(term, set([])) # create a set if needed
                 clauses.add(clause)
         else:
-            pred.clauses.add(clause)
+            pred.clauses[id_] = clause
         insert(pred)
     return clause
 
                 pred.index[i][term].remove(clause)
                 # TODO del pred.index[i][term] if the set is empty
         else:
-            pred.clauses.remove(pred.db[id_])
+            del pred.clauses[id_]
         del pred.db[id_]  # remove clause from pred.db
     """ TODO retract last fact removes pred ??  problem with assert function
     if len(pred.db) == 0 and pred.prim == None: # if no definition left
         return list(literal.pred.db.values())
     else:
         #result= [ literal.pred.db[id_] for id_ in result ] + [ literal.pred.db[id_] for id_ in literal.pred.clauses]
-        return list(result) + list(literal.pred.clauses)
+        return list(result) + list(literal.pred.clauses.values())
     
 """
 The remaining functions in this file implement the tabled logic
         self.i += 1
         return self.i
 
-class OrderedSet(collections.MutableSet):
-
-    def __init__(self, iterable=None):
-        self.end = end = [] 
-        end += [None, end, end]         # sentinel node for doubly linked list
-        self.map = {}                   # key --> [key, prev, next]
-        if iterable is not None:
-            self |= iterable
-
-    def __len__(self):
-        return len(self.map)
-
-    def __contains__(self, key):
-        return key in self.map
-
-    def add(self, key):
-        if key not in self.map:
-            end = self.end
-            curr = end[1]
-            curr[2] = end[1] = self.map[key] = [key, curr, end]
-
-    def discard(self, key):
-        if key in self.map:        
-            key, prev, next = self.map.pop(key)
-            prev[2] = next
-            next[1] = prev
-
-    def __iter__(self):
-        end = self.end
-        curr = end[2]
-        while curr is not end:
-            yield curr[0]
-            curr = curr[2]
-
-    def __reversed__(self):
-        end = self.end
-        curr = end[1]
-        while curr is not end:
-            yield curr[0]
-            curr = curr[1]
-
-    def pop(self, last=True):
-        if not self:
-            raise KeyError('set is empty')
-        key = self.end[1][0] if last else self.end[2][0]
-        self.discard(key)
-        return key
-
-    def __repr__(self):
-        if not self:
-            return '%s()' % (self.__class__.__name__,)
-        return '%s(%r)' % (self.__class__.__name__, list(self))
-
-    def __eq__(self, other):
-        if isinstance(other, OrderedSet):
-            return len(self) == len(other) and list(self) == list(other)
-        return set(self) == set(other)