前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >pyDatalog: python的逻辑编程引擎【二:基础教程(上)】

pyDatalog: python的逻辑编程引擎【二:基础教程(上)】

作者头像
blmoistawinde
发布2019-10-30 19:09:22
1.3K0
发布2019-10-30 19:09:22
举报

变量和表达式

第一步是导入pyDatalog: 下一步是声明我们将使用的变量。他们必须以大写字母开头: 变量出现在逻辑查询中,返回可打印的结果

In [1]:

代码语言:javascript
复制
from pyDatalog import pyDatalog
pyDatalog.create_terms('X,Y')
# give me all the X so that X is 1
print(X==1)
代码语言:javascript
复制
X
-
1

查询可以包含多个变量和几个条件('&'表示and关系):

In [2]:

代码语言:javascript
复制
# give me all the X and Y so that X is True and Y is False
print((X==True) & (Y==False))
代码语言:javascript
复制
X    | Y    
-----|------
True | False

有些查询返回空结果:

In [3]:

代码语言:javascript
复制
# give me all the X that are both True and False
print((X==True) & (X==False))
代码语言:javascript
复制
[]

除了数字和布尔值之外,变量可以表示字符串(如'Hello')。此外,查询可以包含python表达式(如加法):

In [4]:

代码语言:javascript
复制
# give me all the X and Y so that X is a name and Y is 'Hello ' followed by the first letter of X
# python2请使用raw_input
print((X==input('Please enter your name : ')) & (Y=='Hello ' + X[0]))
代码语言:javascript
复制
Please enter your name : World
X     | Y      
------|--------
World | Hello W

在第二个等式中,X被称为受第一个等式的约束,也就是说要在第一个等式给X一个值,才使得第二个等式中关于X的表达式(Y)有可能被估值。

pyDatalog没有符号解析器(目前)!如果表达式中的变量未被绑定,则查询返回一个空list:

In [5]:

代码语言:javascript
复制
# give me all the X and Y so that Y is 1 and Y is X+1
print((Y==1) & (Y==X+1))
代码语言:javascript
复制
[]

变量也可以表示(嵌套的)元组,它们可以参与表达式并被切片(0为基)。

In [6]:

代码语言:javascript
复制
print((X==(1,2)+(3,)) & (Y==X[2]))
代码语言:javascript
复制
X         | Y
----------|--
(1, 2, 3) | 3

要在逻辑表达式中使用自己的函数,请在Python中定义它们,然后在pyDatalog为它们创建逻辑术语:

In [7]:

代码语言:javascript
复制
def twice(a):
    return a+a

pyDatalog.create_terms('twice')
print((X==1) & (Y==twice(X)))
代码语言:javascript
复制
X | Y
--|--
1 | 2

同样,pyDatalog变量可以传递给Python标准库中的函数:

In [8]:

代码语言:javascript
复制
# give me all the X and Y so that X is 2 and Y is the square root of X
import math
pyDatalog.create_terms('math')
print((X==2) & (Y==math.sqrt(X)))
代码语言:javascript
复制
X | Y                 
--|-------------------
2 | 1.4142135623730951

循环

循环可以通过使用.in_() 方法创建 (我们将在以后看到还有其他方法可以创建循环): 【注:这里没有使用==,但同样执行了一次查询,查询的结果存在X中】

In [9]:

代码语言:javascript
复制
pyDatalog.create_terms('X,Y,Z')
# give me all the X so that X is in the range 0..4
print(X.in_((0,1,2,3,4)))

# python中的等效语句
# for x in range(5):
#     print(x)
代码语言:javascript
复制
X
-
4
3
2
1
0

查询的结果是一组可能的解决方案【行】,以随机顺序排列。每个解决方案对查询中的每个变量【列】都有一个值。用.data 属性可以访问结果。

In [10]:

代码语言:javascript
复制
print(X.in_(range(5)).data)
print(X.in_(range(5)) == set([(0,), (1,), (2,), (3,), (4,)]))
代码语言:javascript
复制
[(4,), (3,), (2,), (1,), (0,)]
True

同样,在查询之后,变量包含所有可能值的元组。它们可以用这些方法访问:

In [11]:

代码语言:javascript
复制
print("Data : ",X.data)
print("First value : ",  X.v())
# below, '>=' is a variable extraction operator
print("Extraction of first value of X: ", X.in_(range(5)) >= X)
代码语言:javascript
复制
Data :  [4, 3, 2, 1, 0]
First value :  4
Extraction of first value of X:  4

'&'运算符可用于过滤结果。

In [12]:

代码语言:javascript
复制
# give me all X in range 0..4 that are below 2
print(X.in_(range(5)) & (X<2))
代码语言:javascript
复制
X
-
1
0

循环可以很容易地嵌套。使用缩进可以提高可读性:

In [13]:

代码语言:javascript
复制
# give me all X, Y and Z so that X and Y are in 0..4, Z is their sum, and Z is below 3
print(X.in_(range(5)) &
          Y.in_(range(5)) &
              (Z==X+Y) &
              (Z<3))
代码语言:javascript
复制
X | Y | Z
--|---|--
2 | 0 | 2
1 | 1 | 2
1 | 0 | 1
0 | 2 | 2
0 | 1 | 1
0 | 0 | 0

逻辑函数与字典

作为例子,我们将计算员工foo和bar的净工资。

In [14]:

代码语言:javascript
复制
pyDatalog.create_terms('X,Y,Z, salary, tax_rate, tax_rate_for_salary_above, net_salary')
salary['foo'] = 60
salary['bar'] = 110

# Python equivalent【只是作为展示, 实际上_salary 并没有被 define】
# _salary = dict()
# _salary['foo'] = 60
# _salary['bar'] = 110

# give me all the X and Y so that the salary of X is Y
print(salary[X]==Y)
print({X.data[i]:Y.data[i] for i in range(len(X.data))})        #【真正转化为字典的写法】
# python equivalent
# print(_salary.items())
代码语言:javascript
复制
X   | Y  
----|----
bar | 110
foo | 60 
{'bar': 110, 'foo': 60}

请注意,逻辑函数名称(例如 salary),以小写字母开头。 函数为给定参数定义一个值。它类似于Python字典。

一个函数可以用值查询。 一个函数对同一个参数只能有一个值。【后来值会覆盖旧值】

In [15]:

代码语言:javascript
复制
# foo now has a salary of 70
salary['foo'] = 70
print(salary['foo']==Y)
代码语言:javascript
复制
Y 
--
70

一个函数也可以用键查询。

In [16]:

代码语言:javascript
复制
# give me all the X that have a salary of 110
print(salary[X]==110)
# procedural equivalent in python
# for i, j in _salary.items():
#     if j==110:
#         print i, '-->', j
#  Notice that there is a implicit loop in the query.
代码语言:javascript
复制
X  
---
bar

注意查询中有一个隐式循环。【因此这种查询效率比较低】

查询可以测试一个标准的否定。

In [17]:

代码语言:javascript
复制
# A query can test the negation of a criteria.
print((salary[X]==Y) & ~(Y==110))
代码语言:javascript
复制
X   | Y 
----|---
foo | 70

现在让我们定义一个全球税率。我们将使用 None 函数参数:

In [18]:

代码语言:javascript
复制
# Let's now define a global tax rate. We'll use None for the function argument:
# the standard tax rate is 33%
+(tax_rate[None]==0.33)

# 一个函数可以在公式中调用:
# give me the net salary for all X
print((Z==salary[X]*(1-tax_rate[None])))
代码语言:javascript
复制
X   | Z                
----|------------------
bar | 73.69999999999999
foo | 46.89999999999999

在这种情况下,X受到salary[X]的约束,因此可以评估表达式。

一个函数也可以由一个子句定义。这是一个简单的例子:

In [19]:

代码语言:javascript
复制
# the net salary of X is Y if Y is the salary of X, reduced by the tax rate
net_salary[X] = salary[X]*(1-tax_rate[None])

# give me all the X and Y so that Y is the net salary of X
print(net_salary[X]==Y)
代码语言:javascript
复制
X   | Y                
----|------------------
bar | 73.69999999999999
foo | 46.89999999999999

In [20]:

代码语言:javascript
复制
# give me the net salary of foo
print(net_salary['foo']==Y)
print(net_salary[X]<50)
代码语言:javascript
复制
Y                
-----------------
46.89999999999999
X  
---
foo

现在让我们来定义一个累进税制:默认税率是33%,但是100%以上的工资是50%。

In [21]:

代码语言:javascript
复制
# Let's now define a progressive tax system: the tax rate is 33 % by default, but 50% for salaries above 100.
(tax_rate_for_salary_above[X] == 0.33) <= (0 <= X)
(tax_rate_for_salary_above[X] == 0.50) <= (100 <= X)
print(tax_rate_for_salary_above[70]==Y)
print(tax_rate_for_salary_above[150]==Y)
代码语言:javascript
复制
Y   
----
0.33
Y  
---
0.5

这里第一次出现了“推理”

"<="是上述陈述中的重要标志:它被读作'if'。【可以用来定义“推出”的规则】

首先给出函数的最一般定义。当搜索可能的答案时,pyDatalog从最后定义的规则开始,即更具体的规则,只要找到该函数的有效答案就立即停止。所以,尽管这两条规则似乎都适用于150的薪水,但实际上我们是按照第二条规则得到了50%的税率。

接下来让我们重新定义净工资。在此之前,我们要删除原始定义:

In [22]:

代码语言:javascript
复制
# retract our previous definition of net_salary
del net_salary[X]
# new definition
net_salary[X] = salary[X]*(1-tax_rate_for_salary_above[salary[X]])
# give me all X and Y so that Y is the net salary of X
print(net_salary[X]==Y)
# Please note that we used f[X]=<expr> above, as a shorter notation for (f[X]==Y) <= (Y==expr)

# This short notation, together with the fact that functions can be defined in any order,
# makes writing a pyDatalog program as easy as creating a spreadsheet.
代码语言:javascript
复制
X   | Y                
----|------------------
bar | 55.0             
foo | 46.89999999999999

请注意,我们在上面使用的f[X]=,是(f[X]==Y) <= (Y==expr)的简写。

这个简短的表示法以及可以按任意顺序定义函数的事实,使得编写pyDatalog程序像创建电子表格一样简单。

为了说明这一点,看看这个不能更清晰的Factorial的定义!

In [23]:

代码语言:javascript
复制
# To illustrate the point, this definition of Factorial cannot be any clearer !
pyDatalog.create_terms('N, factorial')
factorial[N] = N*factorial[N-1]
factorial[1] = 1

print(factorial[3]==N)
代码语言:javascript
复制
N
-
6
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-06-30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 变量和表达式
  • 循环
  • 逻辑函数与字典
  • 这里第一次出现了“推理”
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档