Intersection in SWI-Prolog - prolog

I am new to Prolog and I am having a little bit of trouble understanding recursion. I am trying to write a relation that finds the intersection of two sorted lists without using SWI's built-in intersect. I've used trace to see what's happening, and it's behaving as I expect up until the point where I want it to terminate and return the new list that contains the intersection. This makes me think that my base case is wrong. I've played around with several different ways of forming the base case, but it hasn't been fruitful. I've been using the lists [1, 2, 3, 4] and [2, 4, 6] as test cases with the following relations (the base case on top is just one I threw in as a placeholder... it doesn't work at all):
intersectS([], [], []).
intersectS([A | B], [C | D], Z) :- A < C, intersectS(B, [C | D], Z).
intersectS([A | B], [C | D], Z) :- A > C, intersectS([A | B], D, Z).
intersectS([A | B], [C | D], Z) :- A = C, append(Z, [A], Y), intersectS(B, D, Y).
Any help is appreciated. I've seen examples where the cut (!) operator is used alongside the member/non-member, but I'm supposed to take advantage of the fact that the lists are sorted so I thought I would try this approach. Thanks in advance.

Overall, the solution you have is partway there (as you observed). There are two areas that need fixing I think. One is, as you pointed out, the "base case". I would do it as follows:
intersectS([], _, []).
intersectS(_, [], []).
In other words, anything intersected with an empty list is empty.
The second trouble spot is the clause for A = C. You have:
intersectS([A | B], [C | D], Z) :- A = C, append(Z, [A], Y), intersectS(B, D, Y).
Which says that if the heads of the two lists match, then the intersection (Z) appended with [A] (the matching head) is the intersection of the tails of the two lists. This doesn't seem correct. I think you want to say that the intersection (Z) is the intersection of the tails B and D appended to [A], which looks like this:
intersectS([A | B], [C | D], Z) :- A = C, append([A], Y, Z), intersectS(B, D, Y).
So the whole thing looks like:
intersectS([], _, []).
intersectS(_, [], []).
intersectS([A | B], [C | D], Z) :- A < C, intersectS(B, [C | D], Z).
intersectS([A | B], [C | D], Z) :- A > C, intersectS([A | B], D, Z).
intersectS([A | B], [C | D], Z) :- A = C, append([A], Y, Z), intersectS(B, D, Y).
You can take it a step further and get rid of the append since you're just dealing with one element. append([A], Y, Z) is the same as saying Z = [A|Y]. So you can replace the last clause with simply:
intersectS([A | B], [C | D], [A | Y]) :- A = C, intersectS(B, D, Y).
Running your test case:
?- intersectS([1, 2, 3, 4], [2,4,6], L).
L = [2, 4] ;
false.
?-

Related

Prolog recursively applying a function to a list

I have a list of lists and I want to remove duplicates from all of them.
I already have the code for removing duplicates from a list.
The only thing I need to do is to apply this to the whole list and return it via the second argument.
This is what I tried.
rem_list_dup([], _).
rem_list_dup([H | T], Final) :-
remove_duplicates(H, List), /* This already works. Removes all duplicates from list H. List is the resulting list */
rem_list_dup(T, [List | Final]).
EDIT:
Example Input:
[[a, b, a], [b, b, c], [c, c, c]]
Output:
[[a, b], [b,c], [c]]
The order does not matter.
Since you understand basics of using recursion and a base case down and know how to use a tracer, you should be able to quickly understand the few changes here without needing a walk thru of the why.
remove_duplicates(List,Set) :-
list_to_set(List,Set).
rem_list_dup([],[]).
rem_list_dup([H0|T0],[H|T]) :-
remove_duplicates(H0,H),
rem_list_dup(T0,T).
:- begin_tests(rem_list_dup).
rem_list_dup_test_case_generator([[a, b, a], [b, b, c], [c, c, c]],[[a, b], [b,c], [c]]).
test(1,[forall(rem_list_dup_test_case_generator(List0,List))]) :-
rem_list_dup(List0,List).
% Based on comment by #false
test(2,[forall(rem_list_dup_test_case_generator(List0,List))]) :-
maplist(list_to_set,List0,List).
:- end_tests(rem_list_dup).
Example run using SWI-Prolog
?- consult("C:/Users/Groot/Documents/Projects/Prolog/SO_question_182.pl").
true.
?- run_tests.
% PL-Unit: rem_list_dup .. done
% All 2 tests passed
true.

Getting node from a graph prolog

I'm a newbie in Prolog, I have this question.
From this fact need getting every single node from this nodelist, how I can do?
nodelist([[a,[2,3],[b,d]],[b,[5,1],[a,c,d]],[c,[3,2],[b,d]]).
where nodelist([[node,[coordinate_node],[neighbours]]])
I've tried
node(Nodelist,Node):- nodelist(Nodelist), findall(Node,Nodelist(Nodes),Nodes).
syntax error operator expected
I show you two ways to do the job :
First way, "functionnal design" because you work with every element of the list of nodes
:- use_module(library(lambda)).
nodelist([[a,[2,3],[b,d]],[b,[5,1],[a,c,d]],[c,[3,2],[b,d]]]).
fetch_nodes(In, Out) :-
foldl(\X^Y^Z^(X = [_, _, Nodes], union(Y,Nodes, Z)), In, [], Out).
example
?- nodelist(L), fetch_nodes(L, Nodes).
L = [[a, [2, 3], [b, d]], [b, [5, 1], [a, c, d]], [c, [3, 2], [b, d]]],
Nodes = [a, c, b, d].
The second way is more "prologish", aggregate_all extends findall :
nodes(Nodelist,Nodes):-
aggregate_all(set(Node), (member([_, _, L], Nodelist), member(Node, L)),Nodes).
PS You can find details for library lambda, foldl, union and aggregate_all on the site of SWI-Prolog
Here is a complete program. Note that I had to fix your definition of nodelist/1.
nodelist([[a,[2,3],[b,d]],[b,[5,1],[a,c,d]],[c,[3,2],[b,d]]]).
node(X) :-
nodelist(L),
member([X,_,_], L).
nodes(Xs) :-
nodelist(L),
nodes(L, Xs).
nodes([], []).
nodes([[X,_,_]|L], [X|Xs]) :-
nodes(L, Xs).
and now:
?- node(X).
X = a ;
X = b ;
X = c.
?- nodes(Xs).
Xs = [a, b, c].

Write a set of prolog rules that returns a list which contains the larger item in each position in two lists of the same length?

Very, VERY new to Prolog here. My function needs to compare two lists of equal length by taking the larger number into a new list (e.g. larger([3, 12, 5], [6, 3, 11], X) returns X = [6, 12, 11].) This is what I have, but it is not getting me what I need:
larger([],[],[]).
larger([H|T],[E|A],X):- H > E, larger([T],[A],[H|X]).
larger([H|T],[E|A],X):- H < E, larger([T],[A],[E|X]).
Any help is much appreciated.
The other answer is OK, this is a slightly different approach.
Two clauses should be enough:
larger([], [], []).
larger([X|Xs], [Y|Ys], [Z|Zs]) :-
/* Z is the larger number from (X, Y) */
larger(Xs, Ys, Zs).
How you do the part in the comments depends on your exact problem statement and maybe the implementation. At least SWI-Prolog and GNU-Prolog both have an arithmetic function max() that you can use like this in the above:
larger([], [], []).
larger([X|Xs], [Y|Ys], [Z|Zs]) :-
Z is max(X, Y),
larger(Xs, Ys, Zs).
This is arguably nicer than the solution with three clauses because it won't leave behind unnecessary choice points. Like the other solution, it will work fine as long as the two lists have numbers in them.
This would be identical to using a maplist, for example like this:
larger(Xs, Ys, Zs) :-
maplist(max_number, Xs, Ys, Zs).
max_number(X, Y, Z) :- Z is max(X, Y).
You're not far.
Try with
larger([], [], []).
larger([H | T], [E | A], [H | X]) :-
H > E,
larger(T, A, X).
larger([H | T], [E | A], [E | X]) :-
H =< E,
larger(T, A, X).
If I'm not wrong, there are three errors in your code.
(1) you have to translate the bigger head value (H or E) in the third argument of larger/3, not in the recursive call
% ------- H added here ---v
larger([H | T], [E | A], [H | X]) :-
H > E,
larger(T, A, X).
% not here ----^
(2) T and A, the tails in [H|T] and [E|A], are lists, so you have to pass they recursively as T and A, not as [T] and [A]
larger([H | T], [E | A], [H | X]) :-
H > E,
larger(T, A, X).
% not larger([T], [A], X)
(3) if you have the cases H > E and H < E, your code fail when H is equal to E; one solution is H > E and H =< E; the secon case cover H equal to E.

nested list in comp

I am trying to modify my list from [a, (a s b), ( a s b s c), a] to [[a], [a, b], [a,b,c], [a]]
I tried sth like that:
:- op(300, xfy, s).
lol([], List).
lol([X|T], List) :-
X \=(A s B),
lol(T, [[X]|List]).
lol([X s P|T], List) :-
lol([P|T], [[X]|List]).
but this makes:
lol([], [[a], [b], [c], [d], [e]|_G4165]
Your base case is not correct as it leaves the tail of the constructed list unbound. It should be:
lol([], []).
The recursive cases can also be fixed as:
lol([X| Xs], [[X]| Tail]) :-
X \= s(_, _),
lol(Xs, Tail).
lol([X s P| Xs], [[X| Ps]| Tail]) :-
lol([P| Xs], [Ps| Tail]).
With these changes we get:
?- lol([a, (a s b), ( a s b s c), a], List).
List = [[a], [a, b], [a, b, c], [a]] .
To avoid spurious choice points you can either add a cut in the first recursive case:
lol([X| Xs], [[X]| Tail]) :-
X \= s(_, _),
!,
lol(Xs, Tail).
Or combine the two recursive cases using an if-then-else control construct (left as an exercise).

prolog predicates - swap

I have an exam in Prolog today and am revising for it using old questions.
Would answer c be the incorrect answer? Can anyone please explain this to me? It would be very helpful. Thank you,
Consider the following predicate:
swap([], []).
swap([X1, X2 | L], [X2, X1 | S]) :- swap(L, S).
Which of the following query and answer pairs is incorrect:
(a) ?- swap([a,b,c,d], S).
S = [b, a, d, c].
(b) ?- swap([a,b,d], H).
false.
(c) ?- swap([a,a,b,b], S).
S = [b, b, a, a].
(d) ?- swap([], S).
S = [].
(c) is indeed the incorrect answer. Item (c) has the following query:
swap([a,a,b,b], S).
If you run this query manually, it clearly doesn't match the clause swap([], []). It then does match the second clause: swap([X1,X2|L], [X2,X1|S]) :-....
swap([a, a, b, b], S).
swap([X1, X2 | L], [X2, X1 | S]) :- swap(L, S).
==> X1 = a, X2 = a, L = [b, b]
==> swap([a, a| [b,b]], [a, a | S]) :- swap([b, b], S).
Prolog can instantiate the first argument [X1,X2|L] with the given list, [a,a,b,b]. That, then, means X1 = a, X2 = a, and the rest of the list, L = [b,b]. Already from this information, you know that the list [X2,X1|S] is [a,a|S] but the answer shown by (c) is [b,b,a,a]. You don't even need to find out what S because since you know alrady that [a,a|S] isn't going to match [b,b,a,a].

Resources