Python中的逻辑编程

3

我正在从事一个主要基于逻辑编程的项目。我预定义了相关规则和事实,程序使用这些规则和事实来计算概率,然后将这些概率附加到数据中,并馈入进一步的机器学习模型。例如,可以在prolog中轻松定义计算概率的程序如下:

has_lot_work(daniel, 8). %number of lets say urgent tasks
has_lot_work(david, 3).
stress(X, P) :- has_lot_work(X, P2), P is P2 / 100.
to_smoke(X, Prob) :- stress(X, P1), friends(Y, X), influences(Y, X, P2), smokes(Y), Prob is P1 + P2.
to_have_asthma(X, 0.3) :- smokes(X). %30 percent of current smokers get asthma
to_have_asthma(X, Prob) :- to_smoke(X, P2), Prob is P2 * 0.25. %25 percent of smokers-to-be will get asthma
friends(X, Y) :- friend(X, Y).
friends(X, Y) :- friend(Y, X).
influences(X, Y, 0.4) :- friends(X, Y). %friends influence each other by 40 percent
friend(peter, david).
friend(peter, rebecca).
friend(daniel, rebecca).
smokes(peter).
smokes(rebecca).

在这个例子中,我对计算某人吸烟的概率(to_smoke(Who, Prob))和患哮喘的概率(to_have_asthma(Who, Prob))感兴趣。我使用Python来获取和清理数据,并用于之后的ML模型,因此我希望也能在Python中应用这种逻辑。但是我找不到一种方法来进行这种逻辑计算,也找不到一种合适的方法来连接Python与Prolog,避免出现错误和问题。


2
请简要解释一下。很难理解你的问题。给一些例子以便更好地理解... - undefined
Pyke是一个示例模块。 - undefined
5个回答

6
我尝试开发一个使用Prolog语法、方法和回溯的Python解决方案。我编写了pytholog库,这里是GitHub链接。 我分享这些答案是为了获得反馈意见,以寻求更好的解决方案。在pytholog中,我初始化了一个知识库,并进行了查询。
import pytholog as pl
friends_kb = pl.KnowledgeBase("friends")
friends_kb([
    "has_lot_work(daniel, 8)",
    "has_lot_work(david, 3)",
    "stress(X, P) :- has_lot_work(X, P2), P is P2 / 100",
    "to_smoke(X, Prob) :- stress(X, P1), friends(Y, X), influences(Y, X, P2), smokes(Y), Prob is P1 + P2",
    "to_have_asthma(X, 0.3) :- smokes(X)",
    "to_have_asthma(X, Prob) :- to_smoke(X, P2), Prob is P2 * 0.25",
    "friends(X, Y) :- friend(X, Y)",
    "friends(X, Y) :- friend(Y, X)",
    "influences(X, Y, 0.4) :- friends(X, Y)",
    "friend(peter, david)",
    "friend(peter, rebecca)",
    "friend(daniel, rebecca)",
    "smokes(peter)",
    "smokes(rebecca)"
])
print(friends_kb.query(pl.Expr("to_smoke(Who, P)")))
# [{'Who': 'daniel', 'P': 0.48000000000000004}, {'Who': 'david', 'P': 0.43000000000000005}]
print(friends_kb.query(pl.Expr("to_have_asthma(Who, P)")))
# [{'Who': 'peter', 'P': '0.3'}, {'Who': 'rebecca', 'P': '0.3'}, {'Who': 'daniel', 'P': 0.12000000000000001}, {'Who': 'david', 'P': 0.10750000000000001}]

5
你有几种选择,但据我所知Python没有内置的方法或谓词,因此您需要将其作为库来访问。
  1. 一种流行的方法是使用 miniKanren。我没有使用过这个,但只看它的语法就足以让我惊恐地逃开。
  2. 另一种方法是找到Python和Prolog之间的接口,其中一种流行的接口是Python和SWI-Prolog之间的接口,例如pyswip。有很多这样的接口,因此您必须寻找并检查哪一个最适合您的需求。同样,我也没有使用过这些。
如果您选择使用连接到SWI-Prolog的库,请注意SWI-Prolog论坛中不时会出现这些问题
我会选择这种方式,因为您可以访问具有剪枝、回溯、表格等完整功能的Prolog。
  1. 一种更加困难的方法,但是能够提供最深入的见解,就是自己用Python实现逻辑。参见:在Python中实现Prolog Unification算法?回溯

你不喜欢括号,伙计?>:-) 你看过《The Reasoned Schemer》这本书吗?链接 - undefined

4

看看z3定理证明器,它也有Python绑定。这里是指南

你可以像这样在z3中表达你的问题:

import z3


def main():
    person = z3.Datatype("Person")
    for p in ["daniel", "david", "peter", "rebecca"]:
        person.declare(p)

    person = person.create()
    p1, p2 = z3.Const("p1", person), z3.Const("p2", person)
    s = z3.Solver()

    has_lot_work = z3.Function("has_lot_work", person, z3.RealSort())
    s.add(has_lot_work(person.daniel) == 8)
    s.add(has_lot_work(person.david) == 3)

    friends = z3.Function("friends", person, person, z3.BoolSort())
    friend = z3.Function("friend", person, person, z3.BoolSort())
    s.add(
        z3.ForAll(
            [p1, p2], z3.Implies(z3.Or(friend(p1, p2), friend(p2, p1)), friends(p1, p2))
        )
    )
    s.add(friend(person.peter, person.david))
    s.add(friend(person.peter, person.rebecca))
    s.add(friend(person.daniel, person.rebecca))

    smokes = z3.Function("smokes", person, z3.BoolSort())
    s.add(smokes(person.peter))
    s.add(smokes(person.rebecca))
    s.add(z3.Not(smokes(person.david)))
    s.add(z3.Not(smokes(person.daniel)))

    stress = z3.Function("stress", person, z3.RealSort())
    s.add(z3.ForAll(p1, stress(p1) == has_lot_work(p1) / 100.0))

    influences = z3.Function("influences", person, person, z3.RealSort())
    s.add(z3.ForAll([p1, p2], influences(p1, p2) == z3.If(friends(p1, p2), 0.4, 0.0)))

    to_smoke = z3.Function("to_smoke", person, z3.RealSort())
    s.add(
        z3.ForAll(
            [p1, p2],
            z3.Or(
                p1 == p2,
                z3.Not(smokes(p2)),
                z3.Not(friends(p2, p1)),
                to_smoke(p1) == stress(p1) + influences(p2, p1),
            ),
        )
    )

    to_have_asthma = z3.Function("to_have_asthma", person, z3.RealSort())
    s.add(
        z3.ForAll(
            p1,
            to_have_asthma(p1)
            == z3.If(
                smokes(p1),
                0.3,
                to_smoke(p1) * 0.25,
            ),
        )
    )

    s.check()
    model = s.model()
    result = {
        p: float(model.eval(to_have_asthma(p)).as_fraction())
        for p in [person.peter, person.daniel, person.david, person.rebecca]
    }
    print(result)


if __name__ == "__main__":
    main()

输出:

{peter: 0.3, daniel: 0.12, david: 0.1075, rebecca: 0.3}

虽然这个链接可能回答了问题,但最好在这里包含答案的关键部分,并提供链接作为参考。仅有链接的答案如果链接页面发生变化可能会失效。 - undefined

2

-1

有一个Python版本的Dogelog运行时。它可以打包成单个Python文件,无需服务器往返,只需在一个Python文件中使用ISO核心Prolog,需要Python 3.10。

Python版本还具有外部函数接口。但最简单的方法是将知识库放入Prolog文本文件中,进行咨询和查询:

>python.exe toplevel.py
Dogelog Runtime, Prolog to the Moon, 0.9.3
(c) 1985-2021, XLOG Technologies AG, Switzerland
?- ['prob.pl'].
true.
?- to_have_asthma(X, Y).
X = peter, Y = 0.3;
X = rebecca, Y = 0.3;
X = daniel, Y = 0.12000000000000001;
X = david, Y = 0.10750000000000001;
fail.

Dogelog运行时是开源的,可以在GitHub上找到。 使用Python版本的参与式查询答案者是一种使用方式, 也是控制台教程的一部分。

Doglog运行时:Python控制台示例
https://github.com/jburse/dogelog-moon/tree/main/samples/console

示例作为Prolog文本的原样
https://gist.github.com/jburse/00d14dee1582a131a52bdddf1ffb9dcb#file-prob-pl


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接