Related
So i found a way of solving it from stackoverflow and it involves this answer:
last(X,Y) :-
append(_,[X],Y).
But i can't actually understand how this actually works.
If anyone can help me it would be really helpful.Thanks.
You can use append/3 [swi-doc] in several directions. You can for example pass a list, and look how two lists can append to that list. For example:
?- append(X, Y, [1,4,2,5]).
X = [],
Y = [1, 4, 2, 5] ;
X = [1],
Y = [4, 2, 5] ;
X = [1, 4],
Y = [2, 5] ;
X = [1, 4, 2],
Y = [5] ;
X = [1, 4, 2, 5],
Y = [] ;
false.
As you can see, there are five ways to construct that. For example with X = [] and Y = [1,4,2,5], or with X = [1] and Y = [4,2,5].
We thus define the predicate last/2 as:
last(X, L) :-
append(_, [X], L).
Notice the [X] as second parameter. We here thus specify that the second list should be a singleton list (a list with exactly one element). An empty list, or a list with two or more elements will not unify with [X].
The append/3 predicate will this aim to unify the second list with candidates like we have seen in the example. But only if the second list is an singleton list, it will match, in which case X is unified with the last element.
See the definition on the SWI-Prolog website.
One of the examples is:
?- append(X, [Last], [a,b,c]).
X = [a,b],
Last = c.
It means the Last is the single element in a list.
Think of the imperative way that X appends the "Last" to the end of the list. Then, it becomes the list [a,b,c].
Therefore, to define the last, we could:
mylast(Xs,Last):-
append(_,[Last],Xs). % doesn't care about the rest of the elements except the [Last]
I have a list with an unknown number of zeros at the beginning of it, for example [0, 0, 0, 1, 2, 0, 3]. I need this list to be stripped of leading zeros, so that it would look like [1, 2, 0 , 3].
Here's what I have:
lead([Head | _], _) :- Head =\= 0.
lead([0 | Tail], _) :-
lead(Tail, Tail).
The output of which is simply True. Reading the trace shows that it is running until it has a list with no leading zeros, but then the answer doesn't propagate back up the stack. I'm pretty new to Prolog, so I can't figure out how to make it do that.
Here is a solution that works in all directions:
lead([],[]).
lead([H|T],[H|T]) :-
dif(H,0).
lead([0|T],T2) :-
lead(T,T2).
Some queries:
?- lead([0,0,0,1,2,0,3], L).
L = [1, 2, 0, 3] ;
false.
?- lead(L, []).
L = [] ;
L = [0] ;
L = [0, 0] ;
L = [0, 0, 0] ;
...
?- lead(L0, L).
L0 = L, L = [] ;
L0 = L, L = [_G489|_G490],
dif(_G489, 0) ;
L0 = [0],
L = [] ;
L0 = [0, _G495|_G496],
L = [_G495|_G496],
dif(_G495, 0) ;
L0 = [0, 0],
L = [] ;
L0 = [0, 0, _G501|_G502],
L = [_G501|_G502],
dif(_G501, 0) ;
L0 = [0, 0, 0],
L = [] ;
...
EDIT This predicate actually doesn't work for e.g. lead(L0, [0,1,2]).
With library(reif):
:- use_module(reif).
remove_leading_zeros([], []).
remove_leading_zeros([H|T], Rest) :-
if_( H = 0,
remove_leading_zeros(T, Rest),
Rest = [H|T]).
Then:
?- remove_leading_zeros([0,0,0,1,2,0,3], R).
R = [1, 2, 0, 3].
?- remove_leading_zeros([2,0,3], R).
R = [2, 0, 3].
?- remove_leading_zeros(L, R).
L = R, R = [] ;
L = [0],
R = [] ;
L = [0, 0],
R = [] ;
L = [0, 0, 0],
R = [] . % and so on
Here is a solution that actually works for all possible inputs and doesn't leave unnecessary choice points:
lead(L0, L) :-
( nonvar(L),
L = [H|_] ->
dif(H,0)
;
true
),
lead_(L0, L).
lead_([], []).
lead_([H|T], L) :-
if_(H \= 0,
L = [H|T],
lead_(T,L)).
The initial check for nonvar(L) is the only solution I have been able to come up with that would prevent problems with e.g. lead(L0, [0,1,2,3]), while retaining the behavior of the predicate in all other situations.
This uses if_/3, part of library(reif)
if_(If_1, Then_0, Else_0) :-
call(If_1, T),
( T == true -> Then_0
; T == false -> Else_0
; nonvar(T) -> throw(error(type_error(boolean,T),
type_error(call(If_1,T),2,boolean,T)))
; throw(error(instantiation_error,instantiation_error(call(If_1,T),2)))
).
This also uses (\=)/3, that I came up with by simple modification of (=)/3 in library(reif).
\=(X, Y, T) :-
( X \= Y -> T = true
; X == Y -> T = false
; T = true, dif(X, Y)
; T = false,
X = Y
).
Some queries
?- lead([0,0,0,1,2,0,3],L). % No choice point
L = [1, 2, 0, 3].
?- lead([1,2,0,3],L).
L = [1, 2, 0, 3].
?- lead([0,0,0,0],L).
L = [].
?- lead([],L).
L = [].
?- lead(L0,[0,1,2,0,3]). % Correctly fails
false.
?- lead(L0,[1,2,0,3]).
L0 = [1, 2, 0, 3] ;
L0 = [0, 1, 2, 0, 3] ;
L0 = [0, 0, 1, 2, 0, 3] ;
…
?- lead(L0,L). % Exhaustively enumerates all cases:
L0 = L, L = [] ; % - LO empty
L0 = L, L = [_G2611|_G2612], % - L0 contains no leading 0
dif(_G2611, 0) ;
L0 = [0], % - L0 = [0]
L = [] ;
L0 = [0, _G2629|_G2630], % - L0 contains one leading 0
L = [_G2629|_G2630],
dif(_G2629, 0) ;
L0 = [0, 0], % - L0 = [0, 0]
L = [] ;
L0 = [0, 0, _G2647|_G2648], % - L0 contains two leading 0s
L = [_G2647|_G2648],
dif(_G2647, 0) ;
… % etc.
Here is a solution that doesn't generate any choice points. Its
using freeze/2, in a way that is not anticipated by dif/2. But using
freeze/2 here is quite appropriate, since one rule of thumb for freeze/2
is as follows:
Rule of Thumb for freeze/2: Use freeze/2 where the predicate would
generate uninstantiated solutions and a lot of choice points. The hope
is that a subsequent goal will specify the solution more, and the
freeze/2 will be woken up. Unfortunately doesn't work with CLP(FD) or
dif/2, since freeze/2 does not react to refinements implied by CLP(FD)
or dif/2, only unification will wake it up.
The code is thus:
lead(X, Y) :- var(X), !, freeze(X, lead(X,Y)).
lead([X|Y], Z) :- var(X), !, freeze(X, lead([X|Y],Z)).
lead([0|X], Y) :- !, lead(X, Y).
lead(X, X).
Here are some sample runs (SWI-Prolog without some import, Jekejeke Prolog use Minlog Extension and ?- use_module(library(term/suspend))):
?- lead([0,0,0,1,2,3], X).
X = [1, 2, 3].
?- lead([0,0|X], Y).
freeze(X, lead(X, Y)).
?- lead([0,0|X], Y), X = [0,1,2,3].
X = [0, 1, 2, 3],
Y = [1, 2, 3].
?- lead([Z,0|X], Y), X = [0,1,2,3].
X = [0, 1, 2, 3],
freeze(Z, lead([Z, 0, 0, 1, 2, 3], Y)).
?- lead([Z,0|X], Y), X = [0,1,2,3], Z = 0.
Z = 0,
X = [0, 1, 2, 3],
Y = [1, 2, 3].
In the above lead/2 implemetation only the first argument is handled. To handle multiple arguments simultaneously the predicate when/2 can be used. But for simplicity this is not shown here.
Also when using suspended goals, one might need a labeling like predicate at the end, since suspended goals cannot detect inconsistency among them.
The problem in your code is that the second parameter, your output, is specified as _, so your predicate is true for any output. What you want is a predicate that is true if and only if it is the input minus leading zeroes.
lead([], []).
lead([0 | Tail], Tail2) :- !, lead(Tail, Tail2).
lead([Head | Tail], [Head | Tail]) :- Head =\= 0.
The ! in the first line is optional. It prunes the search tree so Prolog does not consider the second line (which would fail) if the first line matches.
Here's how I'd phrase it. First, establish constraints: either X or Y must be bound to a list. Anything else fails.
If X is bound, we don't care about Y: it can be bound or unbound. We just strip any leading zeros from X and unify the results with Y. This path has a single possible solution.
If X is unbound and Y is bound, we shift into generative mode. This path has an infinite number of possible solutions.
The code:
strip_leading_zeros(X,Y) :- listish(X), !, rmv0( X , Y ) .
strip_leading_zeros(X,Y) :- listish(Y), !, add0( Y , X ) .
rmv0( [] , [] ) .
rmv0( [D|Ds] , R ) :- D \= 0 -> R = [D|Ds] ; rmv0(Ds,R) .
add0( X , X ) .
add0( X , Y ) :- add0([0|X],Y ) .
listish/1 is a simple shallow test for listish-ness. Use is_list/1 if you want to be pedantic about things.
listish( L ) :- var(L), !, fail.
listish( [] ) .
listish( [_|_] ) .
Edited to note: is_list/1 traverses the entire list to ensure that it is testing is a properly constructed list, that is, a ./2 term, whose right-hand child is itself either another ./2 term or the atom [] (which denotes the empty list). If the list is long, this can be an expensive operation.
So, something like [a,b,c] is a proper list and is actually this term: .(a,.(b,.(c,[]))). Something like [a,b|32] is not a proper list: it is the term .(a,.(b,32)).
I need to write a program in prolog that accepts a list, reverses that list and the appends that to the end of the original list.
Example:
list_rList([1,2,3],X)
X = [1,2,3,3,2,1]
So far I have been able to reverse the list, but I can manage to append the reverse list to the original list.
Here is what I have:
list_rList([],[]).
list_rList([H|T],R):- list_rList(T,RevT), append(RevT,[H],R).
Here is a solution which will work correctly in all directions:
list_rList(L, T) :-
list_rList(L, [], T).
list_rList([], A, A).
list_rList([H|T], C, [H|T2]) :-
list_rList(T, [H|C], T2).
The second argument will accumulate the reversed list, and the third one will accumulate the result: each element of the original list is appended at the beginning of that third argument, and its tail is the second argument once we have emptied the first list.
Some example queries:
?- list_rList([1,2,3],Z). % What you asked
Z = [1, 2, 3, 3, 2, 1].
?- list_rList([1|T],Z). % With a variable tail
T = [],
Z = [1, 1] ;
T = [_G1659],
Z = [1, _G1659, _G1659, 1] ;
T = [_G1659, _G1668],
Z = [1, _G1659, _G1668, _G1668, _G1659, 1]
…
?- list_rList(Z,[1,2,3,3,2,1]). % The original list from the result
Z = [1, 2, 3] ;
false.
?- list_rList(Z,[1,2,3,3,2]). % Check that a list can be the result of this predicate
false.
?- list_rList(Z,[1,2,3,X,Y,3,2,1]). % With variable elements in the result
Z = [1, 2, 3, Y],
X = Y ;
false.
?- list_rList(L,Z). % With completely free arguments
L = Z, Z = [] ;
L = [_G1623],
Z = [_G1623, _G1623] ;
L = [_G1623, _G1632],
Z = [_G1623, _G1632, _G1632, _G1623] ;
L = [_G1623, _G1632, _G1641],
Z = [_G1623, _G1632, _G1641, _G1641, _G1632, _G1623] ;
L = [_G1623, _G1632, _G1641, _G1650],
Z = [_G1623, _G1632, _G1641, _G1650, _G1650, _G1641, _G1632, _G1623]
…
you could do something like this:
accRev([H|T],A,L,R) :- accRev(T,[H|A],L,R).
accRev([],A,L,R) :- append(L,A,R).
list_rList(L,R) :- accRev(L,[],L,R).
Here, first the list is reversed using an accumulator (the second argument of accRev) and once this is finished, the original list (which is kept in the third argument of accRev) is prepended.
I'm trying to add either 1 or 2 to numbers in a list in SWI-Prolog.
I've managed to add 1 or 2 to the head of the list however I'm having difficulties adding onto each element on the tail of the list. I don't want to add 1 or 2 to EVERY element at the same time just at separate times. I.e. If my input is
add([2,3,4], X).
I would like the possibilities of X to be the following:
X = [3,3,4]
X = [4,3,4]
X = [2,4,4]
X = [2,5,4]
X = [2,3,5]
X = [2,3,6]
My code at present is:
add([],[]).
add([H1|T1],[H2|T2]) :-
is(H2,+(H1,1)), T1=T2;
is(H2,+(H1,2)), T1=T2.
Obviously this only adds 1 or 2 onto the head of the list and not the tail. Therefore does anyone know how I may go about adding 1 or 2 onto the elements in the tail of my list?
First define a predicate addX/3 that will add X to one of the members of the first list:
addX([], [],_). % base case
addX([H|T], [H1 | T], X) :- H1 is H + X. % add to first element
addX([H|T], [H | T1], X) :- addX(T, T1, X). % or retain the first element and add to some element in the tail
Than using it define your add predicate as addX with X=1 or X=2:
add(L, R) :- addX(L, R, 1).
add(L, R) :- addX(L, R, 2).
Testing:
?- add([2,3,4], X).
X = [3, 3, 4] ;
X = [2, 4, 4] ;
X = [2, 3, 5] ;
X = [2, 3, 4] ;
X = [4, 3, 4] ;
X = [2, 5, 4] ;
X = [2, 3, 6] ;
X = [2, 3, 4].
sometime more verbose can be clearer:
add([],[]).
add([H1|T],[H2|T]) :-
H2 is H1+1.
add([H1|T],[H2|T]) :-
H2 is H1+2.
add([H|T1],[H|T2]) :-
add(T1,T2).
now alternatives are listed out, the last one just handles - recursively - the remaining elements
Anyway, your code is just missing a line:
add([],[]).
add([H1|T1],[H2|T2]) :-
is(H2,+(H1,1)), T1=T2;
is(H2,+(H1,2)), T1=T2;
H1=H2, add(T1,T2).
After comment, here is how to subtract and keep only positive values:
add([H1|T1],[H2|T2]) :-
H2 is H1-1, H2 > 0, T1=T2;
...
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]