PROLOG CLPFD minimize expression - prolog

I have a list of variables L over a finite domain. For example:
:- use_module(library(clpfd)).
example :-
L = [_,_,_],
L ins 1..10,
...
Moreover, I have a predicate
pred(L,C)
that, for any assignment of L to values of the domain, gives a cost C.
The question is how to use the labeling feature of CLPFD to find the assignment of L that minimizes C.
example :-
L = [_,_,_],
L ins 1..10,
pred(L,C),
labeling([min(C)],L),
write(L).
Doesn't work. It just chooses the first assignment (i.e. [1,1,1]).

Most likely, C is already instantiated at the time labeling/2 is called in this example. The goal then reads similar to:
labeling([min(1)], Ls)
and of course, no room is left for actually minimizing C here during labeling/2.
To make this work, you have to formulate pred/2 such that C is deterministically related to the variables Vs via constraints. For example:
sum(Vs, #=, C),
labeling([min(C)], Vs)
works as intended if the cost function is the sum of the finite domain variables Vs.
I illustrate my further suggestions by rewriting your example as:
example(Ls) :-
Ls = [_,_,_],
Ls ins 1..10,
pred(Ls, C),
labeling([min(C)], Ls).
Notice in particular:
I do not need to use write/1 because the Prolog toplevel will display the solution for me when I query ?- example(Ls).
I let the names of variables that denote lists end with an s in analogy of building an English plural.

Related

Creating Metavariables in Prolog

I am working with implementing a unification algorithm for a term rewriting system in Prolog. To fully implement this, I need a predicate substituting out a given subterm for another term. Unfortunately, the way that Prolog instantiates fresh variables prevents the system from successfully be able to achieve this. I have some built in operators, star and divi (really just representing the * and / symbols, but in prefix form). My substitute predicate is made up of the following predicates:
replace(A,B, [], []).
replace(A,B, [H|T], [B|T2]) :- (H==A)->replace(A, B, T, T2).
replace(A,B, [H|T], [H|T2]) :- (H\==A)->replace(A, B, T, T2).
replace_lst([], [H|T], [H2|T2]).
replace_lst([H1|T1], [H|T], [H2|T2]) :-
arg(1,H1,X),
arg(2,H1,Y),
replace(X,Y,[H|T],[H2|T2]),
replace_lst(T1,[H|T],[H2|T2]).
substitute([H|T],A,X):-
A=..List,
replace_lst([H|T],List,C),
X=..C.
Where this runs into trouble is that, for instance, the terms star(X,X) and star(Y,Y), are, by the logic of my rewrite system, structurally equivalent and require no such substitution. However, comparing these two terms using the unifiable predicate will lead Prolog to attempting unification for the two, and the resulting term is no longer equivalent in structure to the original star(X,X) structure. Therefore, I attempted to check for term equality through their structure, but this leads to another can of worms in which, for instance, my rewrite system contains the rewrite rule:
star(X,X)==>X.
However,attempting to substitute based on the variant equality =#= operator leads to the issue of Prolog seeing two differently instantiated terms with the same structure as the same term. Therefore, defining a variant-based subtitution predicate like so:
variant_replace(A,B, [], []).
variant_replace(A,B, [H|T], [B|T2]) :- (H=#=A)->variant_replace(A, B, T, T2).
variant_replace(A,B, [H|T], [H|T2]) :- (H\=#=A)->variant_replace(A, B, T, T2).
variant_replace_lst([], [H|T], [H2|T2]).
variant_replace_lst([H1|T1], [H|T], [H2|T2]) :-
arg(1,H1,X),
arg(2,H1,Y),
variant_replace(X,Y,[H|T],[H2|T2]),
variant_replace_lst(T1,[H|T],[H2|T2]).
variant_substitute([H|T],A,X):-
A=..List,
variant_replace_lst([H|T],List,C),
X=..C.
Leads to an issue where if I have some term:
star((star(X,Y),star(A,B))
and I want to substitute the star(X,Y) subterm with the following predicate:
?- variant_substitute([star(X,Y)=hole],star(star(X,Y),star(A,B)),D).
D = star(hole, hole) .
We can see Prolog, by the logic of the variant substitution predicate, will simply check for terms of a given structure, disregarding the actual variable instantiation. Therefore, I need a way to declare variables. What I desire is to have a system that is able to use metavariables declared in such a way each given term has up to N unique variables, ranging in value from V(0) to V(N-1). Ideally, such a system of metavariables would look like so:
substitute([star(v(0),v(1))=hole],star(star(v(0),v(1)),star(v(2),v(3))),D).
D = star(hole, star(v(2), v(3)))
I need Prolog to see terms denoted with v(#) as variables since I will need to use the unifiable predicate down the road to compare them to the original declaration of my rewrite rules, which is declared like so :
star(X,X) ==> X.
divi(X,X) ==> X.
divi(star(X,Y),Y) ==> X.
star(divi(X,Y),Y) ==> X.
star(X, star(Y,Z)) ==> star(star(divi(X,Z),Y),Z).
divi(X, star(Y,Z)) ==> star(divi(divi(X,Z),Y),Z).
star(X, divi(Y,Z)) ==> divi(star(star(X,Z),Y),Z).
divi(X, divi(Y,Z)) ==> divi(divi(star(X,Z),Y),Z).
What would be the best way to implement this format of metavariable in Prolog?

Getting a sorted, distinct list of integers in Prolog

I'm trying to do something very simple while learning Prolog. However I'm confused why this works:
?- length( L, 3 ),
maplist( member, L, [[1,2,3], [1,2,3], [1,2,3]] ),
sort( L, L ).
L = [1, 2, 3] ;
But this seemingly equivalent variation using clpfd doesn't:
?- use_module(library(clpfd)).
?- length( L, 3 ), L ins 1..3, sort( L, L ).
L = [_G5891, _G5894, _G5897],
_G5891 in 1..3,
_G5894 in 1..3,
_G5897 in 1..3.
This works:
?- length( L, 3 ), L ins 1..3, chain( L, #< ).
L = [1, 2, 3].
But this doesn't:
?- length( L, 3 ), L ins 1..3, chain( L, #=< ), all_different( L ).
L = [_G6519, _G6522, _G6525],
_G6519 in 1..3,
all_different([_G6519, _G6522, _G6525]),
_G6522#>=_G6519,
_G6522 in 1..3,
_G6525#>=_G6522,
_G6525 in 1..3.
Can anyone explain why the non-working examples don't give me the outcome I'm expecting?
As a side question, is there a more concise way to rewrite my maplist expression in the first example above?
CLP in Prolog
The system you are using (SWI-Prolog + library(clpfd)) is one example of the embedding of an integer finite-domain constraint solver into a Prolog system (some others are CHIP, ECLiPSe+fd/ic, B-Prolog, SICStus+clpfd). Such an embedding is very natural in the sense that many Prolog concepts map directly to concepts in Constraint Programming, giving us Constraint Logic Programming (CLP).
However, there are number of features of plain Prolog that should be avoided when using it for CLP. Among those are cuts (including the hidden ones in the if-then-else construct and the \+/2 negation), but also meta-logical operations as in your case. For our purposes, meta-logical means any primitive that treats variables as objects (rather than just as placeholders for values). Examples of these are var/1, ==/2, #</2, and indeed also sort/2.
Meta-logical primitives can already cause ugly effects in plain Prolog, e.g.
?- X\==Y, X=3, Y=3, X==Y.
Yes
but Prolog programmers have learned to use them correctly and avoid such problems. With CLP however, it is easier to fall into these traps because the execution control flow is much less obvious.
As to your examples, the first one works because sort/2 sorts lists of integers, no problem there. In the second case, sort/2 sorts a list of domain variables, resulting in a list of domain variables in an arbitrary, system-defined order. Once this is done, sort/2 considers its job done. If you later assign integer values to those ostensibly "sorted" variables, the sortedness of the list will not be checked again, and your program can now return unsorted integer lists as results.
The correct alternative is to use a sortedness check that involves only pure logical Prolog primitives and/or the constraint predicates defined by the CLP solver. You have already done that by using the chain/2 constraint in your third example.
Local Propagation and Search
In your last example you can observe the typical behaviour of a constraint solver based on local propagation: The answer you get is correct, but not very satisfactory. By analyzing the constraints more deeply, it is actually possible to infer that the only correct solution is [1,2,3], but the solver doesn't do that because it could be computationally expensive. But look what happens if you add just a little bit of information:
?- L=[_,Y,_], L ins 1..3, chain(L, #=<), all_different(L), Y=2.
L = [1, 2, 3],
Y = 2
Ass soon as the solver knows that Y is 2, the problem becomes easy enough for the solver to solve completely.
A solution for the general case is to systematically break down the problem into simpler sub-problems, making sure you cover everything. In other words, you add search, and the Prolog way to do search is with a disjunction. In the example, this could be a simple member(Y,[1,2,3]). Typically, you want to do the same for all the domain variables in your problem, just to be on the safe side. A CLP solver will give you a convenient primitive for this, e.g. in the case of clpfd
?- L=[_,_,_], L ins 1..3, chain(L, #=<), all_different(L), label(L).
L = [1, 2, 3] ;
false.
This is a general structure for CLP programs: first constraint setup, then search.
The built-in predicate sort/2 effectively sorts a list based on the term order defined over all terms including variables. For this reason this predicate cannot be considered to implement a concrete relation. Only in special cases like when the first argument is variable free (that is, ground(L) succeeds) and the term is acyclic (acyclic_term(L) succeeds), the built-in corresponds to the obvious relation.
Here is another such strange case sort([X,1],[1,1]) which succeeds, unifying X = 1.

How to prevent Prolog from backtracking where it shouldn't

I'm trying to solve a CSP where I need to distribute cocktails over bartenders so that each bartender has at most one cocktail and all cocktails are given a bartender. I solved it by creating a list of clpfd variables,first giving them the full domain of all bartenders and then removing all bartenders that don't know how to make that cocktail.
My code works, but there is one problem: it's too slow. If I look in the profiler, remove_domain gets called 2000 times(for the input I'm giving my program), while it's Redo statistic is >100 000.
What do I need to change in one of these functions(or both) so that prolog doesn't need to backtrack?
produce_domains(_,_,[],[]) :- !.
produce_domains(Bartenders,NBartenders,[Cocktail|Cocktails],[Var|Vars]) :-
Var in 1..NBartenders,
remove_domain(Bartenders,NBartenders,Cocktail,Var),!,
produce_domains(Bartenders,NBartenders,Cocktails,Vars),!.
remove_domain([],0,_,_) :- !.
remove_domain([Bartender|Bartenders],NBartenders,Cocktail,Var) :-
(\+ member(Cocktail,Bartender) -> Var #\= NBartenders;!),!,
NNBartenders is NBartenders - 1,
remove_domain(Bartenders,NNBartenders,Cocktail,Var),!.
I have already read this related question, but I am using the latest Windows build of SWI-Prolog(5.10.5), so that shouldn't be the problem here.
You do not need so many !/0: Prolog can often tell that your predicates are deterministic.
Let me first offer the following version of your code. It uses names that are more relational, contains no !/0 and uses higher-order predicates to make the code shorter.
:- use_module(library(clpfd)).
bartenders_cocktails_variables(Bs, Cs, Vs) :-
length(Bs, LBs),
maplist(bartenders_cocktail_variable(Bs, LBs), Cs, Vs).
bartenders_cocktail_variable(Bs, N, C, V) :-
V in 1..N,
foldl(compatible_bartender(C,V), Bs, 1, _).
compatible_bartender(C, V, Cs, N0, N1) :-
( member(C, Cs) -> true
; V #\= N0
),
N1 #= N0 + 1.
Notice that I am counting upwards instead of downwards to enumerate the bartenders (which are just lists of cocktails they are able to mix), since this seems more natural. I was also able to omit a (\+)/1 by simply switching the branches of the if-then-else.
Example query, showing that the predicate is deterministic in this use case:
?- bartenders_cocktails_variables([[a,b],[a,b],[x,y]], [x,a,b], Vars).
Vars = [3, _G1098, _G1101],
_G1098 in 1..2,
_G1101 in 1..2.
We see: Cocktail x must be mixed by the third bartender etc.
I think this part of your program may not be responsible for the slow performance you are describing. Maybe other parts of your program are (unintentionally) not deterministic? Maybe try different labeling strategies or other constraints? We may be able to help you more if you post more context.

How do I define a binary operation on a set of numbers in prolog?

How do I define a binary operation on a list in prolog and then check its properties such as closure , associative, transitive , identity etc. ? I am new to prolog.. I don't know whether it is the place to ask but I tried and I didn't come across anything somewhere.
In Prolog you define predicates, i.e. relations among a symbol (called functor) and its arguments.
A predicate doesn't have a 'return value', just a 'truth value', depending of whether it can be evaluated WRT its arguments. Then your question it's not easy to answer.
Associativity, transitivity, identity, are of little help when it come down to speaking about predicates. The first and most common property we wish to evaluate is termination, because Prolog control flow it's a bit unusual and can easily lead to infinite recursion.
Anyway, the simpler binary relation on a list is member/2, that holds when its first argument it's an element of the second argument (the list).
member(X, [X|_]).
member(X, [_|T]) :- member(X,T).
I can't see any benefit in assessing that it's not associative, neither transitive (its arguments are of different types !).
Common operations like intersection, union, etc typically needs 3 arguments, where the last is the result of the operation performed between 2 lists.
Identity in Prolog (that is an implementation of first order logic) deserves a special role. Indeed, the usual programming symbol = used to assess identity, really performs a (potentially) complex operation, called unification. You can see from the (succint) documentation page that it's 'just' a matching between arbitrary terms.
You could do something like this:
% Define sets I want to try
set7([0,1,2,3,4,5,6]).
% Define operations
% Sum modulo 7
sum7(X, Y, R) :-
R is (X+Y) mod 7.
% Normal sum
nsum(X, Y, R) :-
R is X + Y.
% A given set is closed if there is not a single case which
% indicates that it is not closed
closed(S, Operator) :-
\+ n_closed(S, Operator, _), !.
% This predicate will succeed if it finds one pair of elements
% from S which, when operated upon, will give a result R which
% is outside of the set
n_closed(S, Operator, R) :-
member(X, S),
member(Y, S),
Operation =.. [Operator, X, Y, R],
Operation,
\+ member(R, S).
When you execute it, you get these results:
| ?- set7(S), closed(S, sum7).
(1 ms) yes
| ?- set7(S), closed(S, nsum).
no
I'm not convinced my closure check is optimal, but it gives some ideas for how to play with it.

Predicate that succeeds if two or more results are returned

How to implement rule1 that succeeds iff rule2 returns two or more results?
rule1(X) :-
rule2(X, _).
How can I count the results, and then set a minimum for when to succeed?
How can I count the results, and then set a minimum for when it's true?
It is not clear what you mean by results. So I will make some guesses. A result might be:
A solution. For example, the goal member(X,[1,2,1]) has two solutions. Not three. In this case consider using either setof/3 or a similar predicate. In any case, you should first understand setof/3 before addressing the problem you have.
An answer. The goal member(X,[1,2,1]) has three answers. The goal member(X,[Y,Z]) has two answers, but infinitely many solutions.
So if you want to ensure that there are at least a certain number of answers, define:
at_least(Goal, N) :-
\+ \+ call_nth(Goal, N).
with call_nth/2 defined in another SO-answer.
Note that the other SO-answers are not correct: They either do not terminate or produce unexpected instantiations.
you can use library(aggregate) to count solutions
:- use_module(library(aggregate)).
% it's useful to declare this for modularization
:- meta_predicate at_least(0, +).
at_least(Predicate, Minimum) :-
aggregate_all(count, Predicate, N),
N >= Minimum.
example:
?- at_least(member(_,[1,2,3]),3).
true.
?- at_least(member(_,[1,2,3]),4).
false.
edit here is a more efficient way, using SWI-Prolog facilities for global variables
at_least(P, N) :-
nb_setval(at_least, 0),
P,
nb_getval(at_least, C),
S is C + 1,
( S >= N, ! ; nb_setval(at_least, S), fail ).
with this definition, P is called just N times. (I introduce a service predicate m/2 that displays what it returns)
m(X, L) :- member(X, L), writeln(x:X).
?- at_least(m(X,[1,2,3]),2).
x:1
x:2
X = 2.
edit accounting for #false comment, I tried
?- call_nth(m(X,[1,2,3]),2).
x:1
x:2
X = 2 ;
x:3
false.
with call_nth from here.
From the practical point of view, I think nb_setval (vs nb_setarg) suffers the usual tradeoffs between global and local variables. I.e. for some task could be handly to know what's the limit hit to accept the condition. If this is not required, nb_setarg it's more clean.
Bottom line: the better way to do would clearly be using call_nth, with the 'trick' of double negation solving the undue variable instantiation.

Resources