prolog- break a list - list

The example is like this
?- runs([3,4,5,4,2,7,5,6,6,8,3], RunList).
RunList = [[3, 4, 5], [4], [2, 7], [5, 6, 6, 8], [3]]
The list need to be broken in to a number of non-decreasing sequence of consecutive numbers. My code is:
next([],0).
next([H|_],R):-
R is H.
runs1([],[]).
runs1([H|T],R):-
runs1(T,R1),
next(T,X),
H=<X,
R = [H|R1].
runs1([H|T],R):-
runs1(T,R1),
next(T,X),
H>X,
R = [[H]|R1].
I tried lots of methods, but still do not know how to write it...
Hope someone could help me.
Thanks in advance.

For a logically pure and monotone implementation look at
my answer to related question "Extracting sequences (Lists) Prolog".
I present the meta-predicate splitlistIfAdj/3 which is based on if_/3 as proposed by #false in this answer.
splitlistIfAdj/3 ensures logical soundness while remaining deterministic when possible.
The predicate passed to splitlistIfAdj/3 has to obey the same convention as (=)/3 and memberd_truth/3.
For your case we need a definition of (#>)/3:
#>(X,Y,Truth) :- X #> Y #<==> B, =(B,1,Truth).
Let's use splitlistIfAdj/3 and (#>)/3 in the example you gave:
?- splitlistIfAdj(#>,[3,4,5,4,2,7,5,6,6,8,3],Pss).
Pss = [[3,4,5],[4],[2,7],[5,6,6,8],[3]]. % succeeds deterministically
Now let's ask a more general query:
?- splitlistIfAdj(#>,[A,B],Pss).
Pss = [[A],[B]], A#>=_X, B+1#=_X ;
Pss = [[A,B]], A#>=_Y#<==>_Z, B+1#=_Y, _Z in 0..1, dif(_Z,1).
Last, let's run the query that #lurker suggested in his comment to #rrrfer's answer:
?- splitlistIfAdj(#>, Ls, [[3,4,5],[4],[2,7],[5,6,6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ;
false.

runs([], []):-!.
runs([H|T], S):-
runs(T, TS),
ins(H, TS, S).
ins(E, [], [[E]]):-!.
ins(E, [[H|T]|TL], [[E, H|T]|TL]):-
H >= E, !.
ins(E, TL, [[E]|TL]).

Related

Is there a way to sum only the integers in a list of pairs that contain a letter and an integer in Prolog?

I'm having trouble figuring out how to find the sum of the integers that are in a list of pairs like so:
[[a, 1], [b, 2], [c, 3], [d, 4]]
I tried something like this, since it is reminiscent of a regular sum function:
sum([], 0).
sum([[_,Head]|[_,Tail]], Sum) :-
sum([_,Tail], Sum2),
Sum is Head+Sum2.
With the call being:
sum([[a, 1], [b, 2], [c, 3], [d, 4]], Total),
write('Sum = '), write(Total).
But that doesn't work. It prints out false, when it should print out the sum, which would be 10 here.
In your attempt to define the predicate sum/2, you're not handling the lists of lists correctly. Try:
sum(Lists, Sum) :-
sum(Lists, 0, Sum).
sum([], Sum, Sum).
sum([[_,N]| Lists], Sum0, Sum) :-
Sum1 is Sum0 + N,
sum(Lists, Sum1, Sum).
This version uses an accumulator to enable a tail-recursive definition. Sample call:
| ?- sum([[a, 1], [b, 2], [c, 3], [d, 4]], Sum).
Sum = 10
yes
I think it might help to split this into two tasks:
create a new list of the second item of each sublist; and
sum up that list.
This makes it easier to tackle the two problems, and furthermore you now have two extra predicates that can be used for other purposes.
We can obtain a list of the second item of the sublists with:
item2list([], []).
item2list([[_, X|_]|T], [X|T2]) :-
item2list(T, T2).
or we can use maplist/3 [swi-doc] and nth1/3 [swi-doc]:
item2list(L1, L2) :-
maplist(nth1(2), L1, L2).
or we can write item2list in terms of findall/3 [swi-doc] and member/2 [swi-doc]:
item2list(L1, L2) :-
findall(X, member([_,X|_], L1), L2).
although here the predicate is not bidirectional.
For example:
?- item2list([[a, 1], [b, 2], [c, 3], [d, 4]], L).
L = [1, 2, 3, 4].
I leave summing up that list as an exercise.
Whenever a goal fails that you expect to succeed, see this as an opportunity to learn (short form for logic earn = earn logic). After all, this is Prolog which was meant to mean Programming in Logic. So where is the logic in your program?
For the moment your program fails, but you expected it to succeed. Where is the culprit? Let's generalize your program such that the resulting program still fails, but is much smaller. There are two easy ways to generalize a program:
remove goals (by adding a prefix *)
remove terms (replacing term by _/*term*/
We can do this pretty blindly. No need to understand your program. Just recheck that the goal still fails. Here is what I came up with on my first try:
:- op(950, fy, *).
* _G_0. % ignore the argument _G_0
sum([], _/*0*/).
sum([_/*[_,Head]*/|[_,Tail]], Sum) :-
* sum([_,Tail], Sum2),
* Sum is Head+Sum2.
?- sum([_/*[a, 1]*/, _/*[b, 2]*/, _/*[c, 3]*/, _/*[d, 4]*/], Total).
false. % gnah - still fails
One problem has to be in the remaining visible part. Too difficult to figure out? Let Prolog explain it to you by querying the most general query:
?- sum(Xs, Sum).
Xs = []
; Xs = [_A,_B,_C].
So only two lengths of lists are possible: The empty list and a list with three elements. Note that we have currently a generalized version of the predicate. So there is no guarantee that we will find solutions for both lengths. However, we can be 100% sure that for all other lengths there will be no solution.
Let's get back at the original program and ask the most general query:
?- sum(Os, Total).
Os = [], Total = 0
; false.
Oh no, there is a single solution only. And not even a single solution for sum([_|_], Total).
So let's generalize the program again but now with respect to this failing goal:
sum([], _/*0*/).
sum([_/*[_,Head]*/|[_,Tail|_/*[]*/]], Sum) :-
sum([_,Tail], Sum2),
* Sum is Head+Sum2.
?- Os = [_|_], sum(Os, Total).
false.
In this part there must be a further error. And in fact, the goal sum([_,Tail], Sum2) is the culprit: It is about a list of exactly two elements, but the rule wants at least three
For the actual fixes, see the other answers.
This method works for pure, monotonic programs such as yours.

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.

Removing lists-within-lists from my prolog code

I've been trying to solve this problem of mine for a while now but I'm not really sure how to go about it.
For example, let's say I have this "tree" in my database:
tree4(b(b(l(Apple),l(Banana)), b(l(Orange), l(Pear)))).
I want to be able to query the database so as to retrieve the information within each l() and present it in a list. So far I've done this:
leaves(l(X), L) :-
L = X.
leaves(b(X,Y), L) :-
leaves(X, A),
leaves(Y, B),
L = [A, B].
I then query the database and it gives me this:
?- tree4(T), leaves(T, L).
T = b(b(l(1), l(2)), b(l(3), l(4))),
L = [[1, 2], [3, 4]].
The problem with this code is it generates multiple lists nestled within my original one. Is there another way to go about this? Any help would be greatly appreciated!
As you are describing a list (in this case: of leaves), consider using a DCG:
leaves(l(L)) --> [L].
leaves(b(B1,B2)) --> leaves(B1), leaves(B2).
Example query (using atoms instead of variables in tree4/1):
?- tree4(Tree), phrase(leaves(Tree), Leaves).
Tree = b(b(l(apple), l(banana)), b(l(orange), l(pear))),
Leaves = [apple, banana, orange, pear].
You can avoid the cost of the append/3 predicate by using an accumulator to collect the leaves during the traversal of the tree:
leaves(Tree, Leaves) :-
leaves(Tree, [], Leaves).
leaves(l(Leaf), Leaves, [Leaf| Leaves]).
leaves(b(Left,Right), Leaves0, Leaves) :-
leaves(Right, Leaves0, Leaves1),
leaves(Left, Leaves1, Leaves).
Using your sample call:
?- leaves(b(b(l(1), l(2)), b(l(3), l(4))), Leaves).
Leaves = [1, 2, 3, 4].
Assuming your Prolog implementation has an append predicate, you could do this:
leaves(l(X), [X]).
leaves(b(X,Y), L) :-
leaves(X, A),
leaves(Y, B),
append(A, B, L).
So leaves will always return a flat list, even if there's just one. This also assumes your tree is strictly binary, as you have it described.
Just a reminder about flatten/2, an handy builtin:
?- leaves(b(b(l(1), l(2)), b(l(3), l(4))), L), flatten(L, F).
L = [[1, 2], [3, 4]],
F = [1, 2, 3, 4].
As you can see from documentation, its use is discouraged, and you have already received plenty of good hints that allow to avoid it.

Taking a tree and making a list

I have written a program that can take a list and change it into a tree.
build_tree([X,Y],'Tree'(X,Y)) :- !.
build_tree([X|Y],'Tree'(X,Z)) :- build_tree(Y, Z).
If I want to reverse the process and take the tree and change it back into a list, how would I do this?
Note that your tree->list conversion isn't a function since trees may correspond to multiple lists:
?- build_tree([1, 2, 3], T).
T = 'Tree'(1, 'Tree'(2, 3)).
?- build_tree([1, 'Tree'(2, 3)], T).
T = 'Tree'(1, 'Tree'(2, 3)).
If you want a predicate that can generate all lists from a tree, remove the cut from build_tree and apply it with a variable first argument. If you want a deterministic conversion, write a new predicate tree_to_list.
Just curious, how would that deterministic version play out? Assuming there was only one possible list, from the tree, for example:
('Tree'('Tree'(nil, 2, nil), 5, 'Tree'(nil, 6, nil)).
Which gives: L = [5, 2, 6]
If you remove the cut from the first rule, your code it's ready to work in 'backward' mode:
?- build_tree([1,2,3,4],T).
T = 'Tree'(1, 'Tree'(2, 'Tree'(3, 4))) ;
false.
?- build_tree(X,$T).
X = [1, 'Tree'(2, 'Tree'(3, 4))] ;
X = [1, 2, 'Tree'(3, 4)] ;
X = [1, 2, 3, 4] ;
false.
flatten(leaf, []).
flatten(node(L, E, R), Ls) :-
flatten(L, Ls1),
append(Ls1, [E], Ls2),
flatten(R, Ls3),
append(Ls2, Ls3, Ls).
if you consider tree ass node(leaf,Element,leaf) for example
flatten(node(node(leaf,2,leaf),3,node(leaf,5,leaf)),X).
gives X=[2,3,5].
and if you wanna have bst
List to Tree.
insert(E,leaf,node(leaf,E,leaf)).
insert(E,node(L,N,R),T) :-
E >= N,
T=node(L,N,R1),
insert(E,R,R1).
insert(E,node(L,N,R),T) :-
E < N,
T=node(L1,N,R),
insert(E,L,L1).
list_to_tree(List,Tree) :-
list_to_tree(List,leaf,Trea2),
Tree=Trea2.
list_to_tree([],Tree,Tree).
list_to_tree([H|T],Tree,St):-
insert(H,Tree,R),
list_to_tree(T,R,St).

Permute into a list SWI-Prolog

How do you use the permute predicate to output into a list in SWI prolog?
The permutation/2 predicate only returns one result at a time.
The most straight forward way to describe all permutations is using bagof/3. Note that findall/3 cannot be used directly, since findall produces literal copies of the original list.
list_allperms(L, Ps) :-
bagof(P, permutation(L,P), Ps).
?- L = [A,B,C], list_allperms(L, Ps).
L = [A, B, C], Ps = [[A,B,C],[A,C,B],[B,A,C],[B,C,A],[C,A,B],[C,B,A]].
So that's the no-brainer version. But you can even implement it directly in pure Prolog without any auxiliary built-ins.
If you want a list of all permutations, findall/3 is the way to go. If you want to print, you can use forall/2. Either case:
case_a(In, L) :- findall(Perm, permutation(In, Perm), L).
case_b(In) :- forall(permutation(In, Perm), writeln(Perm)).
forall it's a general purpose builtin, implementing a failure driven loop, amazing for its' simplicity. I report the definition from SWI-Prolog library, I think it's interesting.
%% forall(+Condition, +Action)
%
% True if Action if true for all variable bindings for which Condition
% if true.
forall(Cond, Action) :-
\+ (Cond, \+ Action).
EDIT:
As noted by false, if you have variables in your list, you should be aware of the different behaviour of findall/3 WRT bagof/3:
?- case_a([1,2,3],X).
X = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]].
?- case_a([A,B,C],X).
X = [[_G467, _G470, _G473], [_G455, _G458, _G461], [_G443, _G446, _G449], [_G431, _G434, _G437], [_G419, _G422, _G425], [_G407, _G410, _G413]].
Note that each variable in in the second query output is different: that could be the request outcome, or not, depending on the problem at hand. Deciding the appropriate behaviour WRT the variable quantification is mandatory in the restricted class of problems where variables are data, i.e. metaprogramming, I think...