簡體   English   中英

Prolog初學者:如何為謂詞中的每個變量制作唯一的值

[英]Prolog Beginner: How to make unique values for each Variable in a predicate

我有一個序言謂詞:

Add( [A|B] , Answer ) :-
    ...
    ~ Add everything in the list to come up with answer
    ...

我現在想實現AddUnique ,它將為列表中的所有內容返回唯一值, 除非我兩次給變量賦值。


以下是邏輯上等效的內容:

?- AddUnique([A, B, C], 10). 等效於: ?- Add([A, B, C], 10), A != B, B != C, A != C.

和:

?- AddUnique([A, B, B], 10). 等價於: ?- Add([A, B, B], 10), A != B.

也:

?- AddUnique([A, B, B], 10). 等於: ?- Add([A, B, B], 10), A != B, B!=B.


如果?- AddUnique([A,B,C,D], 4). 給定它應該返回false,因為它不能帶有加到4的唯一正整數。

如果?- AddUnique([A,A,A,A], 4). 給定它應該返回A=1


問題 :如何在謂詞內部移動A != B, B != C, A != C.邏輯而無需執行類似A != A

Khm ...您應該了解doStuff(A,B,C,D)doStuff(A,A,B,B)意思。 首先是要統一值A .. D與這使得適當的值doStuff/4到達目標。 第二個等於A=B, C=D, doStuff(A,B,C,D)doStuff(A,B,C,D), A=B, C=D (但最后一個變體可能會導致回溯)。 因此,我希望您理解不要在doStuff/4內完成unique/1 ,因為它超出了限制。 因此,您應該使用doStuff(A,B,C,D), unique([A,B,C,D])doStuff(A,A,B,B), unique([A,B])

我不知道您如何讀A is not B ...無論如何,您可以將unique/1定義為

not_unique([H|T]):- member(H, T) ; not_unique(T).
unique(L):- not(not_unique(L)).

給定您對addUnique/2謂詞的描述,可以使用約束邏輯編程來實現解決方案。 不是初學者的東西,但是我還是會發布一個解釋。

首先,可能有必要查找什么是約束邏輯編程,以及如何使用實現(例如SWI-PL clpfd )。 基本上,約束邏輯編程(尤其是有限域求解器)將允許您在輸入列表上的變量上為addUnique/2指定以下約束:

  1. 輸入列表中的變量如何綁定到某些數值(即,從0到指定值的整數)
  2. 輸入列表中的不同變量如何不能同時綁定到相同的值(即,!=不同處)
  3. 輸入列表中的變量加上所有數字的總和如何必須等於指定的值(即,變量可以在上面的1中取的最大值)。

這些規范一起使基礎的約束求解器可以自動確定在上述約束條件下變量可以同時采用的允許值,從而為您提供解決方案(可能有多個,一個或沒有)。

這是在SWI-PROLOG中使用上述約束求解器(clpfd求解器)的解決方案:

:- use_module(library(clpfd)).  % import and use the constraint solver library

addUnique([A|As], Val) :-
    unique_vars([A|As], UVs),  % determine all unique variables
    UVs ins 0..Val,            % (1) domain of all unique variables is 0 to Val
    pairwise_inequ(UVs),       % (2) all unique variables are pairwise !=
    construct_sum_constr(As, Val, A, Program),  % (3) construct the sum constraint
    Program,              % assert the sum constraint
    label(UVs).           % label domains to enumerate a solution (backtracks)

% predicate to return a list of unique vars, if present
unique_vars([], []).
unique_vars([V|Vs], [V|Uniq]) :-
    var(V),
    \+ var_memberchk(V, Vs), !,
    unique_vars(Vs, Uniq).
unique_vars([_|Vs], Uniq) :-
    unique_vars(Vs, Uniq).

% predicate to test if a variable appears in a list (possibly including variables)
var_memberchk(V0, [V1|_]) :- 
    V0 == V1, !.
var_memberchk(V0, [_|V1s]) :- 
    var_memberchk(V0, V1s).

% create constraints that assert each in the input list != to each other
pairwise_inequ([]).
pairwise_inequ([V|Vs]) :-
    map_inequ(Vs, V),
    pairwise_inequ(Vs).

% predicate to pairwise assert inequality between all list members
map_inequ([], _).
map_inequ([V1|V1s], V0) :-
    V0 #\= V1,   % the inequality constraint
    map_inequ(V1s, V0).

% predicate to construct a summation constraint, whereby all variables in the 
% input list are constructed into a sum with +/2 and finally equated to a value
construct_sum_constr([], Val, Sum, (Sum #= Val)).
construct_sum_constr([V|Vs], Val, Sum, Program) :-
    construct_sum_constr(Vs, Val, (V + Sum), Program).

運行此代碼,例如,將為您提供:

?- addUnique([A,B,B], 6).
A = 0,
B = 3 ;
A = 4,
B = 1 ;
A = 6,
B = 0.

; 列舉了變量之間允許的綁定的下一個解決方案。 請注意, AB絕不會根據需要采用相同的值,但是輸入列表中所有出現的內容總和為6 另一個查詢:

 ?- addUnique([A,A,A],4).
false.

結果是失敗的,因為找不到單個整數來綁定到A ,該A加起來總計為4 ,而:

 ?- addUnique([A,A,A,A],4).
A = 1.

...符合預期 另外,您想嘗試:

?- addUnique([A,B,C,D],4).
false.

同樣,這里的結果是失敗的,因為所有變量ABCD都被斷言為不同,並且不能全部綁定為1

編輯 PS。 ony也想嘗試:

?- addUnique([A,A,A,1],4).
A = 1.

對上述代碼的簡單修改可確保在調用ins聲明域時僅使用變量(而不是輸入列表中的任何數字)。

這是我想出的解決方案。 它將只將輸入分配為小於10的數字,但效果很好!

addUnique( A, Answer ) :- 
    used(A,[0,1,2,3,4,5,6,7,8,9],_),
    add(A,Answer).

add( [A|B] , Answer ) :-
    ~ Add everything in the list to come up with answer ~.


% ================================
% Ensures that all variables are unique.  
% ================================

% Base case: Assigned variables unique values
used([], Nin, Nin).

% Have already assigned a value to this variable
used([A|B], Nin, Nout) :-
        integer(A),
        helper(B,Nin,Nout).

% Have not assigned a value to this variable yet
% Assign it and remove it from the list.  
used( [A|B] , Nin, Nout) :-
        member(A,Nin),
        delete(Nin,A,Temp),
        helper(B,Temp,Nout).

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM