2015-10-02 6 views
2

Я пытаюсь решить множество проблем, подобных проблеме Einsten, используя пролог.proog clpfd: создание арифметических ограничений из данных

Мой вход состоит из двух списков:

  1. список доменов. Например: [[домен (торговая марка), volkswagen, gm, audi], [домен (страна), германия, испания, Италия]].
  2. Список ограничений: [[=, spain, [+, gm, 1]], [=, germany, volkswagen], [=, italy, 2]]. Это означает: испания = г + 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). 

дает

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

Простое обобщение выраж/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). 

, но обратите внимание на разницу: ограничения/2 сообщения фактических ограничений, в то время как выражение/3 просто перевести синтаксическое дерево.