首页 文章

事实,谓词和规则

提问于
浏览
3

我决定学习prolog只是为了好玩,我找到了解决这个问题的方法 .
我能够在纸上解决这个难题,但我无法将其传递给代码 .

问题:

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

我有一些规则,如:

Sara将于周三9点接受测试 . 周三,8岁的女孩将不会接受测试.Pilar必须在Nanda之前进行测试 . Olga将在Mel的同一天进行测试 . 如果Lia在任何一天的8天进行测试,那么Rute必须在不同的日子进行8次测试 .

don't want 完整的解决方案,我只是想从一开始就有所帮助 .

我试图写一些东西,但没有成功 .

%   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.

我甚至试图 Build 一个 struct

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

之后,我的程序将不得不回答一些问题,如:

从星期一到星期五,哪个候选人将在8:00进行测试?

我的主要想法是开始编写规则和事实然后我'd go through all the rules testing each one. But I can'甚至写 factsrules 对......

2 回答

  • 4

    Prolog是一种声明性语言 . 专注于清楚地描述每个解决方案的内容 . Prolog系统将为您完成剩下的工作 . 不要说:"I'd go through all the rules testing each one" . 更好的说法:“我说明了解决每个解决方案的属性 . ”这是因为,当您完成后,您的谓词可用于多个方向:是的,您可以使用它来测试给定的解决方案 . 但是,如果可能,您还可以使用它来生成解决方案,并完成部分填充的计划 .

    首先:

    schedule(S) :- ...

    这被理解为: S 是一个时间表 if ....现在,填写点:在任何有效的时间表中有哪些属性?这些是您的任务中给出的约束,在Prolog中表示为目标 .

    如您所愿,我不会给您一个完整的解决方案,但有一些提示可以帮助您入门 . 我正在使用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 中的每个变量不等于( (#\=)/2 )到 4 时才为真 .

    我将编码最后两个约束作为练习留给你 . 尝试很好地和紧凑地编码它们 .

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

    ?- 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 .
    

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

  • 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构造变得容易 .

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

相关问题