How to prevent a prologue from indenting where it should not

I am trying to solve a CSP where I need to distribute cocktails over bartenders so that each bartender has no more than one cocktail, and all the cocktails are given a bartender. I solved this by creating a list of clpfd variables, first providing them with the full domain of all the bartenders, and then deleting all the bartenders who do not know how to make this cocktail.
My code works, but there is one problem: it is too slow. If I look in the profiler, remove_domain is called 2,000 times (for the input that I give to my program), while the repetition statistics is> 100,000. What do I need to change in one of these functions (or both) so that the prolog does not need in retreat?

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 already read this related question , but I am using the latest version of Windows SWI-Prolog (5.10.5), so this should not be a problem here.

+2
source share
1 answer

You don’t need so much !/0 : Prolog can often say that your predicates are deterministic.

Let me first suggest the next version of your code. It uses names that are more relational, does not contain !/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 up and not down to list the bartenders (which are just lists of cocktails that they can mix), as this seems more natural. I was also able to omit (\+)/1 by simply switching if-then-else branches.

An example query showing that a 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 a third bartender, etc.

I think this part of your program may not be responsible for the slow performance that you are describing. Perhaps other parts of your program (inadvertently) are not determinate? Maybe try different labeling strategies or other restrictions? We can help you more if you post more contexts.

+2
source

Source: https://habr.com/ru/post/983979/


All Articles