Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中实现Prolog统一算法?回溯_Python_Algorithm_Prolog_Backtracking_Unification - Fatal编程技术网

在Python中实现Prolog统一算法?回溯

在Python中实现Prolog统一算法?回溯,python,algorithm,prolog,backtracking,unification,Python,Algorithm,Prolog,Backtracking,Unification,我试图实现统一,但遇到了问题。。已经有十几个例子了,但他们所做的只是把水弄脏。我感到困惑多于开悟: [以下代码基于本简介] 序言的艺术一个…和其他几个。 最大的问题是我想不出这个问题的明确表述。更多的数学或口齿不清的解释让我更加困惑 作为一个良好的开端,遵循基于列表的表示似乎是一个好主意(如lispy案例),即: 除了如何表示列表本身!?i、 e.[H | T] 如果您能给我看一个Python伪代码和/或更详细的算法描述,或者一个指向它的指针,我会很高兴的 我掌握的一些要点是需要在通用

我试图实现统一,但遇到了问题。。已经有十几个例子了,但他们所做的只是把水弄脏。我感到困惑多于开悟:

[以下代码基于本简介]

序言的艺术一个…和其他几个。 最大的问题是我想不出这个问题的明确表述。更多的数学或口齿不清的解释让我更加困惑

作为一个良好的开端,遵循基于列表的表示似乎是一个好主意(如lispy案例),即:

除了如何表示列表本身!?i、 e.[H | T]

如果您能给我看一个Python伪代码和/或更详细的算法描述,或者一个指向它的指针,我会很高兴的

我掌握的一些要点是需要在通用统一器和var统一器中分离代码,但是我看不到相互重复的情况。。。等等


作为旁注:我也希望你们提到,你们如何处理回溯的统一问题。我想我已经把回溯整理好了,但我知道回溯中的替换帧必须发生一些事情


添加了带有当前代码的答案


我将从以下内容中快速总结Baader和Snyder的章节:

术语由常量(以小写字母开头)和变量(以大写字母开头)构成:

  • 没有参数的常数是一个术语:例如
    car
  • 以术语作为参数的常量,即所谓的函数应用程序,是术语。e、 g.
    日期(1,102000)
  • 变量是一个术语,例如
    Date
    (变量从来没有参数)
替换是将术语分配给变量的映射。在文献中,这通常被写成
{f(Y)/X,g(X)/Y}
或带有箭头
{X→f(Y),Y→g(X)}
。对术语应用替换将用列表中相应的术语替换每个变量。例如,上面应用于
元组(X,Y)
的替换结果是术语
元组(f(Y),g(X))

给定两个术语
s
t
,unifier是使
s
t
相等的替换。例如,如果我们将替换
{a/X,a/Y}
应用于术语
日期(X,12000)
,我们得到
日期(a,12000)
,如果我们将其应用于
日期(Y,12000)
我们也得到
日期(a,12000)
。换句话说,可以通过应用统一的
{a/X,a/Y}
来解决(语法)等式
date(X,12000)=date(Y,12000)
。另一个更简单的统一工具是
X/Y
。这种最简单的统一体称为最一般的统一体。出于我们的目的,我们只需要知道,我们可以限制自己搜索这样一个最通用的统一体,如果它存在,它是唯一的(直到一些变量的名称)

Mortelli和Montanari(参见本文第2.2节和其中的参考文献)给出了一组规则来计算这样一个最通用的统一体(如果存在的话)。输入是一组术语对(例如{f(X,b)=f(a,Y),X=Y}),如果存在,则输出是最通用的统一体,如果不存在则输出失败。在该示例中,替换{a/X,b/Y}将使第一对相等(
f(a,b)=f(a,b)
),但第二对将不同(
a=b

该算法不确定地从集合中选取一个等式,并对其应用以下规则之一:

  • 琐碎的:等式
    s=s
    (或
    X=X
    )已经相等,可以安全删除
  • 分解:等式
    f(u,v)=f(s,t)
    被等式
    u=s
    v=t
    替换
  • 符号冲突:相等的
    a=b
    f(X)=g(X)
    会以失败终止进程
  • 方向:将形式为
    t=X
    的等式(其中
    t
    不是另一个变量)翻转到
    X=t
    ,使变量位于左侧
  • 发生检查:如果方程式的形式为
    X=t
    t
    不是
    X
    本身,如果
    X
    发生在
    t
    内的某个地方,则我们失败。[1]
  • 变量消除:我们有一个等式
    X=t
    ,其中
    X
    不出现在
    t
    中,我们可以将替换
    t/X
    应用于所有其他问题
当没有可应用的规则时,我们最终得到一组表示要应用的替换的方程
{X=s,Y=t,…}

以下是更多的例子:

  • {f(a,X)=f(Y,b)}
    是可统一的: 分解得到{a=Y,X=b},翻转得到{Y=a,X=b}
  • {f(a,X,X)=f(a,a,b)}
    是不可统一的: 分解得到{a=a,X=a,X=b},通过平凡性消除
    a=a
    ,然后消除变量
    X
    得到
    {a=b}
    ,并因符号冲突而失败
  • {f(X,X)=f(Y,g(Y))}
    是不可统一的: 分解以获得
    {X=Y,X=g(Y)}
    ,消除变量
    X
    以获得
    {Y=g(Y)}
    ,失败并进行检查
即使算法是不确定的(因为我们需要选择一个等式来处理),顺序也不重要。因为您可以按照任何顺序进行操作,所以不必撤销您的工作,而是尝试另一个等式。这种技术通常被称为回溯,它对于Prolog中的证明搜索是必要的,但对于统一本身不是必要的

现在只剩下为术语和替换选择合适的数据结构,并实现将替换应用于术语的算法以及基于规则的统一算法

[1] 如果我们尝试求解
X=f(X)
,我们会发现X的形式应该是
f(Y)
t
pred(Var, val)  =becomes=> [pred, Var, val] 
p1(val1, p2(val2, Var1)) ==> [p1, val1, [p2, val2, Var1]]
def unify_var(self, var, val, subst):
#   print "var> ", var, val, subst

    if var in subst :   
        return self.unify(subst[var], val, subst)
    elif isinstance(val, str) and val in subst : 
        return self.unify(var, subst[val], subst)
    #elif (var occurs anywhere in x) then return failure
    else :
        #print "%s := %s" % (var, val)
        subst[var] = val ; return subst

def unify(self, sym1, sym2, subst):
    #print 'unify>', sym1, sym2, subst

    if subst is False : return False
    #when both symbols match
    elif isinstance(sym1, str) and isinstance(sym2, str) and sym1 == sym2 : return subst
    #variable cases
    elif isinstance(sym1, str) and is_var(sym1) : return self.unify_var(sym1, sym2, subst)
    elif isinstance(sym2, str) and is_var(sym2) : return self.unify_var(sym2, sym1, subst)
    elif isinstance(sym1, tuple) and isinstance(sym2, tuple) : #predicate case
        if len(sym1) == 0 and len(sym2) == 0 : return subst
        #Functors of structures have to match
        if isinstance(sym1[0], str) and  isinstance(sym2[0],str) and not (is_var(sym1[0]) or is_var(sym2[0])) and sym1[0] != sym2[0] : return False
        return self.unify(sym1[1:],sym2[1:], self.unify(sym1[0], sym2[0], subst))
    elif isinstance(sym1, list) and isinstance(sym2, list) : #list-case
        if len(sym1) == 0 and len(sym2) == 0 : return subst
        return self.unify(sym1[1:],sym2[1:], self.unify(sym1[0], sym2[0], subst))

    else: return False
OK: a <=> a : {}
OK: X <=> a : {'X': 'a'}
OK: ['a'] <=> ['a'] : {}
OK: ['X'] <=> ['a'] : {'X': 'a'}
OK: ['a'] <=> ['X'] : {'X': 'a'}
OK: ['X'] <=> ['X'] : {}
OK: ['X'] <=> ['Z'] : {'X': 'Z'}
OK: ['p', 'a'] <=> ['p', 'a'] : {}
OK: ['p', 'X'] <=> ['p', 'a'] : {'X': 'a'}
OK: ['p', 'X'] <=> ['p', 'X'] : {}
OK: ['p', 'X'] <=> ['p', 'Z'] : {'X': 'Z'}
OK: ['X', 'X'] <=> ['p', 'X'] : {'X': 'p'}
OK: ['p', 'X', 'Y'] <=> ['p', 'Y', 'X'] : {'X': 'Y'}
OK: ['p', 'X', 'Y', 'a'] <=> ['p', 'Y', 'X', 'X'] : {'Y': 'a', 'X': 'Y'}
 ================= STRUCT cases ===================
OK: ['e', 'X', ('p', 'a')] <=> ['e', 'Y', ('p', 'a')] : {'X': 'Y'}
OK: ['e', 'X', ('p', 'a')] <=> ['e', 'Y', ('p', 'Z')] : {'X': 'Y', 'Z': 'a'}
OK: ['e', 'X', ('p', 'a')] <=> ['e', 'Y', ('P', 'Z')] : {'X': 'Y', 'Z': 'a', 'P': 'p'}
OK: [('p', 'a', 'X')] <=> [('p', 'Y', 'b')] : {'Y': 'a', 'X': 'b'}
OK: ['X', 'Y'] <=> [('p', 'a'), 'X'] : {'Y': ('p', 'a'), 'X': ('p', 'a')}
OK: [('p', 'a')] <=> ['X'] : {'X': ('p', 'a')}
-----
FAIL: ['e', 'X', ('p1', 'a')] <=> ['e', 'Y', ('p2', 'Z')] : False
FAIL: ['e', 'X', ('p1', 'a')] <=> ['e', 'Y', ('p1', 'b')] : False
FAIL: [('p', 'a', 'X', 'X')] <=> [('p', 'a', 'a', 'b')] : False
(should fail, occurs) OK: [('p1', 'X', 'X')] <=> [('p1', 'Y', ('p2', 'Y'))] : {'Y': ('p2', 'Y'), 'X': 'Y'}
================= LIST cases ===================
OK: ['e', 'X', ['e', 'a']] <=> ['e', 'Y', ['e', 'a']] : {'X': 'Y'}
OK: ['e', 'X', ['a', 'a']] <=> ['e', 'Y', ['a', 'Z']] : {'X': 'Y', 'Z': 'a'}
OK: ['e', 'X', ['e', 'a']] <=> ['e', 'Y', ['E', 'Z']] : {'X': 'Y', 'Z': 'a', 'E': 'e'}
OK: ['e', 'X', ['e1', 'a']] <=> ['e', 'Y', ['e1', 'a']] : {'X': 'Y'}
OK: [['e', 'a']] <=> ['X'] : {'X': ['e', 'a']}
OK: ['X'] <=> [['e', 'a']] : {'X': ['e', 'a']}
================= FAIL cases ===================
FAIL: ['a'] <=> ['b'] : False
FAIL: ['p', 'a'] <=> ['p', 'b'] : False
FAIL: ['X', 'X'] <=> ['p', 'b'] : False