prolog clpfd:从数据创建算术约束

时间:2015-10-02 04:12:01

标签: prolog swi-prolog clpfd

我正在尝试使用prolog解决类似于Einsten问题的一组问题。

我的输入包含两个列表:

  1. 域名列表。例如:[[domain(brand),volkswagen,gm,audi],[domain(country),Germany,spain,italy]]。
  2. 约束列表:[[=,西班牙,[+,gm,1]],[=,德国,大众],[=,意大利,2]]。这意味着:西班牙= gm + 1,德国=大众汽车,意大利= 2.
  3. 我可以轻松地解决这个问题:

    puzzle(Spain,Italy,Germany,Volkswagen,Gm,Audi,X):-
    Country = [Spain, Italy, Germany], ins(Country, 1..X), all_different(Country),
    Brand = [Volkswagen, Gm, Audi], ins(Brand, 1..X), all_different(Brand),
    Spain #= Gm + 1,
    Germany #= Volkswagen,
    Italy #= 2.
    

    并致电:

    275 ?- puzzle(Spain, Italy,Germany, Volkswagen, Gm, Audi,3).
    Spain = Audi, Audi = 3,
    Italy = Gm, Gm = 2,
    Germany = Volkswagen, Volkswagen = 1.
    

    我的问题:

    1. 从输入数据动态创建域的方法是什么?在这个例子中,我只有2个域(国家,品牌),但有另外5个或6个域的输入。因此,我怎样才能使域的数量和大小变量?
    2. 我如何从列表中动态创建约束?如何将约束列表中的常量连接到上一个问题的变量?
    3. 总之,如何构建仅依赖于输入的解算器?

1 个答案:

答案 0 :(得分:2)

简单易懂的翻译

puzzle(Ds, Cs, Symbols) :-
    maplist(make_vars, Ds, Syms, Vars),
    append(Syms, Symbols),
    maplist(constraints(Symbols), Cs),
    append(Vars, Store),
    label(Store).

make_vars([domain(_)|Names], NamesVars, Vars) :-
    length(Names, N),
    length(Vars, N),
    Vars ins 1 .. N,
    all_distinct(Vars),
    pairs_keys_values(NamesVars, Names, Vars).

constraints(Symbols, [=, L, R]) :-
    expr(L, Symbols, X),
    expr(R, Symbols, Y),
    X #= Y.

expr(N, _, N) :- number(N).
expr(S, Symbols, X) :- memberchk(S-X, Symbols).
expr([+, L, R], Symbols, X + Y) :-
    expr(L, Symbols, X),
    expr(R, Symbols, Y).

产量

[volkswagen-1,gm-2,audi-3,germany-1,spain-3,italy-2]

expr / 3的简单推广:

expr([Op, L, R], Symbols, ClpF) :-
    expr(L, Symbols, X),
    expr(R, Symbols, Y),
    ClpF =.. [Op, X, Y].

所以它接受其他二元运算符。类似的也可以应用于约束/ 2:

constraints(Symbols, [Op, L, R]) :-
    expr(L, Symbols, X),
    expr(R, Symbols, Y),
    memberchk((Op, OpC), [(=, #=), (<, #<)]),
    call(OpC, X, Y).

但请注意区别:constraints / 2 发布实际约束,而expr / 3只是翻译语法树。