Re-organizing a list in prolog - list

I am trying to write some Prolog code to take a list such as:
[[park, joe], [park, bob], [park, kate], [school, joe], [zoo, amy], [zoo, ted]].
and organizes the list into the form:
[[park,[joe, bob, kate]], [school,[joe]], [zoo,[amy, ted]]].
It can be assumed that all matching heads of each element (park = park, zoo = zoo) are directly next to each other in the list because the code I made to create the list sorts it in alphabetical order. I can't seem to figure out how to accomplish this and seem to get errors at every turn :(. Below is the code that I have so far in the last state that it ran without errors and I will try to explain what I was thinking.
merge([],[]).
merge([First|Rest], Z) :-
merge(Rest, U),
[Meet1, Person1] = First,
( =(U, []) -> % beginning case from recursion, U is empty
Meet2 = [],
Person2 = [];
[[Meet2|Person2]|_] = U),
( =(Meet1, Meet2) -> % Case of matching heads, combine the tails
print('Match '),
append([First], U, Z);
print('No-match '), % otherwise, not matching
append([First], U, Z) ).
So what I was trying to do is use appends to add all of the changes to U and return it to the console with Z. such as,
( =(Meet1, Meet2) ->
append(Person1, Person2, Combpersons),
append([Meet1], [Combpersons], T),
append(T, U, Z);
...no match code here..).
However my code keeps ending prematurely with a false when I try to change or add appends like this in the first block of code I put here. Even a change such as turning append([First], U, Z) into append([Meet1], U, Z) makes my code end with a false and I am not understanding why. Any help/hints on creating a solution would be appreciated.

I think that learning any language it's a process where low and high level issues must be interleaved. So far, you're learning the basic syntax. But why you use such unreadable constructs ? And of course, any programming language builds upon a set of patterns, usually covered by libraries. Consider
l2p([A,B],A-B).
?- maplist(l2p,[[park, joe], [park, bob], [park, kate], [school, joe], [zoo, amy], [zoo, ted]], L),group_pairs_by_key(L,G).
L = [park-joe, park-bob, park-kate, school-joe, zoo-amy, zoo-ted],
G = [park-[joe, bob, kate], school-[joe], zoo-[amy, ted]].
Anyway, here is your code restructured:
merge([],[]).
merge([[Meet, Person]|Rest], Z) :-
merge(Rest, U),
( U = []
-> % beginning case from recursion, U is empty
Z = [[Meet, [Person]]]
; U = [[Meet, Persons] | Rest1]
-> % Case of matching heads, combine the tails
Z = [[Meet, [Person | Persons]] | Rest1]
; % otherwise, not matching
Z = [[Meet, [Person]] | U]
).

If you had your initial list as a list of pairs instead, you could use library(pairs), available in SWI-Prolog.
?- group_pairs_by_key([park-joe, park-bob, park-kate, school-joe, zoo-amy, zoo-ted], G).
G = [park-[joe, bob, kate], school-[joe], zoo-[amy, ted]].
Using the library gives you more than just this "reorganization". There is also library(ugraphs), which might be better suited, depending on what you are doing.

Your code fails, because you are trying to extract the place and the person before checking if there are any.
No use for append here, the reordering looks pretty complicated, but I did my best with the variable names. Furthermore you'll only need one ->: If you hadn't found a tuple with the same first coordinate, you'll want a to start a new, it doesn't matter if there was none before.
merge([],[]).
merge([[Place,Person]|Rest], [[Place,Group]|OtherGroups]) :-
merge(Rest, U),
(U = [[Place,Others]|OtherGroups] ->
Group = [Person|Others];
[OtherGroups,Group] = [U, [Person]]).
Edit: I changed the solution for readablity reasons.

Related

Prolog: Resolvent/Resolution solver and recursion

Given 2 lists of positiv and negativ literals (representing clauses) I want to to get all possible Resolutions of these 2 clauses.
resolution([pos(X)|T],[H2|T2],R):- select(neg(X), [H2|T2],L),union(T,L,R).
resolution([neg(X)|T],[H2|T2],R):- select(pos(X),[H2|T2],L),union(T,L,R).
resolution([H|T],[H2|T2],R):-resolution(T,[H2|T2],R).
This works for the first literal of the first list ([H|T]) but for after that due to how I wrote the recursion I lose the Head of the list after every recursion so that I don't get the whole union of my 2 original list but the union of the second list and the the subset of the first list after the deleted literal.
I couldn't figure out how I (try to) do a resolution for every element of the first list with the second whilst keeping all elements of the first list.
My idea is something like this:
resolution([[_]|[pos(X)|T]],[H2|T2],R):- select(neg(X),[H2|T2],L),select(pos(X),[[_]|[pos(X)|T]],Q),union(Q,L,R).
resolution([[_]|[neg(X)|T]],[H2|T2],R):- select(pos(X),[H2|T2],L),select(neg(X),[[_]|[neg(X)|T]],Q),union(Q,L,R).
resolution([[_]|[neg(X)|T]],[H2|T2],R):-resolution([[[_]|[neg(X)]]|T],[H2|T2],R).
Trying to shift the element I am using for the resolution while keeping my list how it was but this doesn't work at all at the moment.
What the upper codes outputs:
?-resolution([pos(1),neg(3),pos(4)],[neg(1),pos(3),neg(5)],R).
R = [neg(3), pos(4), pos(3), neg(5)]
R = [pos(4), neg(1), neg(5)]
(resolution with pos(1),neg(1) and neg(3),pos(3))
What it I want it to output:
?-resolution([pos(1),neg(3),pos(4)],[neg(1),pos(3),neg(5)],R).
R = [neg(3), pos(4), pos(3), neg(5)]
R = [pos(1),pos(4), neg(1), neg(5)]
Keeping the pos(1) of the first list.
"Shifting" an element to the "result" list can be done by using the list constructor [_ | _] in the "result" parameter as well, i.e., changing the last clause of your original program to:
resolution([pos(X)|T],[H2|T2],R):- select(neg(X), [H2|T2],L),union(T,L,R).
resolution([neg(X)|T],[H2|T2],R):- select(pos(X),[H2|T2],L),union(T,L,R).
resolution([H|T], [H2|T2], [H | R]) :-
resolution(T, [H2|T2], R).
And there you go:
?- resolution([pos(1),neg(3),pos(4)],[neg(1),pos(3),neg(5)],R).
R = [neg(3), pos(4), pos(3), neg(5)] ;
R = [pos(1), pos(4), neg(1), neg(5)] ;
false.
This isn't perfect, for what if H is already present in R? It would be duplicated in the result. So maybe change to this:
resolution([pos(X)|T],[H2|T2],R):- select(neg(X), [H2|T2],L),union(T,L,R).
resolution([neg(X)|T],[H2|T2],R):- select(pos(X),[H2|T2],L),union(T,L,R).
resolution([H|T], [H2|T2], Resolvent) :-
resolution(T, [H2|T2], R),
union([H], R, Resolvent).
It's a bit of a pity that this loses the tail recursivity of the predicate.
For whatever it's worth, I don't see why you bother with recursion at all. What you are trying to do amounts to selecting an element from a list and keeping all other elements around. Your implementation of this, with the small fix from my first version, is basically an unfolded version of select/3 itself. Why not go full select/3? Like this:
resolution(ClauseA, ClauseB, Resolvent) :-
select(Literal, ClauseA, RestA),
literal_opposite(Literal, OppositeLiteral),
select(OppositeLiteral, ClauseB, RestB),
union(RestA, RestB, Resolvent).
literal_opposite(pos(X), neg(X)).
literal_opposite(neg(X), pos(X)).
This is actually pretty close to a textbook definition of resolution.

What is the explanation of this code?

I am trying to learn Prolog. I have a problem and the solution for that in Prolog. Though I am unable to understand the code completely.
The problem is -
Write a procedure mydelete( X, HasXs, OneLessXs ) that returns
% ?- mydelete( 2, [1,2,3,4], L ) . --> L = [1,3,4]
% ?- mydelete( 2, [1,2,3,2], L ) . --> L = [1,3,2] ; L = [1,2,3]
Basically, the problem is t remove the member one by one which matches X and print the result after each removal.
I have a solution , but, I am exactly, not sure how this code is working.
mydelete(X,[X|T],T).
mydelete(X,[H|T1],[H|T2]) :- mydelete(X,T1,T2).
As per my understanding, the first line, displays the L = ... when it finds a match with X in the head of the list.
In the second line of the code, it simply pops out the head from the input list and send that updated list recursively.
But, here, we haven't defined T2.
Let us consider an example for that.
mydelete( 2, [1,2,3,4], L ) . --> this is the call.
X=2, list is = [1,2,3,4], so, H=1, T=[2,3,4].
So, it does not execute line 1 of the code. Now, it comes to the second line of the code.
mydelete(X,[H|T1],[H|T2]) :- mydelete(X,T1,T2).
Here also X=2, H =1, T1=[2,3,4], T2= .
So, on the next recursion,
X=2, list = [2,3,4], H matches X, thus line 1 will get executed.
Therefore, X=2, T=[3,4]
So, it should print = [3,4].(I know, [1,3,4] is the right answer. I am not able to understand the explanation behind this code)
My, question is, what is wrong in my understanding?
And, what is the use of [H|T2] in
mydelete(X,[H|T1],[H|T2]) :- mydelete(X,T1,T2).
Thanks! Please help me out!
edit: I tried removing H from [H|T2]. It is printing [3,4]. How H is adding 1 as the prefix to the list [3,4] ?
The best way to think of this as an imperative programmer is that the last argument is kind of the return value. You see that the first call you make "returns" [H|T2], not merely T2 this is how the first element of the list remains: after recursing to compute the value of T2, mydelete is adding H (which happens to equal 1 in this case) to the start of the returned list.
What is the use of [H|T2]?
In your explanations, you forgot to consider that the third argument, L, is being unified with [H|T2]. Up to this point, L was free (in your case), and now you know that it is a list starting with H. The rest of the list T2 is now the third argument to the recursive call and will be unified likewise, until you reach the base case.
By the way, what happens when your list is empty?

Prolog: Choosing NOT to insert an element during list recursion

I've made a predicate that takes 2 list as arguments and returns a list concatenated with the product of "recipesub", however I need to make a third rule that prohibits the product from being inserted if the product at hand is an empty list.
So the first list could look like this:
recipe([ingredient(rice,4),ingredient(salt,3),ingredient(water,5)]).
And the second one like this:
ingredients([ingredient(rice,3),ingredient(salt,4),ingredient(water,4),
At the moment it returns: List = [ingredient(rice,1),[],ingredient(water,1)]
I WANT it to return: List = [ingredient(rice,1),ingredient(water,1)]
need_to_buy([],_,List):- List = [].
need_to_buy([H|Hs],[X|Xs],[Difference|List]):-
H = ingredient(Type,Amount),
recipesub(Type,Amount,[X|Xs],Difference),
need_to_buy(Hs,[X|Xs],List).
Below is how far I've gotten with the solution.
/*need_to_buy([H|Hs],[X|Xs],List):-
H = ingredient(Type,Amount),
recipesub(Type,Amount,[X|Xs],Difference),
Difference = [],
need_to_buy(Hs,[X|Xs],List).*/
And this is the support-predicate, recipesub.
recipesub(Type,Amount,[],Difference):-
Difference = ingredient(Type,Amount).
recipesub(Type,Amount,[Z|_],Difference):-
Z = ingredient(Type,Stock),
Amount>Stock,
NewAmount is Amount-Stock,
Difference = ingredient(Type,NewAmount).
recipesub(Type,Amount,[Z|_],Difference):-
Z = ingredient(Type, Stock),
Stock >= Amount,
Difference = [].
recipesub(Type,Amount,[Z|Zs],Difference):-
Z = ingredient(WrongType,_),
WrongType \= Type,
recipesub(Type,Amount,Zs,Difference).
I normally don't do a bunch of nested conditionals but it "felt right" this time, and this is the solution I found:
need_to_buy([], _, []).
need_to_buy([ingredient(Type, AmountNeeded)|Ingredients], OnHand, Needed) :-
% Do we have any on-hand?
member(ingredient(Type, AmountOnHand), OnHand) ->
% If the amount on-hand is greater than the amount needed,
% just hand off the rest
(AmountOnHand >= AmountNeeded ->
need_to_buy(Ingredients, OnHand, Needed)
% otherwise, calculate the amount needed and recur
; (AmountToBuy is AmountNeeded - AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded),
Needed = [ingredient(Type, AmountToBuy)|RestNeeded]))
% If we have none on-hand, we can just use the amount needed
% to form the request, and recur
; need_to_buy(Ingredients, OnHand, RestNeeded),
Needed = [ingredient(Type, AmountNeeded)|RestNeeded].
Otherwise I think you'll have a lot of fairly inefficient testing and retesting. The main mistake I see in your code is that you're pattern matching on the second argument. It's easier to rely on member/2 or memberchk/2 to do the dirty work of finding the right ingredient in the stuff you have on-hand.
If I did it with a bunch of clauses instead it would probably look like this:
need_to_buy([], _, []).
% case 1: we don't have the ingredient at all
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
[ingredient(Type, AmountNeeded)|Needed]) :-
\+ memberchk(ingredient(Type, _), OnHand),
need_to_buy(Ingredients, OnHand, Needed).
% case 2: we have it, but not enough
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
[ingredient(Type, AmountToBuy)|RestNeeded]) :-
memberchk(ingredient(Type, AmountOnHand), OnHand),
AmountNeeded > AmountOnHand,
AmountToBuy is AmountNeeded - AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded).
% case 3: we have enough
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
RestNeeded) :-
memberchk(ingredient(Type, AmountOnHand), OnHand),
AmountNeeded =< AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded).
This leaves a choice point on the stack and just generally seems like a lot of retesting the same conditions and re-traversal for my taste. But if it looks better to you it should work the same.
I ultimately solved it by splitting the second rule of need_to_buy into two rules, one which handles the case where difference is an empty list, and on where it isnt an empty list.
I had some trouble with it at first but it turns out the "orientation" of the rules was giving me trouble, so I had to place the rule which handles the case where Difference \= [], above the one where Difference = [].
It now looks like this:
need_to_buy([],_,List):- List = [].
need_to_buy([H|Hs],[X|Xs],[Difference|List]):-
H = ingredient(Type,Amount),
recipesub(Type,Amount,[X|Xs],Difference),
Difference \= [],
need_to_buy(Hs,[X|Xs],List).
need_to_buy([H|Hs],[X|Xs],List):-
H = ingredient(Type,Amount),
recipesub(Type,Amount,[X|Xs],Difference),
Difference = [],
need_to_buy(Hs,[X|Xs],List).

Change a variable in standard ml list

I wonder when working with list in ml, how to change a variable with specific location of the list. For instance, when I have a list [1,2,3,4], I want to change the list to [1,2,5,4] with the 5 subtitle for the 3. What i'm thinking is to write a function that take a location, the variable and the list, return the new list with the update variable. For example,
change(i, var, list) = let val valup = var in (list # [i]) end
So with this code, if my input is change(2, 5, [1,2,3,4]), my out put will be [1,2,3,4,2] which incorrect compare to [1,2,5,4]. I'm new with ml and not good with the list setup in the language so any help would be really appreciate.
You have to realise that values are not mutable in ML. This means that once you create a value, you can't change it!
So if we have these two statements
x = [2,3,4]
y = 1::x
then y and x live in seperate memory locations on the computer.
What you can do is the following:
fun swapFirst [] y = raise Empty
| swapFirst (x::xs) y = y::xs
val test_swapFirst_00 = [1,2,3,4] = swapFirst [2,2,3,4] 1
which will swap the first element of a list out with something else.
Now I have a feeling that this could be for an answer for some course work, so I'm not going to give a complete code that solves your problem, but this information should at least clear some things up, and make it easier for you to solve the problem!
I come up with the solution for the problem.
fun change(i,v,[]) = raise Error
| change(0, v, x::xs) = v :: xs
| change(i, v, x::xs) = if i < 0 then raise Error
else x :: change((i-1), v, xs)

List of all the elements in sublist in Prolog

I need to write a predicate f(L,R) that succeeds if and only if L is a list containing all terms in R that are not lists.
For example:
f(L,[1,2,3,[4,5,6],[[7,8,9]],[]]).
Should give:
L = [1,2,3,4,5,6,7,8,9]
I wrote a predicate that gives the following result instead:
L = [1,2,3,4,5,6,7,8,9,[]]
Empty lists should not be present in the result. My predicate is the following:
f([],[]).
f(V,[H|T]):- H = [_|_] -> append(L,R,V),
f(L,H), f(R,T),!;
V = [H1|T1], H1=H, f(T1,T).
I have two doubts. First of all, the empty lists should not be present in the result. Also I don't know why it does not work if I don't put the cut (!). In fact, if I don't put the cut it gives me the result as above, but if I ask for another result it loops forever. I really don't understand why this should loops.
To remove the empty list, handle that case (discard it).
About the loop: I think the cause could be that you're calling append(L,R,V) with all arguments not instantiated: move append after the recursive calls.
Finally, maybe you don't use rightly the 'if then else' construct: I've indented using the usual SWI-Prolog source style, using indentation to highlight 'sequential' calls
f([], []).
f(V, [H|T]) :-
( H = [] % if H = []
-> f(V, T) % then discard
; H = [_|_] % else if H is list
-> f(L,H), % flat head
f(R,T), % ...
append(L,R,V)
; V = [H|T1], % else
f(T1,T) % ...
).