【问题标题】:How to write kind of Conditional Planning in Prolog?如何在 Prolog 中编写条件规划?
【发布时间】:2012-10-25 01:44:44
【问题描述】:

我尝试编写一个可以理解用 C# 编写的学生程序的 prolog 代码。现在我陷入了识别学生程序中“if”语句的过程中。例如: 以下是我期望学生提供的代码。

int d = int.Parse(Console.ReadLine());  // value d is inputted by user
int s = 0;

if (d>0)
    s = 2;
else if (d==0)
    s = 1;
else
    s = 0;

我将这段预期代码的目标定义为:

goal:- 
   hasVarName(Vid_s, s),
   hasVarName(Vid_d, d),
   hasVarValue(Vid_d, Vd),
   ((not(gt(Vd,0)); hasVarValue(Vid_s, 2)),           %eq: [Vd>0] -> [val_s = 2]
   ((gt(Vd,0); not(eq(Vd,0)); hasVarValue(Vid_s, 1)), %eq: [~(Vd>0)^(Vd=0)] -> [val_s = 1]
   ((gt(Vd,0); eq(Vd,0); hasVarValue(Vid_s, 0).       %eq: [~(Vd>0)^~(Vd=0)] -> [val_s = 0]

问题是如何在 prolog 事实和规则中表示上述学生代码,以找出任何可能的条件都满足目标。

我试图将学生代码的第一部分更改为如下所示的事实,但真的不知道如何将学生的“if”语句表示为 prolog 中的事实/规则(我想,我不应该更改它的序言'if',对吧?)

hasVarName(varID_d, d)
hasVarValue(varID_d, val_d)   %it is unknown, so I represent it as symbol 'val_d'

hasVarName(varID_s, s)
hasVarValue(varID_s, 0)

另外一个,在我的目标中,当我进行比较时,例如gt(Vd,0),我认为我不能使用序言大于运算符,Vd> 0Vd @> 0 都不是因为 Vd 中的值实际上是输入的某个值由用户,但它表示为符号值(在本例中为:val_d)。

注意:使用上述目标,我认为如果将学生代码更改为以下代码,则可以满足定义的目标。

int d = int.Parse(Console.ReadLine());  // value d is inputted by user
int s = 0;

if (d>0)
    s = 2;
else if (d==0)
    s = 1;

int d = int.Parse(Console.ReadLine());  // value d is inputted by user
int s = 10;           // any random initialization

if (d>0)
{
    int x = 2;       // unnecessary step, but still Ok.
    s = x;
}
else if (d==0)
    s = 1;
else
    s = 0;

但同样,我需要帮助/了解如何在 prolog 中将此代码表示为操作/规则/事实以实现目标。

非常感谢任何帮助。

非常感谢

【问题讨论】:

    标签: prolog conditional planning clpfd


    【解决方案1】:

    我猜你试图通过暗示来模拟 if-then-else,使用 以下布尔标识:

    A -> B == ~A v B.
    

    与其使用含意连词,更简单 使用析取在分支之间进行选择,并使用合取 沿着控制流。但是你排除了以前的 if 条件 仍然需要通过否定。

    举个例子:

    if (d>0)
       s = 2;
    else if (d==0)
       s = 1;
    else
       s = 0;
    

    您可以使用 CLP( * ) 对其进行建模。添加额外的变量,以便 变量没有被覆盖,但这不是问题 比 sn-p 小。在 CLP( * ) 中,上述 sn-p 变为,我 为简单起见,我使用 CLP(FD):

    Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.3.0)
    Copyright (c) 1990-2012 University of Amsterdam, VU Amsterdam
    ?- use_module(library(clpfd)).
    ?- [user].
    that_if(D, S) :-
       (D #> 0, S #= 2;
        D #=< 0, D #= 0, S #= 1;
        D #=< 0, D #\= 0, S #= 0)
    ^D
    

    在一个体面的 CLP( * ) 系统中,您可以任意实例化或 在查询中约束 D 或 S。例如,我们已经得到 在 CLP(FD) 中:

    /* What conditions give result S #= 1 ? */
    ?- S #= 1, that_if(D, S).
    S = 1,
    D = 0 .
    
    /* What results give condition D #= 1 */
    ?- D #= 1, that_if(D, S).
    D = 1,
    S = 2 ;
    false.
    
    /* What conditions give a result S #=< 1 */
    ?- S #=< 1, that_if(D, S).
    S = 1,
    D = 0 ;
    S = 0,
    D in inf.. -1.
    
    /* What results give a condition D #>= 0 */
    ?- D #>= 0, that_if(D, S).
    S = 2,
    D in 1..sup ;
    D = 0,
    S = 1 ;
    false.
    

    再见

    【讨论】:

    • CLP 很有趣,但我认为新手可能真的很难理解它。
    • 不是我的意见:我不知道 Budi Hartanto 是否是新手,也没有统计数据表明 CLP( * ) 特别难。 CLP( * ) 应该更简单,因为它更具声明性。
    • 进一步没有一些 CLP( * ) 无法验证。如果你有 int d = int.Parse(Console.ReadLine());那么数据可以是任意的,标准的 Prolog 详尽搜索实际上无法回答您的查询。你需要一些更具象征意义的东西,比如 CLP( * )。
    • 嗨 Cookie Monster,感谢您提出的解决方案。问题是,就我而言,我永远不会知道 d 的值是什么,因为我永远不会运行学生代码。我只需要分析学生代码包含足够的计划(条件)来解决给他的问题。因此,我永远不会知道 D 的值,在我的示例中,我只是简单地将 val_d 分配为变量 d 内容的符号表示。所以,我在这种情况下的问题更像是检查学生的计划(代码)是否可以用来解决给他的问题。
    • CLP( * ) 也不分配值,除非例如在 CLP(FD) 中使用标签。但是诸如 1..sup 中的 D 之类的答案不是赋值,而是变量的域范围。但是您需要更多的编码,并最终具体化约束,才能从您的 CLP( * ) 中获得与您的问题相关的更精确的响应。例如检查 spec_if(D,S) code_if(D,S).
    【解决方案2】:

    通常,语言实现需要一个抽象语法树,可以方便地指定实现我们允许表达的结构的语义操作。

    您似乎跳过了构建语法树的阶段,并且(手动?)代表程序的中间级别。

    如果您坚持这种中等级别的表示,您可以使用递归术语(实际上是抽象树),例如 if(Condition, Then, Else),其中每个 var 依次是语法树。

    否则,更实际的表示(通常应用于命令式语言),使用基本块(没有跳转的指令序列)的概念,然后是标签,来描述执行流程。

    结果是一个图表,程序的行为由该表示的“拓扑”决定。

    goal:- 
       hasVarName(Vid_s, s),
       hasVarName(Vid_d, d),
       hasVarValue(Vid_d, Vd),
    
       %eq: [Vd>0] -> [val_s = 2]
       ((not(gt(Vd,0)); hasVarValue(Vid_s, 2), goto(label(0))),
    
       %eq: [~(Vd>0)^(Vd=0)] -> [val_s = 1]
       ((gt(Vd,0); not(eq(Vd,0)); hasVarValue(Vid_s, 1), goto(label(0))),
    
       %eq: [~(Vd>0)^~(Vd=0)] -> [val_s = 0]
       ((gt(Vd,0); eq(Vd,0); hasVarValue(Vid_s, 0)), % the goto is useless here...
    
       label(0),
       .....
    

    请注意,我没有注意正确描述您的示例程序,只是放置了跳转以显示这种可能性...

    edit我认为general问题无法解决,相当于图灵机的halting problem。对于手头的特殊情况,没有循环,我会在 AST 上使用抽象解释来解决这个问题。 IE。计算有趣内容的解释器。

    是否可行取决于您的目标程序的普遍性。您应该能够为每个条件点中涉及的每个变量划分整数域。事情变得迅速复杂......

    具体来说,在 IF THEN ELSE 的条件点尝试对域进行分区。使用这种方法,让 Prolog 执行 IF 测试两个分支,传播值。但是,正如我所说,这并不容易......

    【讨论】:

    • 嗨,Chac,感谢您提出的解决方案。你能解释一下你的建议吗?供您参考,这就是我所做的全部事情:我有一个读取学生 C# 程序的 C# 程序。在我的 C# 程序中,我有学生代码的 AST。根据这个 AST,我创建了 prolog 子句,让 prolog 确定我为学生任务设置的目标是否得到满足。所以,我已经在我的 C# 程序中准备好了 AST,但我真的不知道如何在 prolog 中呈现它以将它与我的目标联系起来。或者我定义目标的方式不正确?谢谢
    猜你喜欢
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多