2015-10-02 21 views
2

我正在嘗試使用prolog解決一組類似於Einsten問題的問題。prolog clpfd:從數據創建算術約束

我輸入由兩個列表:

  1. 域列表。例如:[[域名(品牌),大衆汽車,gm,奧迪],[域名(國家),德國,西班牙,意大利]]。約束列表:[[=,spain,[+,gm,1]],[=,germany,volkswagen],[=,italy,2]]。這意味着:西班牙= GM + 1,德國=大衆,意大利= 2

我可以很容易地解決這個問題硬編碼它:

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. 如何從列表中動態創建約束條件?如何將常量從約束列表連接到前一個問題的變量?

總之,如何構建一個只依賴於輸入的求解器?

回答

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

產生EXPR/3的

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

易概括:

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

但注意區別:限制/ 2 職位實際的約束,而EXPR/3只是翻譯語法樹。