Prolog intersection of 2 lists of lists - prolog

I am trying to find the intersection of 2 different lists of lists. In other words, find out if all the lists in list1 intersect with any of the lists in list 2.
List1:
[[1,4],[1,6],[6,8],[8,10]]
List2:
[[], [10], [8], [8, 10], [6], [6, 10], [6, 8], [6, 8, 10]]
I want to find an item in list2 where all the items of list1 intersect.
A solution would be [4,6,8]
How would I do this?

A very simple implementation could be the following
intersect(L, M, E) :-
member(E, M),
maplist(intersect_(E), L).
intersect_(L, M) :-
member(E, L),
member(E, M).
Example queries:
?- intersect([[1,4],[1,6],[6,8],[8,10]], [[], [10], [8], [8, 10], [6], [6, 10], [6, 8], [6, 8, 10]], E).
false.
?- intersect([[1,4],[1,6],[6,8],[8,10]], [[], [10], [8], [8, 10], [6], [6, 10], [6, 8], [6, 8, 10], [4,6,8]], E).
E = [4, 6, 8] ;
E = [4, 6, 8] ; % This succeeds twice because the list [6,8] has two ways of satisfying the predicate
false.

Related

Prolog can't figure out how to append

I have a simple problem, and I know why what I'm doing is wrong, I just dont know how to do what I want.
I want to be able to find the max of list X and then append it to the result Xs. It would recurse slowly sorting the list until it was finished. I know there are better sorting algorithms but I want to try and make my problem work.
These are the 2 version of the code that I have tried but I seem to be getting no where
mysort([],_).
mysort([X,Y], Xs) :- max(X,M), mysort(Y,[M|Xs]).
mysort([],_).
mysort([X,Y], Xs) :- max(X,M),append(Xs, [M], Xs) mysort(Y,[M|Xs]).
I would hope to have some kind of hint to completing this code, or someone fixing this silly problem.
I am not sure if I understood your question correctly, but maybe you can use some of this:
Example one:
mysort(List, Result) :-
aggregate(max(X), member(X, List), Result).
Result:
mysort([1,2,3,4], Result).
Result = 4
Example two:
mysort(List, MaxList, Result) :-
aggregate(max(X), member(X, List), Max),
append(MaxList, [Max], Result).
Result:
mysort([1,2,300,3], [100, 200], Result)
Result = [100, 200, 300]
Example three:
mysort(List, Result) :- mysort(List, [], Result).
mysort([], Result, Result).
mysort([H | T], Tmp, Result) :-
aggregate(max(X), member(X, H), Max),
TmpResult = [Max | Tmp],
mysort(T, TmpResult, Result).
Result:
mysort([[122,2,3,4, 6, 10], [127,2,3,4, 6, 10], [127,2,3,4, 6, 10]], Result).
Result = [127, 127, 122]
[X,Y] is a list of 2 elements, then is not what you want.
Instead, you should concentrate on building a predicate select_max/3, that 'extracts' the maximal value and returns it and the list without it.
We could code it adapting the select/3 library predicate:
select_max(Max,List,Rest) :-
select(Max,List,Rest),
\+ (member(Other,List),Other#>Max).
Now you can try to build the main recursive mysort/2, I will left to you as an exercise (remember that the base case should instantiate the output list to empty).
First, you need a predicate to select a maximum element, separating it from the rest of the list. To do so:
Start by taking the first element of the list [X|Xs] as the current maximum element.
Then, recursively traverse the rest of the list (Xs) by comparing the current maximum element (X0) to the current first element (X1), separating the biggest of the two and putting the other in the rest.
Finally, when the list is empty, the current maximum element (Max) is indeed the maximum element of the original list.
% select_max(-Max, +List, -Rest)
select_max(Max, [X|Xs], Rest) :-
select_max(Xs, X, Max, Rest).
select_max([], Max, Max, []).
select_max([X1|Xs], X0, Max, [Lesser|Rest]) :-
compare(Relation, X0, X1),
sorted(Relation, X0, X1, Lesser, Bigger),
select_max(Xs, Bigger, Max, Rest).
sorted(=, A, B, A, B).
sorted(<, A, B, A, B).
sorted(>, A, B, B, A).
Example:
?- trace(select_max, +all), select_max(M, [5,3,7,1], R), trace(select_max, -all).
% select_max/3: [all]
% select_max/4: [all]
T [11] Call: select_max(_30924434, [5, 3, 7, 1], _30924438)
T [20] Call: select_max([3, 7, 1], 5, _30924434, _30924438)
T [29] Call: select_max([7, 1], 5, _30924434, _30929268)
T [38] Call: select_max([1], 7, _30924434, _30930168)
T [47] Call: select_max([], 7, _30924434, _30931068)
T [47] Exit: select_max([], 7, 7, [])
T [38] Exit: select_max([1], 7, 7, [1])
T [29] Exit: select_max([7, 1], 5, 7, [5, 1])
T [20] Exit: select_max([3, 7, 1], 5, 7, [3, 5, 1])
T [11] Exit: select_max(7, [5, 3, 7, 1], [3, 5, 1])
% select_max/3: Not tracing
% select_max/4: Not tracing
M = 7,
R = [3, 5, 1].
Afterwards, you should use predicate select_max/3 to define your sorting algorithm (aka. Bubble Sort) as follows:
% mysort(+List, -SortedList)
mysort(List, SortedList) :-
mysort(List, [], SortedList).
mysort([], SortedList, SortedList).
mysort([X|Xs], SortedSuffix, SortedList) :-
select_max(Max, [X|Xs], Rest),
mysort(Rest, [Max|SortedSuffix], SortedList).
Example:
?- trace(mysort, +all), mysort([5,3,7,1], S), trace(mysort, -all).
% mysort/2: [all]
% mysort/3: [all]
T [11] Call: mysort([5, 3, 7, 1], _36832)
T [20] Call: mysort([5, 3, 7, 1], [], _36832)
T [29] Call: mysort([3, 5, 1], [7], _36832)
T [38] Call: mysort([3, 1], [5, 7], _36832)
T [47] Call: mysort([1], [3, 5, 7], _36832)
T [56] Call: mysort([], [1, 3, 5, 7], _36832)
T [56] Exit: mysort([], [1, 3, 5, 7], [1, 3, 5, 7])
T [47] Exit: mysort([1], [3, 5, 7], [1, 3, 5, 7])
T [38] Exit: mysort([3, 1], [5, 7], [1, 3, 5, 7])
T [29] Exit: mysort([3, 5, 1], [7], [1, 3, 5, 7])
T [20] Exit: mysort([5, 3, 7, 1], [], [1, 3, 5, 7])
T [11] Exit: mysort([5, 3, 7, 1], [1, 3, 5, 7])
% mysort/2: Not tracing
% mysort/3: Not tracing
S = [1, 3, 5, 7].
More examples:
?- mysort([], S).
S = [].
?- mysort([5], S).
S = [5].
?- randseq(5, 100, L), mysort(L, S).
L = [77, 68, 11, 38, 65],
S = [11, 38, 65, 68, 77].
?- randseq(7, 100, L), mysort(L, S).
L = [57, 5, 16, 8, 11, 53, 55],
S = [5, 8, 11, 16, 53, 55, 57].

how to print all nodes from a particular node

I have the following knowledge base:
connects(1,11,10,8).
connects(1,12,2,6).
connects(1,13,-3,-2).
connects(1,14,1,-5).
I have this predicates:
friends(Node, L):-
findall(X,(connects(Node,X,_,_);connects(X,Node,_,_)),L).
when i make the question ?- friends(1,L) i have this:
L = [11, 12, 13, 14].
But my goal is print a list like this:
L = [11,10,8,12,2,6,13,-3,-2,14,-5]
How can i achieve it?
It's not clear to me what relationship the predicate actually represents. Anyway, you can proceed as follows:
First, use findall to collect the data you need as a list of lists:
?- findall([X,Y,Z], connects(1,X,Y,Z), L).
L = [[11, 10, 8], [12, 2, 6], [13, -3, -2], [14, 1, -5]].
After that, you can use append to get a flatten list:
?- findall([X,Y,Z], connects(1,X,Y,Z), L0), append(L0, L1).
L0 = [[11, 10, 8], [12, 2, 6], [13, -3, -2], [14, 1, -5]],
L1 = [11, 10, 8, 12, 2, 6, 13, -3, -2, 14, 1, -5].
Putting it all together, you can define friends/2 as:
friends(Node, L1):-
findall([X,Y,Z],
( connects(Node, X,Y,Z)
; connects(X, Node, Y,Z) ), L0),
append(L0, L1).
Assuming that you are can change the predicate. Replacing the _s with variables will give you the values you need. And then use flatten/2 to turn the matrix (2D list) into a simple 1D list.
This should solve your problem.
friends(Node, L):-
findall([X, Y, Z], (connects(Node, X, Y, Z)), A),
flatten(A, L).
Example output:
?- friends(1, L)
L = [11, 10, 8, 12, 2, 6, 13, -3, -2, 14, 1, -5]

How to create a list without using findall? Prolog

I am generating permutations:
takeout(X,[X|T],T).
takeout(X,[F|R],[F|S]):-
takeout(X,R,S).
perm([],[]).
perm([X|Y],Z):-
perm(Y,W),
takeout(X,Z,W).
I want to know how to create a list of all the permutations without using findall.
Example:
?-perm([1,2,3],List).
List = [[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2], [3, 2, 1]]
Group permutations by the element it starts with.
Take an element X and create permutations Ys1 without it in the original list.
Adding this element X as the first element of all these permutations we have the list XP of permutations starting with X.
Appending all the groups will give you all permutations.
cons(X, Xs, [X|Xs]).
perm([], [[]]).
perm(Xs, Ys) :-
dif(Xs, []),
maplist({Xs}/[X, XP]>>(select(X, Xs, Xs1),
perm(Xs1, Ys1),
maplist(cons(X), Ys1, XP)),
Xs, Yss),
append(Yss, Ys).
?- perm([1, 2, 3], X).
X = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] ;
false.
?- length(Y, 8), perm(Y, X), length(X, N). %8 factorial
N = 40320
The idea is to generate permutations and test if you already created this permutation. I'm using the inbuild predicate permutation/2.
perm(Ori,Out):-
perm(Ori,[],Out).
perm(Ori,Acc,Ret):-
permutation(Ori,Perm),
\+ member(Perm,Acc),
!,
perm(Ori,[Perm|Acc],Ret).
perm(_,L,L).
?- perm([1,2,3],E).
E = [[3, 2, 1], [3, 1, 2], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]].
The code is not the fastest one since it checks multiple times for membership.

Prolog merge sort a list that is inside a list

For an example I need to sort:
?- mergesort([8,1,[4,6,3],2],Sorted).
The outcome should be:
Sorted = [1, 2, 8, [3, 4, 6]]
Unfortunately I'm not sure what to do. I've tried to find an answer myself, but didn't find a solution. Currently the outcome is:
Sorted = [1, 2, 8, [4, 6, 3]]
My code:
mergesort([],[]).
mergesort([A],[A]).
mergesort([A,B|R],S) :-
split([A,B|R],L1,L2),
mergesort(L1,S1),
mergesort(L2,S2),
merge(S1,S2,S).
split([],[],[]).
split([A],[A],[]).
split([A,B|R],[A|Ra],[B|Rb]) :- split(R,Ra,Rb).
merge(A,[],A).
merge([],B,B).
merge([A|Ra],[B|Rb],[A|M]) :- A #=< B, merge(Ra,[B|Rb],M).
merge([A|Ra],[B|Rb],[B|M]) :- A #> B, merge([A|Ra],Rb,M).
Big thanks in advance!
I would write a simple preprocessing step:
sortl([H|T],[Hs|Ts]) :-
( is_list(H)
-> mergesort(H,Gs),
sortl(Gs,Hs)
; Hs = H
),
sortl(T,Ts).
sortl([],[]).
then you could use it this way
?- sortl([8,1,[4,6,[3,4],[1,8],3],2,[1,3,2]],T),mergesort(T,Sorted).
T = [8, 1, [3, 4, 6, [1, 8], [3|...]], 2, [1, 2, 3]],
Sorted = [1, 2, 8, [1, 2, 3], [3, 4, 6, [...|...]|...]]

Prolog insertion sort

There is a simple Prolog insertion sort alghoritm:
sorting([A|B], Sorted) :- sorting(B, SortedTail), insert(A, SortedTail, Sorted).
sorting([], []).
insert(A, [B|C], [B|D]) :- A #> B, !, insert(A, C, D).
insert(A, C, [A|C]).
It does well on normal lists:
?- sorting([5, 4, 9, 1, 3, 8], X).
X = [1, 3, 4, 5, 8, 9].
But I also need to sort sublist of list contains any of them:
?- sorting([2, 5, [5, 4, 3], [6, 3], 4, 8], X).
X = [2, 4, 5, 8, [5, 4, 3], [6, 3]].
Is what return now. And
?- sorting([2, 5, [5, 4, 3], [6, 3], 4, 8], X).
X = [2, 4, 5, 8, [3, 4, 5], [3, 6]].
what I need to return. So how can I sort sublist too? Thanks in advance!
I offer this simple solution:
Insert element in the sorted list
insert(X, [], [X]):- !.
insert(X, [X1|L1], [X, X1|L1]):- X=<X1, !.
insert(X, [X1|L1], [X1|L]):- insert(X, L1, L).
Use principe of insertion sort algorithm
insertionSort([], []):- !.
insertionSort([X|L], S):- insertionSort(L, S1), insert(X, S1, S).

Resources