【问题标题】:Logic programming in pythonpython中的逻辑编程
【发布时间】:2020-04-08 11:10:49
【问题描述】:

我正在从事一个主要基于逻辑编程的项目。我预先定义了程序用来计算概率的相关规则和事实,然后将这些概率附加到数据中并输入到进一步的机器学习模型中。计算概率的程序可以很容易地在 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 连接起来而不会出现错误和问题。

【问题讨论】:

标签: python prolog logic-programming


【解决方案1】:

我尝试开发一些在 python 中使用 prolog 的语法、方法和回溯来解决问题的东西。 我写了pytholog 库。 我正在分享获得 cmets 的答案以及是否有更好的方法。

在 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}]

【讨论】:

    【解决方案2】:

    您有几个选择,但作为 AFAIK,Python 没有内置方法或谓词,因此您需要将其作为库来访问。

    1. 一种流行的方式是使用miniKanren。这个我没用过,但光看它的语法就已经吓得我跑掉了。

    2. 另一种方法是在 Python 和 Prolog 之间找到一个接口,一种流行的方法是在 Python 和 SWI-Prolog 之间,例如 pyswip。其中有很多,因此您必须寻找并检查哪一种最适合您的需求。同样,我没有使用这些。

    如果您确实选择使用库连接到 SWI-Prolog,我知道那些questions 会不时在 SWI-Prolog 论坛上弹出。

    这是我会选择的,因为您可以访问具有剪切、回溯、制表等功能的全功能 Prolog。

    1. 一种更难但最有洞察力的方法是自己在 Python 中实现逻辑。见:Implementing the Prolog Unification algorithm in Python? Backtracking

    【讨论】:

    【解决方案3】:

    看看z3 theorem prover,它也有python绑定。这里是the guide

    您可以像这样在 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}
    

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效
    【解决方案4】:

    PyLog 似乎正是您要寻找的。 https://pypi.org/project/pylog/

    pip install pylog
    

    【讨论】:

      【解决方案5】:

      Dogelog 运行时有 Python 版本。它可以 装入单个 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

      【讨论】:

        猜你喜欢
        • 2010-12-27
        • 1970-01-01
        • 1970-01-01
        • 2021-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-27
        相关资源
        最近更新 更多