坚持Prolog计划

时间:2012-11-19 01:24:18

标签: prolog

我能熟练使用Java和C#,因此Prolog中的编码对我来说一直很困难,因为它似乎是一种完全不同的思维方式。

我需要解决的问题很简单,我可以在十分钟内用Java来解决它。我老实说,即使在这里开始也很麻烦。我得到一份代表选民“投票”的十个数字的清单。投票是0,-1或1.然后我也得到一个列表列表,每个列表是候选人的列表。每个候选人的列表包括一个名称,后面跟选民名单中的十个分数。

我的目标是将选民名单与每个候选人名单进行比较,并根据相同的投票返回最佳匹配列表。

这就是我给出的:

?- best_candidates(
    [           0,   0,   0,   1,   1,   1,  -1,  -1,  -1,   1],
    [[adams     1,   1,   1,   1,   1,   1,   1,   1,   1,   1],
     [grant    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1],
     [polk      1,  -1,   1,  -1,   1,  -1,   1,  -1,   1,  -1],
     [jackson   1,   0,   1,   0,   1,   0,   1,   0,   1,   0],
     [taft      0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1],
     [ford      1,   1,   1,   1,   0,   0,   0,   0,   0,   0],
     [madison   0,   0,   0,   1,  -1,   0,   0,  -1,   1,   1]],
    BestMatches).

这应该返回BestMatches = [adams,ford,madison]。

到目前为止,我没有太多东西。我只想弄明白我应该怎么做。我是否需要多种方法,或者我是否应该在best_candidates方法中完成所有这些?

在回应埃德蒙的建议时,我到目前为止就是这样:

% match V1 and V2 and unify M with the match score
% match(V1, V2, M)
match([], [], 0).
match([H1|T1], [H2|T2], M) :-
    match_single_entry(H1, H2, M1),
    match(T1, T2, M2), 
    M is M1+M2.

% match_single_entry(I, J, M)
match_single_entry(X, Y, M) :-
    X =\= 0,
    Y =\= 0,
    I =:= J, 
    M is 1.

2 个答案:

答案 0 :(得分:1)

问题的关键似乎是一个函数,它接受10个数字的两个向量,并返回总匹配分数。

首先是Prolog没有功能;它有谓词。但是您可以通过提供可以绑定到“函数”输出的变量,轻松地将函数概念转换为谓词概念:

% Match V1 and V2, and unify M with the match score.
match(V1, V2, M) :- ...

目前尚不清楚向量是如何匹配的(但我认为它是相同条目的数量?或每对条目之间的绝对差值之和?)。但是这个谓词可能会用一个基本情况定义(对于长度为0的列表),以及为每个列表的头部计算它的一般情况,以及列表尾部的递归。

match([], [], 0).  % I'm assuming the match score for empty lists is 0.
match([H1|T1], [H2|T2], M) :-
    match_single_entry(H1, H2, M1),  % Somehow compute the score for two single entries.
    match(T1, T2, M2),  % Recurse on the tails.
    M is M1+M2.  % Combine the two scores and bind to the output variable M.

我已经match_single_entry未定义。一旦你定义了它,你应该练习match运行% Let's try getting the match score for adams: ?- match([1,1,1,1,1,1,1,1,1,1], [0,0,0,1,1,1,-1,-1,-1,1], AdamsScore). AdamsScore = 3 ; No 与候选人的矢量对应的各种候选人:

best_candidates

下一个挑战是编写另一个谓词BestMatches,它接受​​选民的向量加上一组候选向量,每一个得分,然后返回 - 也就是说,绑定到对应{{1}的输出变量 - 那些得分最高的人。同样,这个谓词可以通过定义一个基本案例(没有候选者,因此没有最好的候选者)和一次处理一个候选者的递归案例来迭代候选载体集。

对每个候选载体进行评分

如您所述,候选向量的名称后跟值。这意味着可以通过[Name|Values] = V轻松分割向量,并将Values传递给match以与选民向量进行比较。

另一件事是将名称存储在BestMatches列表中。 best_candidates谓词必须对每个候选矢量进行评分,将这些分数保持在某个位置,然后必须找到最佳分数,然后必须通过原始候选名称并添加最佳分数。分数。

建议添加一个谓词来完成第一部分:

% Score all vectors, returning a list of scores.
% score_vectors(VoterVector, AllVectors, AllScores)
score_vectors(V, [], []).
score_vectors(V, [H|T], [SH, ST]) :-
    ... score V against H, matching the result against SH.
    ... recurse on T and ST.

(使用...填写两行)然后使用简单谓词从AllScores中找到最高分数(或者可能有内置谓词来执行此操作)。

然后创建另一个谓词,迭代所有的向量和分数,并选择那些符合最佳分数的谓词:

% Pick best candidates.
% pick_best(AllVectors, AllScores, BestScore, BestNames).
pick_best([], [], BS, []).
pick_best([H|T], [SH|ST], BS, [Name|NT]) :-
    H = [Name|Values],
    SH >= BS.
pick_best([H|T], [SH|ST], BS, NT) :-
    H = [Name|Values],
    SH < BS.

然后从这三个步骤构建best_candidates

best_candidates(VoterVector, CandidateVectors, BestNames) :-
    score_vectors(VoterVector, CandidateVectors, Scores),
    maximum(Scores, BestScore),
    pick_best(CandidateVectors, Scores, BestScore, BestNames).

答案 1 :(得分:1)

我将展示在SWI-Prolog库(aggregate)的帮助下实施的解决方案。

:- [library(aggregate)].

best_candidates(Votes, Candidates, Best) :-
    maplist(count_matched(Votes), Candidates, NamesCounted),
    keysort(NamesCounted, BestDown),
    reverse(BestDown, Best).

count_matched(Votes, [Name|ThisVotes], MatchCount-Name) :-
    aggregate_all(sum(V * T),
        ( nth1(I, Votes, V),
          nth1(I, ThisVotes, T)
        ), MatchCount).

test(BestMatches) :-
    best_candidates(
         [           0,   0,   0,   1,   1,   1,  -1,  -1,  -1,   1],
        [[adams   ,  1,   1,   1,   1,   1,   1,   1,   1,   1,   1],
         [grant   , -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1],
         [polk    ,  1,  -1,   1,  -1,   1,  -1,   1,  -1,   1,  -1],
         [jackson ,  1,   0,   1,   0,   1,   0,   1,   0,   1,   0],
         [taft    ,  0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1],
         [ford    ,  1,   1,   1,   1,   0,   0,   0,   0,   0,   0],
         [madison ,  0,   0,   0,   1,  -1,   0,   0,  -1,   1,   1]],
        BestMatches),
    BestMatches = [_-A, _-B, _-C|_],
    writeln([A, B, C]).

测试输出:

?- test(L).
[madison,ford,adams]
L = [1-madison, 1-ford, 1-adams, -1-jackson, -1-grant, -2-taft, -3-polk].