Prolog-SWI: procedure which removes one occurence - prolog

I have the next function from the book:
% Signature: select (X,HasXs,OneLessXs)/3
% purpose: The list OneLessXs is the result of removing
one occurrence of X from the list HasXs.
select(X,[X|Xs],Xs). *rule number 1*
select(X,[Y|Ys],[Y|Zs]) :- select(X,Ys,Zs). * rule number 2*
?- select(4,[2,3,2,4,5,2,4],X].
X=[2,3,2,5,2,4]
But I didn't understand how it finds the correct answer. After it removes all the Y=!X, It come to a rule number 1, with: Xs=4,5,2,4, then it return true. and what then? If it continue to rule 2, then he also remove the next "4". If it doesn't continue to rule 1, then How Zs is [2,3,2,5,2,4]? I think Im missing a basic rule.

You can understand why this is happening by thinking of how it's going to be executed.
So you have:
% I use K here instead of X, so there is no
% confusion with the X on the rules
select(4,[2,3,2,4,5,2,4], K).
First, it will check rule 1, but 4 != 2 so it will continue to rule 2. At rule 2, you have these "bindings":
X = 2
[Y | Ys] = [2, 3, 2, 4, 5, 2, 4] (which means Y = 2, Ys = [3, 2, 4, 5, 2, 4])
[Y | Zs] = [2 | Zs] (because Y was binded to 2)
And K is binded to [2 | Zs] and not just Zs. The next select call which will be select(4, [3, 2, 4, 5, 2, 4], Zs) finds Zs and so on. That's why the returned result is:
K=[2,3,2,5,2,4] and not K=[5, 2, 4] as you was expecting.

Related

Printing minimum answer as list?

I have a predicate min1([4,2,3,5],L). I want it to return the minimum number for each time the list is sent back as a tail. Example:
List Head|Tail Tail L
[4,2,3,5] [4,2,3,5] [2,3,5] 2
[2,3,5] [2,3,5] [3,5] 2
[3,5] [3,5] [5] 3
[5] [5] [] 5
My code:
min([X],[X]).
min([H|T],Min):-
min(T,TMin),
H=<TMin,
Min is H.
min([H|T],Min):-
min(T,TMin),
H>TMin,
Min is TMin.
min1([],[]).
min1([H|T],L):-
min([H|T],R),
write(R),
min1(T,R).
The problem that I am facing is with L. It does not print anything. When I use write(R), it's showing me the right result but I am unable to print it as a List in L. What should I correct?
?-min1([4,2,3,5],L).
223[5]
L = []
By removing write(R):
?-min1([4,2,3,5],L).
false
One of your problems is trying to understand your program using I/O. This is often not a very useful thing to do in Prolog. If you are interested in the suffixes of the list, even just for debugging, expose those suffixes as an argument of the predicate. This is much clearer than trying to print intermediate results. Because Prolog backtracks, it can be hard to understand what an intermediate result means, at what point it exists, and whether you can actually use it before backtracking makes it disappear.
Your other problem is trying to do too much at once. Take things step by step. Prolog is a language that is well suited for decomposing problems into tiny bits. It also often forces you to decompose a problem into tiny bits.
So, first: Enumerating a list's suffixes (including the list itself as a trivial suffix).
list_suffix(List, List).
list_suffix([_ | Suffix], SuffixOfSuffix) :-
list_suffix(Suffix, SuffixOfSuffix).
?- list_suffix([4, 2, 3, 5], Suffix).
Suffix = [4, 2, 3, 5] ;
Suffix = [2, 3, 5] ;
Suffix = [3, 5] ;
Suffix = [5] ;
Suffix = [].
Then, separately, computing the minimum of a list. Your implementation is almost OK for this, the first clause needed to unwrap [X] (though it could be more efficient by using an accumulator):
list_minimum([X], X).
list_minimum([H | T], Min):-
list_minimum(T, TMin),
H =< TMin,
Min is H.
list_minimum([H | T], Min):-
list_minimum(T, TMin),
H > TMin,
Min is TMin.
?- list_minimum([4, 2, 3, 5], Minimum).
Minimum = 2 ;
false.
Now, and only now, we are in a position to tackle the combined problem:
?- list_suffix([4, 2, 3, 5], Suffix), list_minimum(Suffix, Minimum).
Suffix = [4, 2, 3, 5],
Minimum = 2 ;
Suffix = [2, 3, 5],
Minimum = 2 ;
Suffix = [3, 5],
Minimum = 3 ;
Suffix = [5],
Minimum = 5 ;
false.
You can pack this up in a predicate definition:
list_suffix_suffixminimum(List, Suffix, SuffixMinimum) :-
list_suffix(List, Suffix),
list_minimum(Suffix, SuffixMinimum).
?- list_suffix_suffixminimum([4, 2, 3, 5], Suffix, SuffixMinimum).
Suffix = [4, 2, 3, 5],
SuffixMinimum = 2 ;
Suffix = [2, 3, 5],
SuffixMinimum = 2 ;
Suffix = [3, 5],
SuffixMinimum = 3 ;
Suffix = [5],
SuffixMinimum = 5 ;
false.
Maybe even without exposing the suffix:
list_suffixminimum(List, SuffixMinimum) :-
list_suffix(List, Suffix),
list_minimum(Suffix, SuffixMinimum).
?- list_suffixminimum([4, 2, 3, 5], SuffixMinimum).
SuffixMinimum = 2 ;
SuffixMinimum = 2 ;
SuffixMinimum = 3 ;
SuffixMinimum = 5 ;
false.
Now, and only now that the problem has been solved, you can add I/O if you feel like it. Although at this point, why would you?

Write a program in prolog that determines if there are exactly three values in such a way that they add upto a sum of N

Eg:
List[1,2,3,4,5,6] with N equal to 6 should print true because there are exactly 3 values that add upto 6. 1+2+3.
List[2,5,7,9] with N equal to 12 should print false as there are no 3 elements that add upto 12.
Let's maybe start with a more general predicate that describes the relation between a list, a sublist of said list and the sum of numbers in the sublist. To make it obvious which argument is what, it is opportune to chose a descriptive name for the predicate, say sum_ofsub_fromlist/3. Now let's observe that if the first argument is the sum of the numbers in the sublist, then successively subtracting those numbers from the sum yields zero, e.g.: X=A+B → X-A-B=0. So there will be a base case that contains 0 as the sum and [] as the sublist (rule 1) and a recursive rule that subtracts the elements of the sublist from the sum (rule 2). And since a sublist does not contain all elements of the list it's taken from in general, there will be a recursive rule for skipping elements of the list that do not occur in the sublist (rule 3). This rule is only needed as long as there are still elements in the sublist, so a constraint would be beneficial, that prevents this rule from succeeding once the sublist is empty. These ideas can be realized in Prolog like so:
sum_ofsub_fromlist(0,[],_L). % rule 1
sum_ofsub_fromlist(X,[A|Bs],[A|As]) :- % rule 2
X0 is X-A,
sum_ofsub_fromlist(X0,Bs,As).
sum_ofsub_fromlist(X,Bs,[_A|As]) :- % rule 3
dif(Bs,[]), % constraint: sublist not empty
sum_ofsub_fromlist(X,Bs,As).
You can query this predicate to assure yourself that it delivers all sublists for the given sum in your examples:
?- sum_ofsub_fromlist(6,S,[1,2,3,4,5,6]).
S = [1, 2, 3] ;
S = [1, 5] ;
S = [2, 4] ;
S = [6] ;
false.
?- sum_ofsub_fromlist(12,S,[2,5,7,9]).
S = [5, 7] ;
false.
Building on this you can then write a calling predicate that only succeeds for sublists of length three:
sum_oftriple_fromlist(S,T,L) :-
T=[_,_,_], % T has to be a triple
sum_ofsub_fromlist(S,T,L).
This predicate yields the answers you desire:
?- sum_oftriple_fromlist(6,T,[1,2,3,4,5,6]).
T = [1, 2, 3] ;
false.
?- sum_oftriple_fromlist(12,T,[2,5,7,9]).
false.
Note that the predicate is also working with negative numbers:
?- sum_oftriple_fromlist(6,T,[-5,-3,-1,2,4,7,8,9]).
T = [-5, 2, 9] ;
T = [-5, 4, 7] ;
T = [-3, 2, 7] ;
false.
?- sum_oftriple_fromlist(-6,T,[-6,-5,-4,-3,-2,-1,2,4]).
T = [-6, -4, 4] ;
T = [-6, -2, 2] ;
T = [-5, -3, 2] ;
T = [-3, -2, -1] ;
false.
However, due to the use of is/2, the predicate only works if the first and the third arguments are ground:
?- sum_oftriple_fromlist(S,T,[1,2,3,4,5,6]).
ERROR: is/2: Arguments are not sufficiently instantiated
Exception: (7) sum_ofsub_fromlist(_G918, [_G1016, _G1019, _G1022], [1, 2, 3, 4, 5, 6]) ?
?- sum_oftriple_fromlist(6,T,[A,B,C,D,E,F]).
ERROR: is/2: Arguments are not sufficiently instantiated
Exception: (7) sum_ofsub_fromlist(6, [_G2121, _G2124, _G2127], [_G1945, _G1948, _G1951, _G1954, _G1957, _G1960]) ?
If that's fine with you, you can stop here. Alternatively, you could opt to make the predicate more versatile by using CLP(FD). Just apply these minor changes to your code:
:- use_module(library(clpfd)). % <- new
sum_oftriple_fromlist(S,T,L) :-
T=[_,_,_],
sum_ofsub_fromlist(S,T,L).
sum_ofsub_fromlist(0,[],_L).
sum_ofsub_fromlist(X,[A|Bs],[A|As]) :-
X0 #= X-A, % <- change
sum_ofsub_fromlist(X0,Bs,As).
sum_ofsub_fromlist(X,Bs,[_A|As]) :-
dif(Bs,[]),
sum_ofsub_fromlist(X,Bs,As).
Now the above queries deliver answers:
?- sum_oftriple_fromlist(S,T,[1,2,3,4,5,6]).
S = 6,
T = [1, 2, 3] ;
S = 7,
T = [1, 2, 4] ;
S = 8,
T = [1, 2, 5] ;
. % another
. % seventeen
. % results here
The second query, however, yields residual goals (see documentation for details) as results:
?- sum_oftriple_fromlist(6,T,[A,B,C,D,E,F]).
T = [A, B, C],
_G2424+A#=6,
C+B#=_G2424 ;
T = [A, B, D],
_G2424+A#=6,
D+B#=_G2424 ;
.
.
.
To get actual numbers, you have to restrict the range of the numbers and subsequently label the variables in the list:
?- L=[A,B,C,D,E,F], sum_oftriple_fromlist(6,T,L), L ins 1..6, label(L).
L = [1, 1, 4, 1, 1, 1],
A = B, B = D, D = E, E = F, F = 1,
C = 4,
T = [1, 1, 4] ;
L = [1, 1, 4, 1, 1, 2],
A = B, B = D, D = E, E = 1,
C = 4,
F = 2,
T = [1, 1, 4] ;
.
.
.
Possibly you are only interested in lists where every number only appears once:
?- L=[A,B,C,D,E,F], all_distinct(L), sum_oftriple_fromlist(6,T,L), L ins 1..6, label(L).
L = [1, 2, 3, 4, 5, 6],
A = 1,
B = 2,
C = 3,
D = 4,
E = 5,
F = 6,
T = [1, 2, 3] ;
L = [1, 2, 3, 4, 6, 5],
A = 1,
B = 2,
C = 3,
D = 4,
E = 6,
F = 5,
T = [1, 2, 3] ;
.
.
.
Or maybe you don't even want to restrict the sum:
?- L=[A,B,C,D,E,F], all_distinct(L), sum_oftriple_fromlist(S,T,L), L ins 1..6, label(L).
L = [1, 2, 3, 4, 5, 6],
A = 1,
B = 2,
C = 3,
D = 4,
E = 5,
F = S, S = 6, % sum = 6
T = [1, 2, 3] ;
.
.
.
L = [1, 2, 4, 3, 5, 6],
A = 1,
B = 2,
C = 4,
D = 3,
E = 5,
F = 6,
S = 7, % sum = 7
T = [1, 2, 4] ;
.
.
.
As you can see the CLP(FD) version of the predicate resembles a true relation as opposed to the non-CLP(FD) version. And of course your example queries yield the same answers with both versions.
Your code only considers the first 3 items in the list, and not any other combinations.
The most natural way to structure a solution involving a list is to base your recursion on the structure of the list. So:
If the first element of the list (say, X) is to be included in the 3 values that sum to N, we need to find a way to find 2 values in the rest of the list that sum to N-X.
If it isn't, just try to solve the problem using the rest of the list.
Note that you may need a "helper" version of your predicate that allows you to add other parameters. In this case, knowing how many values you need to add up would be helpful.

How would I modify my predicate to jumble my output result?

So I'm experimenting with some stuff. I have the following simple predicate:
insert([],Y,[Y]).
insert([H|T],Y,[H,Y|T]).
So this'll insert my element Y into my list. However this always puts it in the same place, which is in the middle. But say I wanted it to be more like the following:
?- insert([1,2,3], 4, Zs).
should succeed four times and give the following answers:
Zs = [4, 1, 2, 3]
Zs = [1, 4, 2, 3]
Zs = [1, 2, 4, 3]
Zs = [1, 2, 3, 4].
How would I modify my predicate accordingly?
another useful builtin, extended in SWI-Prolog to handle insertion as well as selection:
?- nth1(_,X,a,[1,2,3]).
X = [a, 1, 2, 3] ;
X = [1, a, 2, 3] ;
X = [1, 2, a, 3] ;
X = [1, 2, 3, a] ;
false.
just ignore first argument (the index itself)
If you want to find possible position of an element in a list, then you have to find all possible concatenation of this list containing the element to insert. This can be described using append/3 predicate:
insert(X,Y,Z):- append(A, B, X), append(A, [Y|B], Z).
This predicate states that exists a concatenation of two sublist that returns list X, and this two sublist concatenated with the value Y in the head of the second sublist, returns list Z.
?- insert([1,2,3], 4, Z).
Z = [4, 1, 2, 3]
Z = [1, 4, 2, 3]
Z = [1, 2, 4, 3]
Z = [1, 2, 3, 4]
false

Eliminate a X element on a list

I have the following knowledge base
eliminate(X,[X|T],T).
eliminate(X,[H|T],[H|T2]) :- eliminate(X,T,T2).
And I have to make the running process of an example by myself, without the interpreter (like a tree).
For example, if I post the query: eliminate(3,[1,2,3,4,5],Y).
First using the first fact, we unificate X=3, and with the second element, which is a list([1,2,3,4,5]) we try to unify 1 with X, but we can't because X now is 3, so it fails and we try with the second rule.
eliminate(3,[1,2,3,4,5],Y).
x = 3, H = 1, T = [2,3,4,5], H = Y , T2 = []
This it the part that I am not sure is right. I don't know why T2 has to be unified with [].
Now with the body clause of the second rule: eliminate(X,T,T2), I have:
eliminate(3,[2,3,4,5],[])
x = 3, (here it fails again, so i have to use the second rule)
eliminate(3,[2,3,4,5],[])
x = 3, H = 2, T = [3,4,5], H = Y, T2 =[] ??? is T2 null again???
T2 doesn't unify with [] the first time the second rule is applied. The resolution knows it is a list (because its on the right side of the [X|Y] construct), but doesn't know its value yet. To find its value, it will first compute the rule, which will find a value for T2 recursively, then unify this value with the Y you ran in your query.
In your example, running the query eliminate(3, [1, 2, 3, 4, 5], Y). will do the following:
Call eliminate(3, [1, 2, 3, 4, 5], Y)
2nd rule: X=3, H=1, T=[2,3,4,5], T2=?, Y=[H|?]
Call eliminate(3, [2, 3, 4, 5], ?)
2nd rule: X=3, H=2, T=[3,4,5], T2=??, Y=[H|??]
Call eliminate(3, [3, 4, 5], ??)
1st rule: ??=[4, 5]
Go back one step, using Y=[H|??], H=2 ??=[4,5]: Y = [2|[4,5]] = [2, 4, 5] = ?
Go back another step, using Y=[H|?], H=1, ?=[2, 4, 5]: Y = [1|[2, 4, 5]] = [1, 2, 4, 5]
I suggest spending some time reading the recusion chapter of your Prolog learning source. Additionally, to find out how you can see this execution in practice to see what's happening, you can use the trace. "command" or other debug equivalent, see this link for swi-pl specifics on debugging a program.

PROLOG List filter predicate not aswering true or false

I'm trying to make a predicate that takes two vectors/lists and uses the first one as a filter. For example:
?- L1=[0,3,0,5,0,0,0,0],L2=[1,2,3,4,5,6,7,8],filter(L1,L2,1).
L1 = [0, 3, 0, 5, 0, 0, 0, 0],
L2 = [1, 2, 3, 4, 5, 6, 7, 8] .
That's what I'm getting but I would want true or false if L2 has 3 as the second element, 5 as the fourth element, etc. The 0s are ignored, that's the "filter" condition.
What I know from the input is that L1 and L2 are always length=8 and only L1 has 0s.
My code is:
filter(_,_,9).
filter([Y|T],V2,Row):-
Y=:=0,
NewRow is Row + 1,
filter([Y|T],V2,NewRow).
filter([Y|T],V2,Row):-
Y=\=0,
nth(Row,[Y|T],X1),
nth(Row,V2,X2),
X1=:=X2,
NewRow is Row + 1,
filter([Y|T],V2,NewRow).
nth(1,[X|_],X).
nth(N,[_|T],R):- M is N-1, nth(M,T,R).
I know there are better ways of doing the function, for example comparing the first element of the first to the nth of the second and delete the head of the first with recursion but I just want to know why I'm not getting true or false, or any "return" value at all.
Can someone help me?, got it working
New code:
filter([],R,_,R).
filter([Y|T],V2,Row,R):-
Y=:=0,
NewRow is Row + 1,
filter(T,V2,NewRow,R).
filter([Y|T],V2,Row,R):-
Y=\=0,
nth(Row,V2,X2),
Y=:=X2,
NewRow is Row + 1,
filter(T,V2,NewRow,R).
Example of expected behaviour:
permutation([1,2,3,4,5,6,7,8],X),filter([1,2,3,4,0,0,0,0],X,1,R).
X = R, R = [1, 2, 3, 4, 5, 6, 7, 8] ;
X = R, R = [1, 2, 3, 4, 5, 6, 8, 7] ;
X = R, R = [1, 2, 3, 4, 5, 7, 6, 8] ;
X = R, R = [1, 2, 3, 4, 5, 7, 8, 6] .
Now i can get all the permutations that starts with 1,2,3,4.
If someone knows a better way to achieve the same, plz share, but i already got what i needed =).
seems like could be a perfect task for maplist/3
filter(L1, L2, _) :-
maplist(skip_or_match, L1, L2).
skip_or_match(E1, E2) :- E1 == 0 ; E1 == E2.
yields
?- permutation([1,2,3,4,5,6,7,8],X),filter([1,2,3,4,0,0,0,0],X,_).
X = [1, 2, 3, 4, 5, 6, 7, 8] ;
X = [1, 2, 3, 4, 5, 6, 8, 7] ;
X = [1, 2, 3, 4, 5, 7, 6, 8] ;
X = [1, 2, 3, 4, 5, 7, 8, 6] ;
...
We could do that more useful, using Prolog facilities - namely, use an anonymus variable to express don't care.
Then filter/N is a simple application of maplist:
?- permutation([1,2,3,4,5,6,7,8],X),maplist(=,[1,2,3,4,_,_,_,_],X).
X = [1, 2, 3, 4, 5, 6, 7, 8] ;
X = [1, 2, 3, 4, 5, 6, 8, 7] ;
X = [1, 2, 3, 4, 5, 7, 6, 8] ;
X = [1, 2, 3, 4, 5, 7, 8, 6] ;
...
Your code always tests the first item of the filtering list for being zero. For example, look at the case when you're checking second value:
filter([0,3,0,5,0,0,0,0], [1,2,3,4,5,6,7,8], 2).
This call will perform the following unifications:
# first case: obvious fail…
filter([0,3,0,5,0,0,0,0], [1,2,3,4,5,6,7,8], 2) =\= filter(_, _, 9).
# second case:
filter([0,3,0,5,0,0,0,0], [1,2,3,4,5,6,7,8], 2) = filter([Y|T],V2,Row).
# unification succeeds with substitutions:
Y = 0
T = [3,0,5,0,0,0,0]
V2 = [1,2,3,4,5,6,7,8]
Row = 2
# and what happens next?
Y =:= 0 # success!
You probably wanted here to check whether second element of [Y|T] is zero; instead, you're checking the first one. If you want to fix it without changing the rest of your code, you should instead perform comparisons to X1:
filter(V1,V2,Row):-
nth(Row, V1, X1),
X1 =:= 0,
NewRow is Row + 1,
filter(V1,V2,NewRow).
filter(V1,V2,Row):-
nth(Row,V1,X1),
X1=\=0,
nth(Row,V2,X2),
X1=:=X2,
NewRow is Row + 1,
filter(V1,V2,NewRow).
Also, there's one more thing that I think you might not be getting yet in Prolog. If a predicate fails, Prolog indeed prints false and stops computation. But if a predicate succeeds, there are two cases:
If there were no variables in your query, Prolog prints true.
If there were any variables in your query, Prolog does not print true. Instead, it prints values of variables instead. This also counts as true.
In your case Prolog actually “returns” true from your predicate—except that because you have used variables in your query, it printed their value instead of printing true.

Resources