Recurrence results stored in list in Prolog - list

I am trying to create a Prolog program for solving the recurrent equation:
f(1)=2, f(2)=5, f(n)=f(n-1)+2*f(n-2)
I managed with the rec function below, but I have trouble when I want to store the result in the list (by function recList).
This is my implementation:
rec(1,2).
rec(2,5).
rec(X,N) :- X1 is X-1, X2 is X-2, rec(X1,N1), rec(X2,N2), N is N1+2*N2.
recList(0,[]).
recList(X,[N|L]) :- rec(X,N), X1 is X-1, recList(X1,L).
My implementation of recList works for calling it by the first value
?- recList(4,X).
->
X = [19, 9, 5, 2] .
but it doesn't when I call it by the second one if it is longer than two elements:
?- rekurList(X,[2]).
X = 1 .
?- rekurList(X,[5,2]).
X = 2 .
?- rekurList(X,[9,5,2]).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] rec(_12587334,9)
ERROR: [8] rekurList(_12587360,[9,5|...]) at /locaiton/rec.pl:6
ERROR: [7] <user>
What is wrong, please?

The predicate is/2 fails because is/2 evaluates the right-hand structure as an arithmetic expression. If it is not a valid arithmetic expression or a number, is/2 fails. So when you call
recList(X, [19, 9, 5, 2]).
you get rec/2: Arguments are not sufficiently instantiated. If you run the tracer (in SWISH, which is SWI on line: trace, recList(X, [19, 9, 5, 2]). In ECLiPSe you can use tkeclipse Tools->Tracer) you get something like:
Call:recList(_13806, [19, 9, 5, 2])
Call:rec(_13806, 19)
Call:_14048 is _13806+-1
Exception:_14102 is _13806+-1
is/2: Arguments are not sufficiently instantiated
To solve this problem you can use the library clpfd in this way (i wrote the solution using SWI):
:- use_module(library(clpfd)).
rec(1,2).
rec(2,5).
rec(X,N):-
X1 #> 0,
X1 #= X-1,
rec(X1,N1),
X2 #> 0,
X2 #= X-2,
rec(X2,N2),
N #= N1+2*N2, !. %notice the cut (!)
recList(0,[]):-!.
recList(X,[N|L]):-
rec(X,N),
X1 #= X-1,
recList(X1,L).
Query:
?- recList(X, [19, 9, 5, 2]).
X = 4.
false.
?- recList(4,L).
L = [19, 9, 5, 2]
false
Note that the cut ! is needed because otherwise, after the first solution, if you click more, the computation will never end. Also X1 #> 0 and X2 #> 0 are needed because otherwise you get a out of local stack error.

Related

Insert into open-ended list without binding its tail variable

Is it possible to solve the following problem in Prolog?
Let A and B be lists of numbers and let N be a number. It is known that B is sorted decreasingly. Check if N can be inserted into A so that the result is B, but do not bind any variable that occurs as a tail in either A nor B.
For example
?- insertable(34, [78, 72, 11 | Z], [78, 72, 34, 11 | Z]).
true.
?- insertable(34, [78, 72, 11 | Z], L).
L = [78, 72, 34, 11 | Z].
Can anyone help me? :)
EDIT 1: This is what I came up with.
insertable(X, List1, List2):- select(X, List2, List1), sorted(List2).
sorted([]).
sorted([_]).
sorted([X, Y | Rest]) :-
X > Y,
sorted([Y | Rest]).
However, even though it works as expected when the arguments are fully instantiated, it binds variables located in tails:
?- insertable(11, [5, 3, 2], [11, 5, 3, 2]).
true .
?- insertable(11, [5, 3, 2 | X], [11, 5, 3, 2 | X] ).
X = [] .
?- insertable(11, [5, 3, 2 | X], L ).
X = [],
L = [11, 5, 3, 2] .
EDIT 2: Here's another approach that I tried.
in(X, [], [X]).
in(X, [Head | Tail1], [Head | Tail2]) :-
X =< Head,
in(X, Tail1, Tail2).
in(X, [Head | Tail], [X, Head | Tail]) :-
X > Head.
The problem is still there:
?- in(1, [3, 2], [3, 2, 1]).
true ;
false.
?- in(1, [3, 2], L).
L = [3, 2, 1] ;
false.
?- in(1, [3, 2 | X], L).
X = [],
L = [3, 2, 1] ;
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (9) in(1, _G8394089, _G8394190) ? abort
% Execution Aborted
?- in(1, [3, 2 | X], [3, 2, 1 | X]).
X = [] ;
X = [1] ;
X = [1, 1] ;
X = [1, 1, 1] ;
X = [1, 1, 1, 1] ;
X = [1, 1, 1, 1, 1] ;
X = [1, 1, 1, 1, 1, 1] ;
X = [1, 1, 1, 1, 1, 1, 1] .
The trick for this exercise are the metalogical predicates var/1 and nonvar/1 which are true if the argument is a variable or not (also have a look at ground/1, atom/1 and integer/1). To make the difference is a little clumsy because we need to keep the list L1 in the head and unify after we know it is a variable or not.
What also might have confused you is the error message of the arithmetic comparison. For that to work, both arguments must be ground. When you don't test for non-var of the tail, the unification automatically instantiates the tail with [Head|Tail1]. That always leads to a comparison number <= Head which leads to the error you had.
The following code assumes you would also like to insert into lists that have a closed tail. If not, the first rule needs to be removed.
in(X, L1, [X]) :- % terminal case for empty list (i.e. tail is not a variable)
nonvar(L1),
L1 = [].
in(X, Xs, [X | Xs]) :- % terminal case if the tail is a variable
var(Xs).
in(X, L1, [N | Zs]) :- % recursive case X =< N
nonvar(L1),
L1 = [N | Ys],
X =< N,
in(X, Ys, Zs).
in(X, L1, [X, N | Ys]) :- % recursive case X > N
nonvar(L1),
L1 = [N | Ys],
X > N.
When we test we can insert 1 in front of a variable tail (after the first result, there are still paths to test but all fail, leading to the false after continuing the query):
?- in(1,Xs,Ys).
Ys = [1|Xs] ;
false.
Also, the inserted element must be 1, so this one should fail:
?- in(1,Xs,[2|Ys]).
false.
It seems the recursion properly propagates to the end:
?- in(1,[3, 2 | Xs], Zs).
Zs = [3, 2, 1|Xs] ;
false.
Inserting in the middle also works:
?- in(2,[3,1 |Xs],Zs).
Zs = [3, 2, 1|Xs].
And finally the test case you tried to solve before:
?- in(34, [78, 72, 11 | Z], [78, 72, 34, 11 | Z]).
true ;
false.
What still doesn't work is if you have variables occurring in your list:
?- in(2,[3,A,1|Xs],Zs).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [10] 2=<_8374
ERROR: [9] in(2,[_8406,1|_8414],[_8418|_8420]) at ./prolog/so-3.pl:9
ERROR: [8] in(2,[3,_8458|...],[3,_8470|_8472]) at ./prolog/so-3.pl:10
ERROR: [7] <user>
Exception: (9) in(2, [_7488, 1|_7496], _7820) ? a
An easy way out would be to guard the comparison with an integer(N) to get
?- in(2,[3,A,1|Xs],Zs).
false.
But then we should also guard against the inserted element being non-integer and the lists having decending integers followed with a variable tail. Alternatively, we could throw a better exception in these cases.

Replacing successive decreasing numbers by the last number of the sequence in Prolog

I've been trying to solve this problem for quite sometime and I think the logic I'm attempting is flawed.
The objective is to replace a subsequently decreasing sublist of numbers by the last of the sublist.
?- compare([1, 3, 7, 6, 5, 10, 9], Result).
Result = [1, 3, 5, 9] ;
false.
What I tried was:
compare([A,B|T],X):-
%succ(B,A),
A is B+1,
append([],NextX,X),
compare([B|T],NextX).
remove([A,B|T],X):-
A=\=B+1,
compare([B|T],X).
I'm not certain how to write the base case for the compare/2 and I think the I'm not correctly converting my logic into the code. What I'm trying here is to compare A and B and drop A from the list if they are successive numbers.
Your help is very much appreciated.
You are almost there. First cover the special case: If the list contains only one element it is in the list.
compare([X],[X]).
your second rule just needs little altering:
compare([A,B|T],X):- % A is not in the list if
A is B+1, % A = B+1
compare([B|T],X). % Note: X is the same as in head of rule
Your predicate remove/2 is should be the 3rd rule of compare/2 covering the alternative case:
compare([A,B|T],[A|X]):- % A is in the list
A=\=B+1, % if A is not B+1
compare([B|T],X).
Now the query works:
?- compare([1, 3, 7, 6, 5, 10, 9], Result).
Result = [1,3,5,9] ?
yes
However, this predicate only works if the first list is variable free. You can't use it the other way round:
?- compare([A,B,C], [1,2]).
ERROR at clause 2 of user:compare/2 !!
INSTANTIATION ERROR- X is A+B: expected bound value
If you use library(clpfd) on the other hand ...
:- use_module(library(clpfd)).
compare([X],[X]).
compare([A,B|T],X):-
A #= B+1,
compare([B|T],X).
compare([A,B|T],[A|X]):-
A #\= B+1,
compare([B|T],X).
... the above query works too:
?- compare([A,B,C], [1,2]).
A = C = 2,
B = 1 ? ;
A = 1,
B = 3,
C = 2 ? ;
no

Prolog divide a list of numbers into two equal parts

Hi I want to write a function called perfect_part that takes a list of integers as input and if possible, return two sub-lists whose sum is exactly half of the total values of all integers in original list.
For example,
?- perfect_part([6, 3, 2, 1], L, R).
L = [6],
R = [3, 2, 1] ;
false.
?- perfect_part([1, 2, 3, 4, 0], L, R).
L = [1, 4],
R = [2, 3, 0] ;
L = [2, 3],
R = [1, 4, 0] ;
Here is my try:
listsum([], 0).
listsum([H|T], Total):-
listsum(T, Sum1),
Total is H + Sum1.
subset([],L).
subset([X|T],L):- member(X,L),subset(T,L).
perfect_part([], 0, 0).
perfect_part(Nums, Left, Right):-
listsum(Nums, S),
H is S / 2,
subset(Left, Nums),
subset(Right, Nums),
listsum(Left, H),
listsum(Right, H).
But if I run it, I got error message:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I fix it? Am I on the right track to sovle this problem?
The predicate subset/2 is missing, and it's an essential part to answer your question. Specifically, if sublists are contiguous, you can solve as easily as
perfect_part(X,L,R) :- append(L,R,X), listsum(L,S), listsum(R,S).
Then I would look for a more adequate replacement for append/3, like
partition([],[],[]).
partition([H|T],[H|L],R) :- partition(T,L,R).
partition([H|T],L,[H|R]) :- partition(T,L,R).
that leads to
perfect_part(X,L,R) :- partition(X,L,R), listsum(L,S), listsum(R,S).
edit Now, from subset/2 it's apparent the error cause: in base case, L is unbound.
Should be subset([],[])., but it doesn't terminate. I wonder how you get the error...
more edit To avoid duplicate solutions, I suggest to break the symmetry with
perfect_part(X,L,R) :- partition(X,L,R), L #=< R, listsum(L,S), listsum(R,S).

prolog two lists are exactly the same

I want to write a function that returns true if two lists are exactly the same(order of elements matters).
I tried it this way:
same([ ], [ ]).
same([H1|R1], [H2|R2]):-
H1 == H2,
same(R1, R2).
It returns true while two lists are the same, also I expect if I have
?- same(X, [1, 2, 3]).
I want it to return
X = [1, 2, 3].
But it doesn't work if input is like this. Here are some sample outputs I got:
?- same([1, 2], [1, 2]).
true.
?- same([2, 1], [1, 2]).
false.
?- same(X, [1, 2, 3]).
false.
?- same([1, 2, 3], [1, 2, X]).
false.
How to fix it?
The problem is that you're using ==/2 (checking whether two items are instantiated the same) rather than =/2 (checks if two items are unified or unifiable). Just change to unification:
same([], []).
same([H1|R1], [H2|R2]):-
H1 = H2,
same(R1, R2).
Then this will have the behavior you're looking for:
| ?- same(X, [1, 2, 3]).
X = [1,2,3] ? a
no
| ?- same([1, 2], [1, 2]).
(1 ms) yes
| ?- same([2, 1], [1, 2]).
no
| ?- same([1, 2, 3], [1, 2, X]).
X = 3
(1 ms) yes
| ?- same([A,B,C], L).
L = [A,B,C]
yes
% In this last example, A, B, and C are variables. So it says L is [A,B,C],
% whatever A, B, and C are.
If you query X == 3 in Prolog, and X is not bound to the value 3, or it is just unbound, it will fail. If X is unbound and you query, X = 3, then Prolog will unify X (bind it) with 3 and it will succeed.
For more regarding the difference between =/2 and ==/2, see What is the difference between == and = in Prolog?
You can also use maplist for a nice, compact solution. maplist is very handy for iterating through a list:
same(L1, L2) :- maplist(=, L1, L2).
Here, unification (=/2) is still used for exactly the same reason as above.
Finally, as #Boris points out, in Prolog, the unification predicate will work on entire lists. In this case, this would suffice:
same(L1, L2) :- L1 = L2.
Or equivalently:
same(L, L). % Would unify L1 and L2 queried as same(L1, L2)
This will succeed if the lists are the same, or will attempt to unify them by unifying each element in turn.
| ?- same([1,2,X], [1,2,3]). % Or just [1,2,X] = [1,2,3]
X = 3
yes
| ?- same([1,2,X], [1,2,3,4]). % Or just [1,2,X] = [1,2,3,4]
no
The prior more elaborate approaches are considered an exercise in list processing for illustration. But the simplest and most correct method for comparison and/or unification of lists would be L1 = L2.

How to access list permutations in prolog?

I want to access list permutation and pass it as argument to other functions.
This is the permutation code:
takeout(X,[X|R],R).
takeout(X,[F|R],[F|S]) :-
takeout(X,R,S),
write(S).
perm([X|Y],Z) :-
perm(Y,W),
takeout(X,Z,W).
perm([],[]).
To start with, let's redefine your predicates so they don't do any unnecessary I/O:
takeout(X,[X|R],R).
takeout(X,[F |R],[F|S]) :- takeout(X,R,S).
perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).
perm([],[]).
Now you have what could be considered a "pure" permutation function:
?- perm([1,2,3], X).
X = [1, 2, 3] ;
X = [2, 1, 3] ;
X = [2, 3, 1] ;
X = [1, 3, 2] ;
X = [3, 1, 2] ;
X = [3, 2, 1] ;
false.
So, suppose you have a max_heap function that takes a list of values and produces a tree. I'll let you worry about that, so let's just posit that it exists and is called max_heap/2 and let's further posit that you have a way to display this attractively called display_heap/1. To "take" the permutation and "send" it as a parameter to these functions, you're really saying in math-ese: suppose P is a permutation of X, let's make a max_heap with it and display it. Or, suppose P is a permutation of X, H is a max heap made from X, let's display H:
show_heaps(List) :- perm(List, P), max_heap(P, H), display_heap(H).
This says the same thing as my English sentence: suppose P is a permutation of the list, then H is a heap representation of it, then display it. Technically, display_heap/1 is still a predicate which could be true or false for a given heap. In practice, it will always be true, and if you run this you'll still have to hit ; repeatedly to say, give me another solution, unless you use a failure-driven loop or an extralogical predicate like findall/3 to cause all the solutions to be found.
Edit: Let's discuss failure-driven loops and findall/3. First let me add some new predicates, because I don't know exactly what you're doing, but it doesn't matter for our purposes.
double([X|Xs], [Y|Ys]) :- Y is X*2, double(Xs, Ys).
double([],[]).
showlist(Xs) :- print(Xs).
So now I have a predicate double/2 which doubles the values in the list and a predicate showlist/1 that prints the list on standard output. We can try it out like so:
?- perm([1,2,3], X), double(X, Y), showlist(Y).
[2,4,6]
X = [1, 2, 3],
Y = [2, 4, 6] ;
[4,2,6]
X = [2, 1, 3],
Y = [4, 2, 6] ;
[4,6,2]
X = [2, 3, 1],
Y = [4, 6, 2] ;
[2,6,4]
X = [1, 3, 2],
Y = [2, 6, 4] ;
[6,2,4]
X = [3, 1, 2],
Y = [6, 2, 4] ;
[6,4,2]
X = [3, 2, 1],
Y = [6, 4, 2] ;
false.
When you type ; you're saying, "or?" to Prolog. In other words, you're saying "what else?" You're telling Prolog, in effect, this isn't the answer I want, try and find me another answer I like better. You can formalize this process with a failure-driven loop:
?- perm([1,2,3], X), double(X, Y), showlist(Y), fail.
[2,4,6][4,2,6][4,6,2][2,6,4][6,2,4][6,4,2]
false.
So now you see the output from each permutation having gone through double/2 there, and then Prolog reported false. That's what one means by something like this:
show_all_heaps(List) :- perm(List, X), double(X, Y), showlist(Y), nl, fail.
show_all_heaps(_).
Look at how that works:
?- show_all_heaps([1,2,3]).
[2,4,6]
[4,2,6]
[4,6,2]
[2,6,4]
[6,2,4]
[6,4,2]
true.
The other option is using findall/3, which looks more like this:
?- findall(Y, (perm([1,2,3], X), double(X, Y)), Ys).
Ys = [[2, 4, 6], [4, 2, 6], [4, 6, 2], [2, 6, 4], [6, 2, 4], [6, 4, 2]].
Using this to solve your problem is probably beyond the scope of whatever homework it is you're working on though.
We can define list_permutation/2 based on same_length/2 and select/3 like this:
:- use_module(library(lists),[same_length/2,select/3]).
list_permutation(As,Bs) :-
same_length(As,Bs), % redundant goal helps termination
list_permutation_(As,Bs).
list_permutation_([],[]).
list_permutation_([A|As],Bs0) :-
select(A,Bs0,Bs),
list_permutation_(As,Bs).
Thanks to same_length/2, both of the following queries1,2 terminate universally:
?- list_permutation([1,2,3],Ys).
Ys = [1,2,3]
; Ys = [1,3,2]
; Ys = [2,1,3]
; Ys = [3,1,2]
; Ys = [2,3,1]
; Ys = [3,2,1]
; false.
?- list_permutation(Xs,[1,2,3]).
Xs = [1,2,3]
; Xs = [1,3,2]
; Xs = [2,1,3]
; Xs = [2,3,1]
; Xs = [3,1,2]
; Xs = [3,2,1]
; false.
So far, so good. But what does the answer sequence look like if there are duplicate list items?
?- list_permutation([1,1,1],Ys).
Ys = [1,1,1]
; Ys = [1,1,1]
; Ys = [1,1,1]
; Ys = [1,1,1]
; Ys = [1,1,1]
; Ys = [1,1,1]
; false.
5/6 answers are redundant! What can we do? We simply use selectd/3 instead of select/3!
list_permuted(As,Bs) :-
same_length(As,Bs),
list_permuted_(As,Bs).
list_permuted_([],[]).
list_permuted_([A|As],Bs0) :-
selectd(A,Bs0,Bs), % use selectd/3, not select/3
list_permuted_(As,Bs).
Let's re-run above query that gave us 5 redundant solutions before!
?- list_permuted([1,1,1],Ys).
Ys = [1,1,1]
; false.
?- list_permuted(Xs,[1,1,1]).
Xs = [1,1,1]
; false.
Better! All redundant answers are gone.
Let's compare the solution set for some sample case:
?- _Xs = [1,2,1,1,2,1,1,2,1],
setof(Ys,list_permutation(_Xs,Ys),Yss),
setof(Ys,list_permuted(_Xs,Ys),Yss),
length(Yss,N).
N = 84, Yss = [[1,1,1,1,1,1,2,2,2],[1,1,1,1,1,2,1,2,2],[...|...]|...].
OK! How about empirical runtime measurements with a problem of a slightly bigger size?
We use call_time/2 for measuring the runtime in milli-seconds T_ms.
?- call_time(\+ (list_permutation([1,2,1,1,1,2,1,1,1,2,1],_),false),T_ms).
T_ms = 8110.
?- call_time(\+ (list_permuted( [1,2,1,1,1,2,1,1,1,2,1],_),false),T_ms).
T_ms = 140.
OK! And with proper compilation of if_/3 and (=)/3, list_permuted/2 is even faster!
Footnote 1: Using SICStus Prolog version 4.3.2 (x86_64-linux-glibc2.12).
Footnote 2: The answers given by the Prolog toplevel have been post-processed for the sake of readability.
If you just want to explore the permutations without the "False" in the end, this code might be helpful
takeout(X,[F |R],[F|S]) :- F\=X, takeout(X,R,S).
takeout(X,[X|R],R).
perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).
perm([],[]).
So, the output of perm([a,b],B) would be
B=[a,b]
B=[b,a]