Prolog: getting rid of a recursive helper predicate - prolog

So I'm trying to get rid of the wrapper clause by using the sort library predicate directly inside split. What split does is just generating a list of numbers from a list that looks like this: [1:2,3:2,4:6] ---split--> [1,2,3,2,4,6]. But the generated list contains duplicates, and I don't want that, so I'm using the wrapper to combine split and sort, which then generates the desired result: [1,2,3,4,6].
I'd really like to get rid of the wrapper and just use sort within split, however I keep getting "ERROR: sort/2: Arguments are not sufficiently instantiated." Any ideas? Thanks :)
split([],[]).
split([H1:H2|T],[H1,H2|NT]) :-
split(T,NT).
wrapper(L,Processed) :-
split(L,L2),
sort(L2,Processed).

I'd really like to get rid of the wrapper and just use sort within split
Then use findall with a complex goal such as
split(Edges, NodeSet) :-
findall(Node,
(member(Edge, Edges), (Edge = (Node:_); Edge = (_:Node))),
NodeList),
sort(NodeList, NodeSet).
However, once you start using aggregating predicates, you could just as well skip the sort and use setof:
split(Edges, NodeSet) :-
setof(Node, Edge^Pair^(member(Edge, Edges),
Edge =.. [:|Pair],
member(Node,Pair)),
NodeSet).
Read as: get the set of all Node s.t. there exists Edge and there exists Pair s.t. (etc.) and call that NodeSet.
The =.. ("univ") operator deconstructs a pair: Edge =.. [:, Left, Right]. For better readability, you can write a separate predicate to get nodes from edges:
% endpoint(Edge, Node) is true iff Node is an endpoint of Edge
endpoint(Node:_, Node).
endpoint(_:Node, Node).
split(Edges, NodeSet) :-
setof(Node, Edge^(member(Edge, Edges), endpoint(Edge, Node)), NodeSet).
EDIT Before you try this approach, see the discussion below this answer for whether or not this is a better idea than the OP's original code.

Related

Removing unique elements from list in prolog

I am attempting to remove unique elements from a list in Prolog.
Output should look something like:
?- rem_Uniq([3,3,1,7,a,c,c],D).
D = [3, c].
Here is my current code.
rem_Uniq(L1,L2).
rem_Uniq([L1|RL1], [L1|D]) :-
member(L1,RL1),
rem_Uniq(RL1,D).
rem_Uniq([L1|RL1], D) :-
remove(L1[L1|RL1], O),
rem_Uniq(O, D).
Currently it just returns true no matter what I do (whether I enter I list containing unique variables or not).
Anyone have any ideas or suggestions on what I am doing wrong?
D is the set of elements of the list which appears only one time.
In Prolog "an element which appears only one time in a list" can be translate by
select(X, L, L_X),
\+member(X, L_X)
In Prolog exist predicates that collect element with a certain property setof/3 and bagof/3.
bagof collect all the elements, setof keeps only one element.
So you can write
rem_uniq(In, Out) :-
setof(X, In_X^(select(X, In, In_X),\+member(X, In_X)), Out).
[EDIT]
Now we want only elements that are duplicated in a list. If I remove one of these elements of the list, it will remain other elements of the same value in the list so it can be translated in Prolog by
select(X, In, In_X),
member(X, In_X)
(we say that select(X, In, In_X),member(X, In_X) succeed).
Now the code can be written
rem_uniq(In, Out) :-
setof(X, In_X^(select(X, In, In_X),member(X, In_X)), Out).
For example
?- rem_uniq([3,3,1,7,a,c,c],D).
D = [3,c].
Note that setof will fail if there no elements available
?- rem_uniq([3,1,7,a,c],D).
false.
Well, your first problem is your first clause:
rem_Uniq(L1,L2).
This literally says "Any two things are rem_Uniq to each other." This is what's giving rise to always getting true with no unifications. You probably meant this:
rem_Uniq([], []).
Your second problem is that this is not valid syntax:
remove(L1[L1|RL1], O),
Specifically, L1[L1|RL1], I am unclear what you meant there. I think you meant this delete(L1, [L1|RL1], O).
Now, algorithmically, I think you're a little confused. In clause #2, you prepend L1 to D in the result, which is to say, after knowing that L1 is present in RL1 and using the recursive call to remove it from D. But then in clause #3, you just remove it from [L1|RL1] to make O, which you then remove uniques from.
Each clause of a recursive predicate should represent a case you have to worry about. I don't really see what these clauses mean. The first one should be, in case where the list is empty. The second one should be the case where the list is not empty. What you seem to be trying to do here is something like, in the case where the list is not empty and contains the head element, and the case where it is not empty and does not contain the head element, but the distinction between having or not having that element is (or ought to be) meaningless to your library routine. In other words, delete/3 in one non-empty recursive case should be totally sufficient for this problem:
rem_uniq([], []).
rem_uniq([X|Xs], [X|UniqueXs]) :-
delete(X, Xs, XsWithoutX),
rem_uniq(XsWithoutX, UniqueXs).
So, I think you have a little confusion about when and why you should have multiple clauses, and I think your choice of variable names may have made life harder on yourself. But that's just my guess.
Hope this helps!

Prolog - Append some elements form a list to another one

I need to append some elements from a list to another like this:
find_same(pt(1,1),pt(2,2),6,[slope(6,pt(3,3)),slope(6,pt(4,4)),slope(7,pt(3,2)),slope(9,pt(5,5))],NL).
result
NL=[pt(1,1),pt(2,2),pt(3,3),pt(4,4)]
I have tried using append but i have some problem, with this code:
find_same(_,_,_,[],_):-!.
find_same(pt(X,Y),pt(Xa,Ya),R,Slopes,Nl):-X\=a,
append(Nla,[pt(X,Y),pt(Xa,Ya)],Nl),
find_same(pt(a,a),pt(b,b),R,Slopes,Nla).
find_same(pt(X,Y),pt(Xa,Ya),R,[slope(R,pt(Xs,Ys))|Ss],Nl):-X=a,
append(Nla,[pt(Xs,Ys)],Nl),
find_same(pt(X,Y),pt(Xa,Ya),R,Ss,Nla).
find_same(_,_,R1,[slope(R2,_)|_],_):-R1\=R2,!.
because return me a lot of list.
then i tried with this other code:
find_same2(_,_,_,[],_):-!.
find_same2(pt(X,Y),pt(Xa,Ya),R,Slopes,_):-X\=a,
find_same2(pt(a,a),pt(b,b),R,Slopes,[pt(X,Y),pt(Xa,Ya)]).
find_same2(pt(X,Y),pt(Xa,Ya),R,[slope(R,pt(Xd,Yd))|Ss],[pt(Xd,Yd)|Nl]):-
X=a,!,
find_same2(pt(X,Y),pt(Xa,Ya),R,Ss,Nl).
find_same2(_,_,R1,[slope(R2,_)|_],_):-R1\=R2.
But it returns only false.
how can i solve this problem? thank you
Because you don't care what the specific components of the points are, you can treat each point as a single variable. So instead of pt(X, Y) for example, just consider it P.
So you want to find the common points:
find_common(P1, P2, N, SlopeList, Result)
If you can create a sublist of elements from SlopeList which meet your criteria, then you can form Result by prepending the two existing points. If that sublist is called, CommonPoints, then your Result would just be [P1, P2 | CommonPoints].
Now you only need to figure out how to determine CommonPoints. You can use member/2 to do this. Consider:
member(slope(N, P), SlopeList)
This will succeed for each element of SlopeList that has an element slope(N, P). To gather them together, you can use findall/3:
findall(P, member(slope(N, P), SlopeList), CommonPoints).
Those are all the pieces you need to solve your problem. You just have to put them together.

How to make an operation to every element of a list

I find myself narrowing a (very simple) problem more and more.
Let's say I have this operation: listsplit([H1,H2,H3|T], H1,H2,H3, T).
Which gives me the first three elements of a list. I want a program, cells, to travel an input list and make (at least that ONE operation!!) to every element of the list.
So I have something like:
cells(Input, Result):-
cellsBody(Input, [], Result).
cellsBody([],Result,Result).
cellsBody([Head|Input], Acc, [Headd|Result]):-
listsplit(Input,H1,H2,H3,_),
cellsBody(Input, [OutputBody|Acc], Result).
I have that code because I have used many I've seen as examples that go like that to travel a list. They separate head from body and go on. I fail to see how this is done in prolog. I tried changing variable names, so that they would match (as I would do in other languages), and I've tried to make the problem as simple as possible.
So, how do I travel a list AND make operations to every element (that I choose to, starting with the first one, the head).
Edit: Examples of what I want to archieve:
I get an input list like oxo, oxxxo, oxoxo, so on. I then apply a rule to the first three elements, then the next three, and so on, and while I do that I add the result of the rule to another list that I return (which is why I am trying to use the accumulator).
You've almost got it. Keeping your predicate cells/2 as is, think about the special cases first: The lists [], [_], [_,_] haven't got three elements, so whatever operation you have in mind for those three elements, there's nothing to do in these cases. Otherwise you have a recursive rule to do what you intend to.
Looking at listsplit/5: you can do that directly in the head of the recursive rule, no need for an extra predicate. Then you have one or more goals for your intended operation. For the sake of an example let's say packaging the 3 head elements as a triplet. And of course the relation must hold for the tail T of the list too. Then your code might look something like that:
cellsBody([],Result,Result).
cellsBody([_],Result,Result).
cellsBody([_,_],Result,Result).
cellsBody([H1,H2,H3|T], Acc, Result):- % the first 3 elements
Triplet=(H1,H2,H3), % at least ONE operation with them
cellsBody(T, [Triplet|Acc], Result).
Example queries:
?- cells([],Result).
Result = []
?- cells([1],Result).
Result = []
?- cells([1,2],Result).
Result = []
?- cells([1,2,3],Result).
Result = [(1,2,3)]
?- cells([1,2,3,4,5,6,7],Result).
Result = [(4,5,6),(1,2,3)]
Of course, if the intended operation is as simple as in the above example, you don't need an extra goal for it: You can do that directly in the recursive goal:
cellsBody([H1,H2,H3|T], Acc, Result):-
cellsBody(T, [(H1,H2,H3)|Acc], Result).

Hierarchical Agglomerative Clustering in Prolog

I'm trying to re-familiarize myself with Prolog and I thought this could be the type of problem with an elegant solution in Prolog.
I'm following along this example:
http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/hierarchical.html
I've tried a variety of data formats:
dist('BA','FI',662).
dist(0,'BA','FI',662).
dist(['BA'],['FI'],662).
but I haven't found any particular one most suitable.
Here's all the data in the first format:
%% Graph distances
dist('BA','FI',662).
dist('BA','MI',877).
dist('BA','NA',255).
dist('BA','RM',412).
dist('BA','TO',996).
dist('FI','MI',295).
dist('FI','NA',468).
dist('FI','RM',268).
dist('FI','TO',400).
dist('MI','NA',754).
dist('MI','RM',564).
dist('MI','TO',138).
dist('NA','RM',219).
dist('NA','TO',869).
dist('RM','TO',669).
Now, there seems to be some awesome structure to this problem to exploit, but I'm really struggling to get a grasp of it. I think I've got the first cluster here (thought it may not be the most elegant way of doing it ;)
minDist(A,B,D) :- dist(A,B,D), dist(X,Y,Z), A \= X, A \= Y, B \= X, B \= Y, D < Z.
min(A,B,B) :- B < A
min(A,B,A) :- A < B
dist([A,B],C, D) :- minDist(A,B,D), dist(A,C,Q), dist(B,C,W), min(Q,W,D)
The problem I have here is the concept of "replacing" the dist statements involving A and B with the cluster.
This just quickly become a brainteaser for me and I'm stuck. Any ideas on how to formulate this? Or is this perhaps just not the kind of problem elegantly solved with Prolog?
Your table is actually perfect! The problem is that you don't have an intermediate data structure. I'm guessing you'll find the following code pretty surprising. In Prolog, you can simply use whatever structures you want, and it will actually work. First let's get the preliminary we need for calculating distance without regard for argument order:
distance(X, Y, Dist) :- dist(X, Y, Dist) ; dist(Y, X, Dist).
This just swaps the order if it doesn't get a distance on the first try.
Another utility we'll need: the list of cities:
all_cities(['BA','FI','MI','NA','RM','TO']).
This is just helpful; we could compute it, but it would be tedious and weird looking.
OK, so the end of the linked article makes it clear that what is actually being created is a tree structure. The article doesn't show you the tree at all until you get to the end, so it isn't obvious that's what's going on in the merges. In Prolog, we can simply use the structure we want and there it is, and it will work. To demonstrate, let's enumerate the items in a tree with something like member/2 for lists:
% Our clustering forms a tree. So we need to be able to do some basic
% operations on the tree, like get all of the cities in the tree. This
% predicate shows how that is done, and shows what the structure of
% the cluster is going to look like.
cluster_member(X, leaf(X)).
cluster_member(X, cluster(Left, Right)) :-
cluster_member(X, Left) ; cluster_member(X, Right).
So you can see we're going to be making use of trees using leaf('FI') for instance, to represent a leaf-node, a cluster of N=1, and cluster(X,Y) to represent a cluster tree with two branches. The code above lets you enumerate all the cities within a cluster, which we'll need to compute the minimum distance between them.
% To calculate the minimum distance between two cluster positions we
% need to basically pair up each city from each side of the cluster
% and find the minimum.
cluster_distance(X, Y, Distance) :-
setof(D,
XCity^YCity^(
cluster_member(XCity, X),
cluster_member(YCity, Y),
distance(XCity, YCity, D)),
[Distance|_]).
This probably looks pretty weird. I'm cheating here. The setof/3 metapredicate finds solutions for a particular goal. The calling pattern is something like setof(Template, Goal, Result) where the Result will become a list of Template for each Goal success. This is just like bagof/3 except that setof/3 gives you unique results. How does it do that? By sorting! My third argument is [Distance|_], saying just give me the first item in the result list. Because the result is sorted, the first item in the list will be the smallest. It's a big cheat!
The XCity^YCity^ notation says to setof/3: I don't care what these variables actually are. It marks them as "existential variables." This means Prolog will not provide multiple solutions for each city combination; they will all be thrown together and sorted once.
This is all we need to perform the clustering!
From the article, the base case is when you have two clusters left: just combine them:
% OK, the base case for clustering is that we have two items left, so
% we cluster them together.
cluster([Left,Right], cluster(Left,Right)).
The inductive case takes the list of results and finds the two which are nearest and combines them. Hold on!
% The inductive case is: pair up each cluster and find the minimum distance.
cluster(CityClusters, FinalCityClusters) :-
CityClusters = [_,_,_|_], % ensure we have >2 clusters
setof(result(D, cluster(N1,N2), CC2),
CC1^(select(N1, CityClusters, CC1),
select(N2, CC1, CC2),
cluster_distance(N1, N2, D)),
[result(_, NewCluster, Remainder)|_]),
cluster([NewCluster|Remainder], FinalCityClusters).
Prolog's built-in sorting is to sort a structure on the first argument. We cheat again here by creating a new structure, result/3, which will contain the distance, the cluster with that distance, and the remaining items to be considered. select/3 is extremely handy. It works by pulling an item out of the list and then giving you back the list without that item. We use it twice here to select two items from the list (I don't have to worry about comparing a place to itself as a result!). CC1 is marked as a free variable. The result structures will be created for considering each possible cluster with the items we were given. Again, setof/3 will sort the list to make it unique, so the first item in the list will happen to be the one with the shortest distance. It's a lot of work for one setof/3 call, but I like to cheat!
The last line says, take the new cluster and append it to the remaining items, and forward it on recursively to ourself. The result of that invocation will eventually be the base case.
Now does it work? Let's make a quick-n-dirty main procedure to test it:
main :-
setof(leaf(X), (all_cities(Cities), member(X, Cities)), Basis),
cluster(Basis, Result),
write(Result), nl.
Line one is a cheesy way to construct the initial conditions (all cities in their own cluster of one). Line two calls our predicate to cluster things. Then we write it out. What do we get? (Output manually indented for readability.)
cluster(
cluster(
leaf(FI),
cluster(
leaf(BA),
cluster(
leaf(NA),
leaf(RM)))),
cluster(
leaf(MI),
leaf(TO)))
The order is slightly different, but the result is the same!
If you're perplexed by my use of setof/3 (I would be!) then consider rewriting those predicates using the aggregate library or with simple recursive procedures that aggregate and find the minimum by hand.

Prolog Connected Edge of a graph

I want to make a predicate that check if a node can reach another node in graph in prolog. e.g Connected(1,X,[[1,3],[3,4],[2,5]]) The first argument is the node I want to start the second is the node I want to reach and the third is a list of edges. So far I have managed to do it but I get an infinite loop when I try to get all the nodes I reach by using findall/3.
Is there any way to stop the infinite loop or I should thing the problem from the beggining?
Here is my code so far:
match([X,Y],List):- member([X,Y], List).
match([X,Y],List):- member([Y,X], List).
go(X,Y,List):-match([X,Y],List).
go(X,Y,List):-match([X,Z],List),go(Z,Y,List).
goes(X,List,List2):-findall(Y,go(X,Y,List),List2).
I am new in Prolog and I cannot figure out what I am doing wrong.
a possible correction to your code
match([X,Y], List, Rest):- select([X,Y], List, Rest).
match([X,Y], List, Rest):- select([Y,X], List, Rest).
go(X,Y,List) :- match([X,Y],List,_).
go(X,Y,List) :- match([X,Z],List,Rest), go(Z,Y,Rest).
goes(X,List,List2) :- findall(Y, go(X,Y,List), List2).
now match 'consumes' an edge, then avoid infinite looping
Have a look at what ?- gtrace, goes(1,[[1,3],[3,4],[2,5]], X). Does.
For all recursions go :- go you need a condition when it stops.
In you case I recommend to add an argument Traversed which is a list of all nodes(or edges) you have visited. Then you do not go over nodes again if you have visited them already.
So you get less and less elements to recursively look at and the recorsion ends at some point.
Many recursions use the predicate !. Have a look at it.

Resources