【问题标题】:How to use member predicate to specify constraints in prologprolog中如何使用成员谓词指定约束
【发布时间】:2016-07-20 10:50:53
【问题描述】:

我正在尝试编写一个 Prolog 程序,它执行以下操作: 我在关系列表中定义了一些关系。 (例如:[f1,s1] 表示 f1 需要 s1)根据 TargetFeat 列表中选择的特征(f1,f2,f3),我想使用约束编程创建结果列表。 这是一个示例代码:

Relations =[[f1, s1], [f2, s2], [f3, s3], [f3, s4]],
TargetFeat = [f3, f1],
Result = [],
member(f3,TargetFeat) #= member(s3,Result), %One of the constraints
labeling(Result).

这不起作用,因为 #= 仅适用于算术表达式作为操作数。有什么替代方法可以实现这样的目标?

【问题讨论】:

    标签: prolog clpfd constraint-programming


    【解决方案1】:

    有许多可能的方法可以用约束对此类依赖项进行建模。我在这篇文章中考虑了 CLP(FD) 和 CLP(B) 约束,因为它们最常用于解决组合任务。

    首先考虑 CLP(FD),它在许多方面使用更频繁,也更方便。当使用 CLP(FD) 约束时,您再次有几个选项来表示您的任务。但是,无论您最终选择哪种模型,您都必须首先将表示中的所有项目切换到约束求解器实际上可以推理的合适实体。对于 CLP(FD),这意味着将您的实体切换为 整数

    将您的实体转换为相应的整数非常简单,这也是为什么 CLP(FD) 约束也足以对实际上不包含整数但可以映射到整数的域上的任务进行建模的原因之一。所以,让我们假设您不是在推理 f1f2f3 的特性,而是关于 整数 012 或任何其他集合适合您的整数。

    您可以直接将您的需求转换到这个新域。例如,而不是:

    [f1,s1] 表示:f1 需要s1

    我们可以说例如:

    0 -> 3 表示:0 需要3

    这使我们已经非常接近 CLP(FD) 约束,使我们能够对整个问题进行建模。我们只需要再进行一次精神上的飞跃,即可获得一种表示,使我们能够对所有需求进行建模。我们现在使用 CLP(FD) 变量 来指示是否必须满足特定要求才能获得所需的特征,而不是 具体 整数。我们将使用变量R1, R2, R3, ... 来表示需要哪些要求,对每个可能的要求使用0(不需要)或1(需要) .

    此时,您必须针对您真正想要描述的内容建立一个清晰的心智模型。我解释一下我的想法:我想描述三件事之间的关系

    1. 功能列表Fs
    2. 功能和需求之间的依赖关系列表Ds
    3. 列表Rs 要求

    我们已经考虑过如何表示所有这些实体:(1) 是一个 整数 列表,表示我们想要获得的特征。 (2) 是 F -> R 对的列表,表示“功能 F 需要需求 R”,(3) 是布尔变量列表,指示最终是否需要每个需求。

    现在让我们尝试将所有这些实体相互关联。

    首先要做的事情:如果不需要任何功能,这一切都是微不足道的:

    features_dependencies_requirements([], _, _).
    

    但是,如果确实需要某个功能怎么办?嗯,很简单:我们只需要考虑该功能的依赖关系:

    features_dependencies_requirements([F|Fs], Ds, Rs) :-
        member(F->R, Ds),
    

    所以我们在R 中有功能F 的要求。现在我们只需要在Rs 中找到合适的变量来表示需求R。但是我们如何找到正确的变量呢?毕竟,Prolog 变量“没有领结”,或者——对于外国人来说——缺少一个我们可以将其与其他变量区分开来的标记。因此,在这一点上,我们实际上会发现能够很好​​地从Rs 中挑选出一个变量,给定它的需求名称。因此,假设我们将Rs 表示为I=R 形式的pairs 列表,其中I 是定义要求的整数,R 是布尔指标表示是否需要该要求。鉴于这种表示,我们可以将上面的整个子句定义如下:

    features_dependencies_requirements([F|Fs], Ds, Rs) :-
        member(F->I, Ds),
        member(I=1, Rs),
        features_dependencies_requirements(Fs, Ds, Rs).
    

    就是这样。这完全关联了一系列特性、依赖项和需求,以便第三个参数指示获得特性所必需的需求。

    此时,细心的读者将会看到,在上面的代码中,没有任何 CLP(FD) 约束,事实上,将特征转换为整数是完全没有必要的。我们也可以使用原子来表示特征和要求,使用上面显示的完全相同的代码

    示例查询和答案:

    ?- features_dependencies_requirements([f3,f1], [f1->s1,f2->s2,f3->s3,f3->s4], [s1=S1,s2=S2,s3=S3,s4=S4])。 S1 = S3, S3 = 1 ; S1 = S4, S4 = 1 ; 错误的。

    显然,我做了以下假设:依赖关系是分离的,这意味着如果至少满足一个的需求,则可以实现该功能。如果你想把它变成一个连词,你显然必须改变它。您可以首先将依赖关系表示为F -> [R1,R2,...R_n]

    除此之外,将实体转换为整数是否仍然有用? 是的,因为您的许多约束可能也可以使用 CLP(FD) 约束来制定,并且您需要 整数 才能使其工作。

    为了帮助您入门,以下两种方法可能适用于您的情况:

    • 使用约束reification来表达什么暗示什么。例如:F #==> R
    • 使用诸如table/2 之类的全局约束来表达关系。

    特别是在第一种情况下,CLP(B) 约束也可能有用。您始终可以使用布尔变量来表示是否必须满足要求。

    【讨论】:

    • 嗨垫,非常感谢您的详细回答。我是 Prolog 的新手,它真的帮助了我。不过我有一个疑问。我不确定我是否理解这些行。 “因此,让我们假设我们将 Rs 表示为 I=R 形式的对列表,其中 I 是定义需求的整数,R 是表示是否需要该需求的布尔指标”。我花了一些时间思考它。但不确定是什么意思。
    • I=R 是术语=(I, R)。因此,例如,我们希望看到s3=1 出现在第三个列表中iff 要求必须满足s3。出于这个原因,我将此称为指标:您可以使用0 表示需要 满足要求,而1 表示其他情况。
    • Nit: member(F->I, Ds) 语法无效。只有 SWI 接受它。
    • 将 F->I 更改为 F -> [R1,R2,...R_n] 会强制所有功能依赖于多个需求,对吧?我想支持这样的东西:[f1->s1,f2->s2,f3->[s3,s4]]
    • @user2139876:只有 SWI 允许这种不一致的语法。对于符合 ISO 标准的系统,您需要使用 member((F->I), Ds)。注意括号!如果你想表达多个需求,你需要对表达这些约束的合取的代码做一些小的改动。我把它作为一个非常简单的练习。
    【解决方案2】:

    不是解决方案,而是一些不适合评论的观察结果。

    不要使用列表来表示关系。例如,不要写[f1, s1],而是写requires(f1, s1)。如果这些要求是固定的,则将requires/2 定义为谓词。如果您需要识别或枚举特征,请考虑使用feature/1 谓词。例如:

    feature(f1).
    feature(f2).
    ...
    

    s1s2、...例如

    support(s1).
    support(s2).
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多