Prolog recursion doesn't work the other way - prolog

I am learning Prolog and I got stuck in the code where the knowledge base and base rules are:
rectangle(a1, 3, 5). %Name,Width,Height
rectangle(a2, 1, 2).
rectangle(a3, 4, 3).
calcWH(T,C) :-
rectangle(T,W,_), C is W. % finds the width of the rect.
The recursive part is:
calcWTH([],0). % Base case
calcWTH([H | T ] ,K) :-
length([H|T],L),
L =< 3,
calcWTH(T,M),
calcWH(H,O),
K is O+M.
What I want to do with this code is, with calcWTH I want to calculate total width of the list of rectangles. For example
calcWTH([a1,a2,a3],A)
returns 8, as expected. The thing I'm puzzled is that this code only works for one way, not the other. For example when I make a query like
calcWTH(A,3)
It first finds A= [a1], then A=[a2,a2,a2], and afterwards I expect the program to stop because of the part length([H|T],L), L =< 3 But It gets into a loop indefinitely. What am I missing here?

Think about what this is doing:
length([H|T],L), L =< 3
Make a list
Check its length is less than 3, if it is - then success, other wise back track to length/2 and try making another list and then check if that list is length is less than 3.
But we know that list/2 is creating lists in order of larger size,
so we know that if list of length 3 fails, then the next list
created on back tracking will be bigger and all other lists.. but
prolog does not know that. You could imagine writing a length
predicate that searchs for lists in a differnt order, maybe
randomly, or from a predefined big size to ever smaller lists.
Then we would want the backtracking to work as is.
Anyway that is why you get infinite recursion, it will keep trying new lists, of ever increasing size.
You might find adding constraints is a good way to solve your problem:
Using a constrained variable with `length/2`

Related

Prolog pathfinder

I'm interested in pathfinder stuff and found a cool example on a site from 2011 but there isn't any explanation for the code. I understand what it does but don't understand how the steps work. So, for example these are the edges:
edge(1,2).
edge(1,4).
edge(2,4).
edge(3,6).
edge(3,7).
edge(4,3).
edge(4,5).
edge(5,6).
edge(5,7).
edge(6,5).
edge(7,5).
edge(8,6).
edge(8,7).
and with this I can tell if there is path between them:
path(X,Y,[X,Y]):- edge(X,Y).
path(X,Y,[X|Xs]):- edge(X,W), path(W,Y,Xs).
The output is something like this:
path(1,6,Xs).
Xs = [1,2,4,5,6];
Xs = [1,4,5,6];
...
But how does it exactly work?
What does [X,Y] do in the first line and what happens in the second?
The crucial thing to understand in this example is how recursive predicates work. First of all, recursion always needs a recursion step (recursive use of the current predicate), and a recursion anchor (the step where the recursion stops). The resolution algorithm is a depth-first search, and whereever there are multiple options to choose from (i.e., a ; or different rules or facts with the signature), the interpreter chooses from top to bottom and from left to right. To avoid infinite evaluations, the recursion anchor needs to be on the top like it is here, and the recursion step should be on the right of the second rule.
In the above example, the recursion stops when there is a direct edge between Xand Y, because that's where the path ends. Keep in mind that the rules are implications from right to left. As the third parameter is an output argument (the result you want to get), it needs to be initialized first in the anchor. [X,Y] does that by starting it with a list that contains the last two elements of the path. The rule is equivalent to the following:
path(X,Y,Result):- edge(X,Y), Result = [X,Y].
The second rule aims to find intermediate path elements: It assumes there is an edge(X,W) to an intermediate element W, and then a path from W to Y. The interpreter will try every edge from X to possible Ws. If there exists a path from a W to Y, there also is a path from X to Y, and the second rule becomes true for that step. The result of the recursive use to the predicate (the path list in the third parameter) will be Xs. So all that needs to be done in the current step is to add the X to the result list ([X|Xs]). Again, that is equivalent to:
path(X,Y,Result):- edge(X,W), path(W,Y,Xs), Result=[X|Xs].
Long story short: The resulting list is started with the last two elements in the recursion anchor, which then gets passed backwards through all recursive steps, and each step add its current X to the front to the list.
Of course recursion can still be infinite when there are cycles in the data (and paths) like in the example. If you want to avoid such cycles (and likely unwanted solutions such as paths where elements appear multiple times), you can keep track of the elements already visited:
path(X,Y,[X,Y],V):- \+member(X,V),\+member(Y,V),edge(X,Y).
path(X,Y,[X|Xs],V):- \+member(X,V),edge(X,W), path(W,Y,Xs,[X|V]).
In this solution, the list in the additional forth parameter collects the items already visited in an additional list. With \+member(X,V) it can be checked if the current X is already contained in V. There are other ways this can be implemented, for example by just using V as a result an reverting it in the anchor. V needs to be initialized in the query with an empty list:
?- path(1,6,R,[]).
R = [1, 2, 4, 3, 6] ;
R = [1, 2, 4, 3, 7, 5, 6] ;
...

Change list domain swi-prolog clpfd

I'm using SWI-Prolog with clpfd library. The problem is that I generate a list of length N with items in 1..2^(N-1), constraining this list to have some properties and calculating the maximum of the ones that verify the constraint. After that I have to find the minimum of these maxima but there are too many cases to evaluate and Prolog ends to freeze.
maxConstrain(N,Max) :-
listN(List,N),
label(List),
constrain(List),
max_list(List,Max).
minMaxConstrain(N,M) :-
findall(Max,maxConstrain(N,Max),Maxs), min_list(Maxs,M).
listN(-List,+N) generate a list with N items in 1..2^(N-1).
maxConstrain(+N,-Max) gives the maximum of List if it verify the constraint.
minMaxConstrain(+N,-M) gives the minimum of all the evaluations of maxConstrain(N,Max).
Since I need the minimum of the maxima I thought to scale down the domain of the lists whenever I find a valid list with a maximum less than the original one. For example if I have N=4 the elements of the list will be in 1..8. Let's say I get two lists List1 and List2 with maximum 8 and 7 respectively. Now I have that every other valid list that contains 8 will be rejected since I have found List2 with the maximum = 7 that is less than 8. So my idea is to reset the range of the domain every time I find a maximum less than the previous. For example if the current domain is 1..Max1 and then I find Max2 < Max1 then I will set the domain to 1..Max2.
Is it possibile to do this?
The idea that you describe is what branch-and-bound algorithms do: you prune those parts of the search that cannot possibly lead to a better solution than the best one you have found so far. Constraint solvers normally provide this functionality in some form.
For example, in ECLiPSe, this is provided by library(branch_and_bound), and you would formulate your problem like
:- lib(ic).
:- lib(branch_and_bound).
min_of_max(N, Max) :-
length(Xs, N),
Xs #:: 1..2^(N-1),
constrain(Xs),
Max #= max(Xs),
bb_min(labeling(Xs), Max, _).
By wrapping the bb_min/3 call around the labeling/1 search routine, any attempt to create a list whose maximum is greater or equal than the smallest maximum found so far will lead to failure. By default, this is achieved by dynamically reducing the upper bound of Max (similar to the procedure you outlined in your question), but other strategy-options are available.

Implement a rule in prolog called "stepWith", that takes three parameters, a list L and two integers i and j [duplicate]

This question already has an answer here:
how should i design this predicate in prolog?
(1 answer)
Closed 7 years ago.
Implement a rule called "stepWith", that takes three parameters,
a list L and two integers i and j. The rule returns true, if the
value i can be "stepped" into the value j, using only legal "steps".
The list L provides a set of integers that make up the legal steps.
For example, stepWith([7,12,19],6,32) would return true, because,
starting at 6, there exists at least one sequence of additions using
only the numbers in the list (7, 3, and 12), producing 28. Namely:
6+7+7+12 = 32.
By contrast, stepWith([7,12,19],6,31) would be an example that should
return false, since there is no sequence of additions starting from 6,
and using only the values 7, 12, and 19, that results in 31.
Make sure that your rule works for various values, and various size
lists for L. You can assume that all of the integers are positive,
and that i is less than j.
*** CLARIFICATION ***
The value i, in the above description, can only be included in
the addition once, at the very beginning. The numbers in the
list L can be used as many times as necessary (or zero times).
this is what i have so far but its just goes through the first element of the list and subtracts it until it reaches 0. I need it to go through each element to find the combination that to get to the given value.
stepWith(L,I,J) :- Z is J-I, step(L,Z).
step([F|L],Z) :- N1 is Z - F, goThrough(N1,L).
step([],0).
goThrough(X,[X|Y]).
goThrough(X,[M|N]) :- goThrough(X,N).
I don't quite get why you introduce that goThrough predicate.
Without that you almost got the solution, just two things to correct:
step(A,0) is true for whatever A you get, not only the empty list (because of the rules you describe, when you reach 0, it does not matter if there are some numbers you havent tried).
recurse step in two ways, by passing just L, and by passing [F|L], meaning that if you tried one number, you don't use it anymore, or you can use it more times.
Here a possible solution:
stepWith(L,I,J) :- Z is J-I, step(L,Z).
step(_,0).
step([F|L],Z) :- Z > 0, step(L,Z).
step([F|L],Z) :- Z > 0, Z1 is Z-F, step([F|L],Z1).
Note that I also added Z > 0 to guarantee universal termination. If you remove Z > 0, then the order of predicates becomes important, and if you move the base case after the recursive rules, you can get non-terminating behavior. (as an exercise, try to remove it and experiment yourself, since you are learning Prolog anyway :-)).

Find best result without findall and a filter

I'm in a bit of pickle in Prolog.
I have a collection of objects. These objects have a certain dimension, hence weight.
I want to split up these objects in 2 sets (which form the entire set together) in such a way that their difference in total weight is minimal.
The first thing I tried was the following (pseudo-code):
-> findall with predicate createSets(List, set(A, B))
-> iterate over results while
---> calculate weight of both
---> calculate difference
---> loop with current difference and compare to current difference
till end of list of sets
This is pretty straightforward. The issue here is that I have a list of +/- 30 objects. Creating all possible sets causes a stack overflow.
Helper predicates:
sublist([],[]).
sublist(X, [_ | RestY]) :-
sublist(X,RestY).
sublist([Item|RestX], [Item|RestY]) :-
sublist(RestX,RestY).
subtract([], _, []) :-
!.
subtract([Head|Tail],ToSubstractList,Result) :-
memberchk(Head,ToSubstractList),
!,
subtract(Tail, ToSubstractList, Result).
subtract([Head|Tail], ToSubstractList, [Head|ResultTail]) :-
!,
subtract(Tail,ToSubstractList,ResultTail).
generateAllPossibleSubsets(ListToSplit,sets(Sublist,SecondPart)) :-
sublist(Sublist,ListToSplit),
subtract(ListToSplit, Sublist, SecondPart).
These can then be used as follows:
:- findall(Set, generateAllPossibleSubsets(ObjectList,Set), ListOfSets ),
findMinimalDifference(ListOfSets,Set).
So because I think this is a wrong way to do it, I figured I'd try it in an iterative way. This is what I have so far:
totalWeightOfSet([],0).
totalWeightOfSet([Head|RestOfSet],Weight) :-
objectWeight(Head,HeadWeight),
totalWeightOfSet(RestOfSet, RestWeight),
Weight is HeadWeight + RestWeight.
findBestBalancedSet(ListOfObjects,Sets) :-
generateAllPossibleSubsets(ListOfObjects,sets(A,B)),
totalWeightOfSet(A,WeightA),
totalWeightOfSet(B,WeightB),
Temp is WeightA - WeightB,
abs(Temp, Difference),
betterSets(ListOfObjects, Difference, Sets).
betterSets(ListOfObjects,OriginalDifference,sets(A,B)) :-
generateAllPossibleSubsets(ListOfObjects,sets(A,B)),
totalWeightOfSet(A,WeightA),
totalWeightOfSet(B,WeightB),
Temp is WeightA - WeightB,
abs(Temp, Difference),
OriginalDifference > Difference,
!,
betterSets(ListOfObjects, Difference, sets(A, B)).
betterSets(_,Difference,sets(A,B)) :-
write_ln(Difference).
The issue here is that it returns a better result, but it hasn't traversed the entire solution tree. I have a feeling this is a default Prolog scheme I'm missing here.
So basically I want it to tell me "these two sets have the minimal difference".
Edit:
What are the pros and cons of using manual list iteration vs recursion through fail
This is a possible solution (the recursion through fail) except that it can not fail, since that won't return the best set.
I would generate the 30 objects list, sort it descending on weight, then pop objects off the sorted list one by one and put each into one or the other of the two sets, so that I get the minimal difference between the two sets on each step. Each time we add an element to a set, just add together their weights, to keep track of the set's weight. Start with two empty sets, each with a total weight of 0.
It won't be the best partition probably, but might come close to it.
A very straightforward implementation:
pair(A,B,A-B).
near_balanced_partition(L,S1,S2):-
maplist(weight,L,W), %// user-supplied predicate weight(+E,?W).
maplist(pair,W,L,WL),
keysort(WL,SL),
reverse(SL,SLR),
partition(SLR,0,[],0,[],S1,S2).
partition([],_,A,_,B,A,B).
partition([N-E|R],N1,L1,N2,L2,S1,S2):-
( abs(N2-N1-N) < abs(N1-N2-N)
-> N3 is N1+N,
partition(R,N3,[E|L1],N2,L2,S1,S2)
; N3 is N2+N,
partition(R,N1,L1,N3,[E|L2],S1,S2)
).
If you insist on finding the precise answer, you will have to generate all the partitions of your list into two sets. Then while generating, you'd keep the current best.
The most important thing left is to find the way to generate them iteratively.
A given object is either included in the first subset, or the second (you don't mention whether they're all different; let's assume they are). We thus have a 30-bit number that represents the partition. This allows us to enumerate them independently, so our state is minimal. For 30 objects there will be 2^30 ~= 10^9 generated partitions.
exact_partition(L,S1,S2):-
maplist(weight,L,W), %// user-supplied predicate weight(+E,?W).
maplist(pair,W,L,WL),
keysort(WL,SL), %// not necessary here except for the aesthetics
length(L,Len), length(Num,Len), maplist(=(0),Num),
.....
You will have to implement the binary arithmetics to add 1 to Num on each step, and generate the two subsets from SL according to the new Num, possibly in one fused operation. For each freshly generated subset, it's easy to calculate its weight (this calculation too can be fused into the same generating operation):
maplist(pair,Ws,_,Subset1),
sumlist(Ws,Weight1),
.....
This binary number, Num, is all that represents our current position in the search space, together with the unchanging list SL. Thus the search will be iterative, i.e. running in constant space.

prolog: subsets of length k

in class we went over the subset_of/2 predicate that my teacher gave as follows:
subset_of([],[]).
subset_of([X|Xs],Zs):-subset_of(Xs,Ys),maybe_add(X,Ys,Zs).
maybe_add(_,Ys,Ys).
maybe_add(X,Ys,[X|Ys]).
subsets_of(Xs,Xss):-findall(Ys,subset_of(Xs,Ys),Xss).
He then asked us to change it to only give the subsets of some length K (but not by using length/2, by directly finding a recursive definition). My first attempt was to split up the subset_of call into one that adds the extra element and one that does not (instead of having the maybe_add call) and to keep track of the length of the list that was passed and check at the end, but this did not work as planned at all.
subset_of(K, 0, [],[]).
subset_of(K, Len, [X|Xs],Zs):-
L1 is Len - 1,
subset_of(K, L1, Xs, Zs),
L1 == K.
subset_of(K, Len, [X|Xs],Zs):-
L1 is Len - 1,
subset_of(K, L1, Xs,Ys),
do_add(X, Ys, Zs),
Len == K.
subsets_of(K,Xs,Xss):-
length(Xs, Len),
findall(Ys,subset_of(K, Len, Xs,Ys),Xss).
I am NOT asking for the correct code to solve this, but only a push in the right direction so I can keep trying to figure it out. This is my first time with a declarative languange and I am pretty confused.
If you don't want a direct answer, than I'd say that it can be done much simpler. I've got 3 rules in my solution. However I don't use this additional maybe_add formula or anything that resambles it. If you really need it, it can be used and it takes 5 arguments then - 3 input arguments and 2 output arguments. This reduces the number of rules for subset_of to only 2, just as in the original solution. They are quite similar after all.
Also watch out for repetitions. I think subset_of(0, _, []) as suggested in other answer may be a way that leads to repetitions. However there might be a correct solution that incorporates it, I'm not sure that there isn't.
Think of it as a proof of correctness. Say you wanted to prove recursively that one set is a K-element subset of another. How would you go about it. Look at the implications that you used. How can you turn them into Prolog rules?
Not using maybe_add seems like a good idea. However, you don't need two extra arguments: one will do. Your base clause would be
subset_of(0, _, []).
i.e., the empty set is a zero-element subset of anything. Of the two recursive clauses, one would look for K-1-element subsets, the other for K-sized subsets.

Resources