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, toolz
, multipledispatch
, and unification
.
简而言之,它是一种轻量级的依赖。
作者
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
- Logic Programming on wikipedia
- miniKanren, a Scheme library for relational programming on which this library is based. More information can be found in the thesis of William Byrd.
- core.logic a popular implementation of miniKanren in Clojure.
如果涉及到某些函数不会用,不知道做啥用的,直接下载源代码,查看里面的各个文件,都有详细的解释。
解决难题
逻辑编程可用于解决许多问题,如8拼图,斑马拼图,数独,N皇后等。在这里,举例说明斑马拼图的变体如下 -
有五间房子。
英国人住在红房子里。
瑞典人有一只狗。
丹麦人喝茶。
绿房子在白房子的左边。
他们在绿房子里喝咖啡。
吸Pall Mall的人有鸟。
吸Dunhill在的人黄色房子里。
在中间的房子里,他们喝牛奶。
挪威人住在第一宫。
那个抽Blend的男人住在猫屋旁边的房子里。
在他们有一匹马的房子旁边的房子里,他们吸Dunhill烟。
抽Blue Master的人喝啤酒。
德国人吸Prince烟。
挪威人住在蓝房子旁边。
他们在房子旁边的房子里喝水,在那里吸Blend烟。
在Python的帮助下解决谁有斑马的问题。
导入必要的软件包 -
from kanren import * from kanren.core import lall import time
现在,我们需要定义两个函数 - 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)])
现在,声明一个变量:houses
,如下 -
houses = var()
需要在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) )
现在,用前面的约束运行解算器 -
solutions = run(0, houses, rules_zebraproblem)
借助以下代码,可以提取解算器的输出 -
output_zebra = [house for house in solutions[0] if 'zebra' in house][0][0]
以下代码将打印解决方案 -
print ('\n'+ output_zebra + 'owns zebra.')
上述代码的输出如下 -
German owns zebra.