Prolog - generate correct bracketing - list

I'd like to get some help in the following exam problem, I have no idea how to do this:
Input: a list of numbers, eg.: [1,2,3,4]
Output: every possible correct bracketing. Eg.: (in case of input [1,2,3,4]):
((1 2) (3 4))
((1 (2 3)) 4)
(1 ((2 3) 4))
(1 (2 (3 4)))
(((1 2) 3) 4)
Bracketing here is like a method with two arguments, for example multiplication - then the output is the possible multiplication orders.

Your assignment could be seen as the inverse of 'computing the yield of a binary tree'.
You can code yield with 2 recursive calls and append/3:
yield((L, R), Y) :-
yield(L, Ly),
yield(R, Ry),
append(Ly, Ry, Y).
yield(T, [T]).
test:
?- yield(((1,2),(3,4)),Y).
Y = [1, 2, 3, 4] ;
Y = [1, 2, (3, 4)] ;
Y = [ (1, 2), 3, 4] ;
Y = [ (1, 2), (3, 4)] ;
Y = [ ((1, 2), 3, 4)].
Thus abstractly, yield/2 should solve your assignment, when called in this way:
?- yield(BinTree, [1,2,3,4]).
but, of course, that do not terminate. Clearly, the SLD resolution (Prolog computing algorithm) can't solve this problem without some help.
But if you recall that append/3 can generate all the alternatives left & right lists that compose the appended:
?- append(L,R,[1,2,3,4]).
L = [],
R = [1, 2, 3, 4] ;
L = [1],
R = [2, 3, 4] ;
L = [1, 2],
R = [3, 4] ;
L = [1, 2, 3],
R = [4] ;
L = [1, 2, 3, 4],
R = [] ;
false.
you can attempt to change the order of calls to get your solution.
Beware that you need sufficiently instantiated arguments before recursing, thus check the 'output' of append. You can test with
...
Yr = [_|_],
...
I also suggest to rename the predicate and change the order of arguments for clarity:
?- brackets([1,2,3,4],B).
B = 1* (2* (3*4)) ;
B = 1* (2*3*4) ;
B = 1*2* (3*4) ;
B = 1* (2*3)*4 ;
B = 1*2*3*4 ;
false.

This code works with SWI-Prolog (nextto/3).
You can explain to Prolog what you want, then ask him all the solutions :
bracket([A,B], [A,B]).
bracket(In, Out) :-
member(X, In),
nextto(X,Y, In),
append_3(A, [X,Y], B, In),
append_3(A, [[X,Y]], B, Temp),
bracket(Temp, Out).
append_3(A,B,C, Out) :-
append(A, B, Temp),
append(Temp, C, Out), !.
all_brackets(R) :-
setof(L, bracket([1,2,3,4], L), R).
you get
?- all_brackets(R), maplist(writeln, R).
[[[1,2],3],4]
[[1,2],[3,4]]
[[1,[2,3]],4]
[1,[[2,3],4]]
[1,[2,[3,4]]]
R = [[[[1,2],3],4],[[1,2],[3,4]],[[1,[2,3]],4],[1,[[2,3],4]],[[1,2],[3,4]],[1,[2,[3,4]]]].

Related

replace an element in list with its first occurence but keep replacing for all occurences- Prolog

I have just started programing in Prolog, using tkeclipse. What I want to do, is to replace an element of the list with another element on the first place that it occurs. However, when I press the more button (;) I want the query to return also the other solutions. Example:
?- replace(1,a,[1,2,3],R).
R = [a, 2, 3]
Yes
?- replace(1,a,[1,2,1,1,3],R).
R = [a, 2, 1, 1, 3] ;
R = [1, 2, a, 1, 3] ;
R = [1, 2, 1, a, 3] ;
No
What I wrote so far, works fine, but in the end, after [1,2,1,a,3], I also get [1,2,1,1,3] instead of no. My code is as follows:
%%% replace/4
replace(_,_,[],[]).
replace(X,Y,[X|T],[Y|T]).
replace(X,Y,[H|T],[H|T2]) :-
replace(X,Y,T,T2).
Just delete the first clause
replace(_,_,[],[]).
and you should be fine.
You [1,2,1,1,3] because:
replace(1,a,[1,2,1,1,3],[1,2,1,1,3]) is successful by
always taking the third clause, reducing the pre-replacement-list and the result-of-the-replacement list element by element
succeeding on the empty list by taking the first clause
You want:
Success on the empty list (0 replacements); and also
A stream of of exactly-one-replacements
And so:
replace(_,_,[],[]) :- !. % make this deterministic with a a cut
replace(X,Y,PreList,PostList) :-
replace_2(X,Y,PreList,PostList).
% replace_2/4 is the same as replace/4 but does NOT succeed for the empty list
replace_2(X,Y,[X|T],[Y|T]).
replace_2(X,Y,[H|T],[H|T2]) :-
replace_2(X,Y,T,T2).
And so:
?- replace(1,a,[1,2,3],R).
R = [a, 2, 3] ;
false.
?- replace(1,a,[1,2,1,1,3],R).
R = [a, 2, 1, 1, 3] ;
R = [1, 2, a, 1, 3] ;
R = [1, 2, 1, a, 3] ;
false.
?- replace(foo,a,[1,2,1,1,3],R).
false.
?- replace(foo,a,[],R).
R = [] ;
false.

Prolog With Lists

I received this problem and I can't get it done, I don't know what I've done wrong, can someone help me ?
Write a predicate to add a value v after 1-st, 2-nd, 4-th, 8-th, … element in a list.
% add(L:list, E:Number, P:Number, C:number, H:List)
% add(i,i,i,i,o)
add([],_,_,_,[]).
add([_|T],E,P,C,[HR|TR]) :-
P =:= C,
HR is E,
C is C+1,
P is P*2,
add(T,E,P,C,TR).
add([H|T],E,P,C,[H|TR]) :-
P =\= C,
C is C+1,
add(T,E,P,C,TR).
Here's another possibility to define such a predicate. Whenever you are describing lists it is worthwhile to consider using DCGs since they yield easily readable code. First let's observe that there's only need for three arguments, namely the list, the element to be inserted and the list with the element already inserted at the desired positions. The arguments P and C are only needed for bookkeeping purposes so it's opportune to hide them inside the predicate. And since we're already about to redesign the predicates interface let's also give it a more descriptive name that reflects its relational nature, say list_e_inserted/3:
list_e_inserted(L,E,I) :-
phrase(inserted(L,E,1,1),I). % the DCG inserted//4 describes the list I
inserted([],_E,_P,_C) --> % if the list L is empty
[]. % the list I is empty as well
inserted([H|T],E,P,P) --> % if P and C are equal
{P1 is P*2, C1 is P+1}, % P is doubled and C is increased
[H,E], % H is in the list I, followed by E
inserted(T,E,P1,C1). % the same holds for T,E,P1,C1
inserted([H|T],E,P,C) --> % if P and C are
{dif(P,C), C1 is C+1}, % different C is increased
[H], % H is in the list I
inserted(T,E,P,C1). % the same holds for T,E,P,C1
Now let's see the predicate at work:
?- list_e_inserted([],10,I).
I = [].
?- list_e_inserted([1],10,I).
I = [1, 10] ;
false.
?- list_e_inserted([1,2],10,I).
I = [1, 10, 2, 10] ;
false.
?- list_e_inserted([1,2,3],10,I).
I = [1, 10, 2, 10, 3] ;
false.
?- list_e_inserted([1,2,3,4],10,I).
I = [1, 10, 2, 10, 3, 4, 10] ;
false.
The predicate also works in the other direction:
?- list_e_inserted(L,E,[1,10,2,10,3,4,10,5]).
L = [1, 2, 3, 4, 5],
E = 10 ;
false.
And the most general query also yields the desired solutions:
?- list_e_inserted(L,E,I).
L = I, I = [] ;
L = [_G23],
I = [_G23, E] ;
L = [_G23, _G35],
I = [_G23, E, _G35, E] ;
L = [_G23, _G35, _G47],
I = [_G23, E, _G35, E, _G47] ;
L = [_G23, _G35, _G47, _G53],
I = [_G23, E, _G35, E, _G47, _G53, E] ;
.
.
.
The main problem is that when a variable in Prolog gets instantiated you can't change the value e.g increase the value so you need to use a new variable:
add([],_,_,_,[]).
add([H|T],E,P,C,[H,E|TR]) :-
P =:= C,
C1 is C+1,
P1 is P*2,
add(T,E,P1,C1,TR).
add([H|T],E,P,C,[H|TR]) :-
P =\= C,
C1 is C+1,
add(T,E,P,C1,TR).
Example:
?- add([1,2,3,4],10,1,1,L).
L = [1, 10, 2, 10, 3, 4, 10] ;
false.

Prolog Lists, Add 1 to tail of the list

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;
...

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).

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]