2013-03-04 3 views
1

Я пишу программу pyDatalog для анализа метеорологических данных из Weather Underground (как демонстрация для себя и других в компании в данный момент). Я написал пользовательский предикат распознаватель, который возвращает показания между начальным и конечным временем:pyDatalog: обработка несвязанных переменных в пользовательском предикате

# class for the reading table. 
class Reading(Base): 
     __table__ = Table('reading', Base.metadata, autoload = True, autoload_with = engine) 
     def __repr__(self): 
     return str(self.Time) 
     # predicate to resolve 'timeBetween(X, Y, Z)' statements 
     # matches items as X where the time of day is between Y and Z (inclusive). 
     # if Y is later than Z, it returns the items not between Z and Y (exclusive). 
     # TODO - make it work where t1 and t2 are not bound. 
     # somehow needs to tell the engine to try somewhere else first. 
     @classmethod 
     def _pyD_timeBetween3(cls, dt, t1, t2): 
     if dt.is_const(): 
      # dt is already known 
      if t1.is_const() and t2.is_const(): 
      if (dt.id.Time.time() >= makeTime(t1.id)) and (dt.id.Time.time() <= makeTime(t2.id)): 
       yield (dt.id, t1.id, t2.id) 
     else: 
      # dt is an unbound variable 
      if t1.is_const() and t2.is_const(): 
      if makeTime(t2.id) > makeTime(t1.id): 
       op = 'and' 
      else: 
       op = 'or' 
      sqlWhere = "time(Time) >= '%s' %s time(Time) <= '%s'" % (t1.id, op, t2.id) 
      for instance in cls.session.query(cls).filter(sqlWhere): 
       yield(instance, t1.id, t2.id) 

Это хорошо работает в том случае, если t1 и t2 связаны с конкретными значениями:

:> easterly(X) <= (Reading.WindDirection[X] == 'East') 
:> + rideAfter('11:00:00') 
:> + rideBefore('15:00:00') 
:> goodTime(X) <= rideAfter(Y) & rideBefore(Z) & Reading.timeBetween(X, Y, Z) 
:> goodTime(X) 
[(2013-02-19 11:25:00,), (2013-02-19 12:45:00,), (2013-02-19 12:50:00,), (2013-02-19 13:25:00,), (2013-02-19 14:30:00,), (2013-02-19 15:00:00,), (2013-02-19 13:35:00,), (2013-02-19 13:50:00,), (2013-02-19 12:20:00,), (2013-02-19 12:35:00,), (2013-02-19 14:05:00,), (2013-02-19 11:20:00,), (2013-02-19 11:50:00,), (2013-02-19 13:15:00,), (2013-02-19 14:55:00,), (2013-02-19 12:00:00,), (2013-02-19 13:00:00,), (2013-02-19 14:20:00,), (2013-02-19 14:15:00,), (2013-02-19 13:10:00,), (2013-02-19 12:10:00,), (2013-02-19 14:45:00,), (2013-02-19 14:35:00,), (2013-02-19 13:20:00,), (2013-02-19 11:10:00,), (2013-02-19 13:05:00,), (2013-02-19 12:55:00,), (2013-02-19 14:10:00,), (2013-02-19 13:45:00,), (2013-02-19 13:55:00,), (2013-02-19 11:05:00,), (2013-02-19 12:25:00,), (2013-02-19 14:00:00,), (2013-02-19 12:05:00,), (2013-02-19 12:40:00,), (2013-02-19 14:40:00,), (2013-02-19 11:00:00,), (2013-02-19 11:15:00,), (2013-02-19 11:30:00,), (2013-02-19 11:45:00,), (2013-02-19 13:40:00,), (2013-02-19 11:55:00,), (2013-02-19 14:25:00,), (2013-02-19 13:30:00,), (2013-02-19 12:30:00,), (2013-02-19 12:15:00,), (2013-02-19 11:40:00,), (2013-02-19 14:50:00,), (2013-02-19 11:35:00,)] 

Однако если я объявить правило Goodtime с условиями в другом порядке (то есть, где Y и Z являются несвязанными в точке он пытается решить timeBetween), она возвращает пустой набор:

:> atoms('niceTime') 
:> niceTime(X) <= Reading.timeBetween(X, Y, Z) & rideAfter(Y) & rideBefore(Z) 
<pyDatalog.pyEngine.Clause object at 0x0adfa510> 
:> niceTime(X) 
[] 

Это кажется неправильным - два запроса должны возвращать одинаковый набор результатов.

Вопрос в том, есть ли способ справиться с этой ситуацией в pyDatalog? Я думаю, что должно произойти то, что timeBetween предикат должен иметь возможность сказать движку как-то отступить и попытаться разрешить другие правила прежде, чем попробовать этот, но я не вижу никакой ссылки на это в документах.

ответ

0

В документе pyDatalog reference говорится: «хотя порядок инструкций pyDatalog безразличен, порядок литералов в теле значим» pyDatalog разрешает предикаты в теле в том порядке, в котором они указаны.

Сказав это, можно было бы улучшить pyDatalog, чтобы сначала разрешить предикаты со связанными переменными, но я не уверен, почему это было бы важно.

+0

Единственная причина для меня - сделать синтаксис более прозрачным и независимым от базового движка. Обычно «&» является транзитивным оператором, поэтому люди ожидают, что это произойдет с других языков. – highfellow

+0

Спасибо за отзыв. В какой-то момент я рассмотрел использование следующего синтаксиса для предложений: p (X) <= (q (X), r (X)) т. Е. Используя список литералов тела вместо &. Это имеет то преимущество, что не подразумевает коммутативность, но я считаю ее менее читаемой, чем «&». После вашей обратной связи, я могу добавить эту нотацию в какой-то момент. Обратите внимание, что 'и' не является действительно коммутативным в Python. если a является ложным, b не оценивается в 'a и b', поэтому 'a и b' могут иметь другой результат, чем 'b и a'. – user474491