how to print all nodes from a particular node - prolog

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]

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

Prolog intersection of 2 lists of lists

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.

Removing list within lists based on nth element

I've got a list of lists, for example:
[[1, 2, 3, 2], [1, 3, 4, 3], [1, 4, 5, 4], [2, 3, 5, 6], [1, 5, 6, 5],
[2, 4, 6, 8], [1, 6, 7, 6], [2, 5, 7, 10], [3, 4, 7, 12], [2, 6, 8, 12]]
I'd like to get the last element of and check to see if is the same as the 4th element of any of the other lists. If it is the same then leave the list alone, but if it is unique then remove the list. So in the example above I would be left with:
[[3, 4, 7, 12], [2, 6, 8, 12]]
Essentially I want to be remove all the lists where the last element is unique.
I've written a predicate to get the nth element:
my_membership(X, [X|_]).
my_membership(X, [_|Tail]) :-
my_membership(X, Tail).
where:
my_membership([_,_,_,Fourth],[[3, 4, 7, 12], [2, 6, 8, 12]]).
gives:
Fourth = 12
Fourth = 12
Start by building two basic predicates:
last([X], X).
last([_|T], X) :- last(T, X).
forth([_,_,_,F|_], F).
The first predicate extracts the last element of a list; the second predicate extracts the forth element of a list.
Now you can make a predicate that counts how many tomes an element X appears in forth place in any of the lists of a list of lists. Below, H in [H|T] is a list:
matching_forth([], _, 0).
matching_forth([H|T], X, R) :- forth(H, X), matching_forth(T, X, RR), R is RR + 1.
matching_forth([_|T], X, R) :- matching_forth(T, X, R).
With these predicates in place you can build a predicate for checking your condition. It will have three clauses - for a situation when the list is empty, for when the head list has a matching forth element in another list, and for situations when it doesn't:
my_membership([], [], _).
my_membership([H|T], [H|R], A) :-
last(H, X), matching_forth(A, X, C), C > 1, my_membership(T, R, A).
my_membership([_|T], R, A) :- my_membership(T, R, A).
The first and last clauses are self-explanatory. The middle clause extracts the last element from the head list, counts how many times it matches the forth element in the original list of lists (A stands for "all"), and adds H to the result when there is a match. Adding happens through unification with the head of the result list.
Finally, you need a my_membership/2 predicate to start off the recursive chain that passes along the original list of lists:
my_membership(L, R) :- my_membership(L, R, L).
Demo.
Here's a different twist on a potential solution. It uses an accumulator to collect members that we've seen already and checks along the way. The result saves those that have either been seen or are currently in the tail. It requires the use of the built-in, memberchk/2.
my_membership(L, R) :-
my_membership(L, [], R).
my_membership([], _, []).
my_membership([X|T], Acc, R) :-
X = [_,_,_,D],
( memberchk([_,_,_,D], Acc)
-> R = [X|T1],
Acc1 = Acc
; memberchk([_,_,_,D], T)
-> R = [X|T1],
Acc1 = [X|Acc]
; R = T1,
Acc1 = Acc
),
my_membership(T, Acc1, T1).
| ?- my_membership([[1, 2, 3, 2], [1, 3, 4, 3], [1, 4, 5, 4], [2, 3, 5, 6], [1, 5, 6, 5],
[2, 4, 6, 8], [1, 6, 7, 6], [2, 5, 7, 10], [3, 4, 7, 12], [2, 6, 8, 12]], L).
L = [[2,3,5,6],[1,6,7,6],[3,4,7,12],[2,6,8,12]]
yes

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