python逻辑编程之kanren

https://github.com/logpy/logpy

https://pypi.org/project/kanren/

 https://www.yiibai.com/ai_with_python/ai_with_python_logic_programming.html

kanren

python逻辑编程

示例:

KANEN是关系的表达式和满足他们的价值的搜索。下列代码就是逻辑编程的"Hello, world!" ,最简单的示例。他请求一个数 x,如x ==5

>>> from kanren import run, eq, membero, var, conde
>>> x = var()
>>> run(1, x, eq(x, 5))
(5,)

多个变量和多个目标可以同时使用。下列代码请求一个数x,如 x==z,同时z==3

>>> z = var()
>>> run(1, x, eq(x, z),
              eq(z, 3))
(3,)

KANN使用统一模式匹配的高级形式来匹配表达式树。下列代码请求一个数 X,如(1, 2)=(1,x)。

>>> run(1, x, eq((1, 2), (1, x)))
(2,)
 

前面的例子中使用的 eq,表述的是两个表达式相等。membero(item, coll) 表示 item  是 coll集合中的一个成员。下面例子使用 两次 membero去请求 x 的2个值,

>>> run(2, x, membero(x, (1, 2, 3)),  # x is a member of (1, 2, 3) #x是(1,2,3)的成员之一
              membero(x, (2, 3, 4)))  # x is a member of (2, 3, 4) #x是(2,3,4)的成员之一   
#2 表示求两个解,则,变量x,可能的解为 (2,3)
(2, 3)

 

逻辑变量

下面例子中,z = var() 创建一个逻辑变量.  您还可以选择为变量命名,以方便后面调试:

>>> z = var('test')
>>> z
~test

也可以用  vars() 带一个整形参数一次创建一组逻辑变量:

>>> a, b, c = vars(3)
>>> a
~_1
>>> b
~_2
>>> c
~_3

 

Representing Knowledge

知识表达

kanren存储两个条件之间的状态关系的数据。

kanren stores data as facts that state relationships between terms.、

下面代码创建一个亲缘关系,并且使用它来判断谁是 Simpsons家庭的父亲。

The following code creates a parent relationship and uses it to state facts about who is a parent of whom within the Simpsons family.

>>> from kanren import Relation, facts
>>> parent = Relation()
>>> facts(parent, ("Homer", "Bart"),
...               ("Homer", "Lisa"),
...               ("Abe",  "Homer"))

>>> run(1, x, parent(x, "Bart"))
('Homer',)

>>> run(2, x, parent("Homer", x))
('Lisa', 'Bart')

我们可以使用中间变量来进行更复杂的查询。Bart的祖父是谁?

We can use intermediate variables for more complex queries. Who is Bart's grandfather?

>>> y = var()
>>> run(1, x, parent(x, y),
              parent(y, 'Bart'))
('Abe',)

 

 

我们可以分别表达祖父关系。在这个例子中,我们使用CONDE,一个用于逻辑和/或OR的目标构造函数。

We can express the grandfather relationship separately. In this example we use conde, a goal constructor for logical and and or.

>>> def grandparent(x, z):
...     y = var()
...     return conde((parent(x, y), parent(y, z)))

>>> run(1, x, grandparent(x, 'Bart'))
('Abe,')

 

数据结构

kanren 依赖 functions, tuples, dicts, and generators. 可以很容易融入以往的代码。

Extending kanren to other Types

kanren uses Multiple Dispatch and the unification library to support pattern matching on user defined types. Also see unification (wikipedia). Types which can be unified can be used for logic programming. See the project examples for how to extend the collection of unifiable types to your use case.

Install

With pip or easy_install

pip install kanren

From source

git clone git@github.com:logpy/logpy.git
cd logpy
python setup.py install

Run tests with tox

tox

支持

kanren supports Python 2.7+ and Python 3.3+ with a common codebase. It is pure Python and requires no dependencies beyond the standard library, toolzmultipledispatch, and unification.

简而言之,它是一种轻量级的依赖。

作者

Matthew Rocklin

License

New BSD license. See LICENSE.txt

Motivation

Logic programming is a general programming paradigm. This implementation however came about specifically to serve as an algorithmic core for Computer Algebra Systems in Python and for the automated generation and optimization of numeric software. Domain specific languages, code generation, and compilers have recently been a hot topic in the Scientific Python community. kanren aims to be a low-level core for these projects.

References

如果涉及到某些函数不会用,不知道做啥用的,直接下载源代码,查看里面的各个文件,都有详细的解释。

解决难题

逻辑编程可用于解决许多问题,如8拼图,斑马拼图,数独,N皇后等。在这里,举例说明斑马拼图的变体如下 -

有五间房子。
英国人住在红房子里。
瑞典人有一只狗。
丹麦人喝茶。
绿房子在白房子的左边。
他们在绿房子里喝咖啡。
吸Pall Mall的人有鸟。
吸Dunhill在的人黄色房子里。
在中间的房子里,他们喝牛奶。
挪威人住在第一宫。
那个抽Blend的男人住在猫屋旁边的房子里。
在他们有一匹马的房子旁边的房子里,他们吸Dunhill烟。
抽Blue Master的人喝啤酒。
德国人吸Prince烟。
挪威人住在蓝房子旁边。
他们在房子旁边的房子里喝水,在那里吸Blend烟。
Text

在Python的帮助下解决谁有斑马的问题。
导入必要的软件包 -

from kanren import *
from kanren.core import lall
import time

 

Python

现在,我们需要定义两个函数 - left()next()来查找哪个房屋左边或接近谁的房子 -

def left(q, p, list):
   return membero((q,p), zip(list, list[1:]))
def next(q, p, list):
   return conde([left(q, p, list)], [left(p, q, list)])

 

Python

现在,声明一个变量:houses,如下 -

houses = var()

 

Python

需要在lall包的帮助下定义规则如下。

5间房子 -

rules_zebraproblem = lall(
   (eq, (var(), var(), var(), var(), var()), houses),     #5个var()分别代表 人、烟、饮料、动物、屋子颜色

   (membero,('Englishman', var(), var(), var(), 'red'), houses),
   (membero,('Swede', var(), var(), 'dog', var()), houses),
   (membero,('Dane', var(), 'tea', var(), var()), houses),
   (left,(var(), var(), var(), var(), 'green'),
   (var(), var(), var(), var(), 'white'), houses),
   (membero,(var(), var(), 'coffee', var(), 'green'), houses),
   (membero,(var(), 'Pall Mall', var(), 'birds', var()), houses),
   (membero,(var(), 'Dunhill', var(), var(), 'yellow'), houses),
   (eq,(var(), var(), (var(), var(), 'milk', var(), var()), var(), var()), houses),
   (eq,(('Norwegian', var(), var(), var(), var()), var(), var(), var(), var()), houses),
   (next,(var(), 'Blend', var(), var(), var()),
   (var(), var(), var(), 'cats', var()), houses),
   (next,(var(), 'Dunhill', var(), var(), var()),
   (var(), var(), var(), 'horse', var()), houses),
   (membero,(var(), 'Blue Master', 'beer', var(), var()), houses),
   (membero,('German', 'Prince', var(), var(), var()), houses),
   (next,('Norwegian', var(), var(), var(), var()),
   (var(), var(), var(), var(), 'blue'), houses),
   (next,(var(), 'Blend', var(), var(), var()),
   (var(), var(), 'water', var(), var()), houses),
   (membero,(var(), var(), var(), 'zebra', var()), houses)
)

 

Python

现在,用前面的约束运行解算器 -

solutions = run(0, houses, rules_zebraproblem)

 

Python

借助以下代码,可以提取解算器的输出 -

output_zebra = [house for house in solutions[0] if 'zebra' in house][0][0]
Python

以下代码将打印解决方案 -

print ('\n'+ output_zebra + 'owns zebra.')
Python

上述代码的输出如下 -

German owns zebra.


posted on 2018-08-24 19:24  耀扬  阅读(8366)  评论(0编辑  收藏  举报

导航