【问题标题】:Facts, Predicates and Rules事实、谓词和规则
【发布时间】:2015-10-12 14:56:34
【问题描述】:

我决定学习 prolog 只是为了好玩,我正在看一些视频教程。另外,我在互联网上搜索了一些尝试解决的问题,但找不到解决此问题的方法。
我能够在纸上解决这个难题,但我无法将其传递给代码。

问题:

我有 8 位候选人(Lia、Mel、Nanda、Olga、Rute、Sara、Tina、Pilar)。
他们都将在周一至周五的 8:00 和 9:00 进行测试。

我有一些规则,例如:

Sara 必须在周三 9 点接受测试。
周三 8 点不会对女孩进行测试。
Pilar 必须在 Nanda 之前进行测试。
奥尔加必须在梅尔的同一天进行测试。
如果 Lia 在任何一天的 8 点进行测试,那么 Rute 必须在另一天的 8 点进行测试。

不想要完整的解决方案,我只是想要一些帮助来开始。

我想写点东西,但没有成功。

%   Facts   %
candidate(lia).
candidate(mel).
candidate(nanda).
candidate(olga).
candidate(pilar).
candidate(rute).
candidate(sara).
candidate(tina).

day(monday).
day(tuesday).
day(wednesday).
day(thursday).
day(friday).

time(8).
time(9).  

/*Sara HAS TO be tested on Wednesday at 9*/
tested_on(sara, wednesday, 9).  

/*No test will happen on Wednesday at 8*/
no_test(X, wednesday, 8) :- X == none.  

我什至试图建立一个struct

cand(
    sara,
    date(wednesday, 9)
    ).  

之后我的程序必须回答一些问题,例如:

在周一至周五的 8:00 测试的候选人名单是正确的?

我的主要想法是开始编写规则和事实,然后我会通过所有规则测试每个规则。但是我连factsrules都写不出来对……

【问题讨论】:

    标签: prolog predicate rules


    【解决方案1】:

    Prolog 是一种声明性语言。专注于对每个解决方案适用的清晰描述。 Prolog 系统将为您完成剩下的工作。不要说:“我会通过所有规则来测试每个规则”。最好说:“我声明了每个解决方案的属性。”这是因为,当你完成后,你的谓词可以在几个方向上使用:是的,你可以用它来测试给定的解决方案。但您也可以使用它生成解决方案,并在可能的情况下完成部分完成的计划。

    开始:

    schedule(S) :- ...

    这被读作:S is a schedule if ... 。现在,填写点:在任何有效的时间表中都有哪些属性?这些是在您的任务中给出的约束,在 Prolog 中以 goals 的形式表示。

    如您所愿,我不会给您一个完整的解决方案,而是提供一些帮助您入门的提示。我正在使用 CLP(FD) 约束以声明方式声明所有要求。代码在 SICStus、SWI、YAP、GNU Prolog 和其他几个系统中运行,至多进行少量修改。

    首先,为了表示可用时隙,我使用整数 0..9。具体来说,我使用:

           Monday  Tuesday  Wednesday Thursday Friday
    8:00:    0        2         4        6       8
    9:00:    1        3         5        7       9
    

    例如,星期四 9:00 用整数 7 表示。

    每个候选者都是一个有限域变量,表示为候选者分配的时隙。

    我将一个时间表表示为一个时隙列表,每个候选人一个,按照任务描述中的顺序排列。

    只需使用 CLP(FD) 谓词对指定的约束进行编码。查看 Prolog 系统的文档以了解这些谓词的含义。例如,对于 SICStus Prolog,请查看 membership constraintsarithmetic constraints。其他系统也是如此。

    这是一个开始:

    :- use_module(library(clpfd)).
    
    schedule(Vars) :-
            Vars = [Lia,Mel,Nanda,Olga,Rute,Sara,_Tina,Pilar],
            all_different(Vars),
            Vars ins 0..9,
            Sara #= 5,
            maplist(#\=(4), Vars),
            Pilar #< Nanda.
    

    如您所见,这与任务描述中出现的约束密切相关。例如,Sara 只能安排在星期三的 9:00,根据上表,这个特定的时间段对应整数5,变量Sara表示安排 Sara 的时间段。因此,我们声明约束Sara #= 5。同样,没有人可以安排在星期三的 8:00。这个时隙对应于整数4,因此我们声明约束maplist(#\=(4), Vars),当且仅当Vars 中的每个变量 等于((#\=)/24.

    我将最后两个约束的编码留给您作为练习。尝试对它们进行良好而紧凑的编码。

    具有编码约束的示例解决方案:

    ?- Vs = [Lia,Mel,Nanda,Olga,Rute,Sara,Tina,Pilar], schedule(Vs), label(Vs).
    Vs = [0, 1, 3, 7, 6, 5, 8, 2],
    Lia = 0,
    Mel = 1,
    Nanda = 3,
    Olga = 7,
    Rute = 6,
    Sara = 5,
    Tina = 8,
    Pilar = 2 .
    

    请注意,巧合的是,这甚至满足了我们尚未明确编码的最后一个约束。

    【讨论】:

    • 非常感谢您帮助我。但是我不得不说我可以理解你的很多代码。它看起来像一个高级编码示例,我对这种语言真的很陌生。有没有办法更简单地展示如何开始创建规则或类似的东西。我正在阅读有关模块和其他内容的信息,但稍微简单一点会很好;P 我习惯于 C、C#、PHP。这对我来说真的很奇怪哈哈;x 再次感谢!
    • 我添加了一些解释,希望对你有用。
    【解决方案2】:

    为了方便日期比较,稍微改变一下表示很方便:

    candidate(1,lia).
    candidate(2,mel).
    candidate(3,nanda).
    candidate(4,olga).
    candidate(5,rute).
    candidate(6,sara).
    candidate(7,tina).
    candidate(8,pilar).
    
    day(1,monday).
    day(2,tuesday).
    day(3,wednesday).
    day(4,thursday).
    day(5,friday).
    

    那么我们可以将解决方案表示为一对(Date,Time)的列表,其中列表中的位置代表女孩:

    solution(Dom) :-
        Dom = [
            (D1,T1),
            (D2,T2),
            ...
            (D8,T8)
        ],
    dom(Dom),
    ...
    

    域生成有点棘手:我们必须得到所有不同的 Day,Time 对。第一种,低效的方法

    dt((D,T)) :- day(D,_),time(T).
    
    dom([]).
    dom([E|R]) :- dt(E), dom(R), \+ memberchk(E, R).
    
    ?- length(L,6),time(aggregate(count,so:(L^dom(L)),N)).
    % 10,044,119 inferences, 3.188 CPU in 3.190 seconds (100% CPU, 3150577 Lips)
    L = [_G6035, _G6038, _G6041, _G6044, _G6047, _G6050],
    N = 151200.
    

    虽然这个替代方案更快

    dom([E]) :- dt(E).
    dom([E|R]) :- dom(R), dt(E), \+ memberchk(E, R).
    
    ?- length(L,6),time(aggregate(count,so:(L^dom(L)),N)).
    % 952,236 inferences, 0.567 CPU in 0.567 seconds (100% CPU, 1680621 Lips)
    L = [_G6041, _G6044, _G6047, _G6050, _G6053, _G6056],
    N = 151200.
    

    (dom/1 适用于任何长度,我选择了 6 来举例说明...)

    现在可以表达约束,例如

    % Sara HAS TO be tested on Wednesday at 9.
    day(D6, wednesday), T6 = 9,
    

    约束

    周三 8 点不会对女孩进行测试。

    可能很棘手:这意味着 (3,8) 不能出现在 Dom 中。 但是使用 if/then/else 结构变得容易。

    如果您需要更多线索,请告诉我。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-16
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多