Prolog: find a supplier who supply all parts - prolog

I'm new to Prolog. These are my facts.
part_cost(Part, Supplier)
part_cost(top_tube ,cinelli).
part_cost(top_tube ,columbus).
part_cost(down_tube ,columbus).
part_cost(head_tube ,cinelli).
part_cost(head_tube ,columbus).
part_cost(seat_mast ,cinelli).
part_cost(seat_mast ,columbus).
I want to find a supplier who supplies all kinds of parts, which is actually columbus.
I don't know how to say "all" in Prolog language.
Any help is appreciated.
Update
Thank you, #Ankur and #Sergey Dymchenko. Your list approach inspired me! I can write rules:
supplyAllParts(Supplier, []):-true.
supplyAllParts(Supplier, [Part|PartRest]) :-
part_cost(Part, Supplier, _, _),
supplyAllParts(Supplier, PartRest).
and call it by
?- supplyAllParts(S,[top_tube, down_tube, head_tube, seat_mast]).
S = columbus.
Now can Prolog dynamically find the part list ([top_tube, down_tube, head_tube, seat_mast]) from the facts rather than I manually provide it?

supplies([],_).
supplies([H|T],S) :- part_cost(H,S), supplies(T,S).
| ?- setof(P,S^part_cost(P,S),R), supplies(R,Supplier).
R = [down_tube,head_tube,seat_mast,top_tube]
Supplier = columbus

First, you probably need to define a notion of "all parts" manually, because maybe there is some kind of "bottom_super_gravitsapa", that no one has:
% store in sorted order, to compare with setof results later
sort([top_tube, down_tube, head_tube, seat_mast], AllParts)
To get a list of all parts for every supplier we can use setof/3:
?- setof(Part, part_cost(Part, Supplier), Parts).
setof(Part, part_cost(Part, Supplier), Parts).
Supplier = cinelli
Parts = [head_tube,seat_mast,top_tube] ?;
Supplier = columbus
Parts = [down_tube,head_tube,seat_mast,top_tube]
yes
And now just add a condition that list of parts for a specific supplier and AllParts are the same:
Parts == AllParts
If you don't want to define AllParts manually and assume that there is a supplier for every possible part, you can use another setof to get AllParts from the facts before the main setof.

all is a big word, in any language, and what it means varies so much... Down to the earth , in Prolog we have findall/3 family, that outputs a list with all patterns we instruct to extract from succeeded queries. The output list then is further processed ... But for your case, library(aggregate) is more handy:
supplies_all(Supplier) :-
aggregate(max(N,S), count_part_cost(S,N), max(_, Supplier)).
count_part_cost(S,N) :-
aggregate(count, P^part_cost(P,S), N).
I used a service predicate count_part_cost/2, just to keep the main one clear...
If you try to 'inline' them, beware to variables usage. Study variables quantification until you are comfortable with it.
edit As noted by Sergey, my code is not correct. Here is my bet for a more appropriate definition:
supplies_all(Supplier) :-
setof(P, S^part_cost(P,S), Ps),
setof(P, part_cost(P,Supplier), Ps).
I think it highlights well what I intended above recommending about studying variable quantification...
edit another possible definition, less costly but with redundant multiple solution (well, we have setof for that...)
supplies_all(Supplier) :-
% peek any Supplier from catalog
part_cost(_,Supplier),
% check it has all parts available
forall(part_cost(P,_), part_cost(P,Supplier)).

Related

How can I get facts from my knowledge base into a list?

Say I have these facts:
person(fred).
person(jim).
person(mary).
is_person(person(_)).
I would like to get a list like:
[person(fred), person(jim), person(mary)]
but my query with findall/3 does not give the expected result:
?- findall(Person,is_person(Person),ListOfPeople).
ListOfPeople = [person(_5034)].
Similarly with bagof/3:
?- bagof(Person,is_person(Person),ListOfPeople).
ListOfPeople = [person(_5940)].
I do not understand why findall/3 and bagof/3 behave like this.
The correct way:
findall(person(Person),person(Person),ListOfPeople).
or
bagof(person(Person),person(Person),ListOfPeople).
Why doesn't your approach work? Consider
findall(Person,is_person(Person),ListOfPeople).
Prolog tries to fulfill is_person(Person).
There is a fact is_person(person(_)).
So, for Person = person(_), we are good! So person(_) will be in the list.
And that's all, there are no other ways to derive is_person(Person).
To collect all the Person, we really need to ask for the Person which fulfills person(Person).
Thus:
findall(person(Person),person(Person),ListOfPeople).
Prolog will find three Person which fulfill person(Person). As the result should not be a list of Person but of person(Person) we slap a person/1 around Person in the 1st parameter, the template.
Alternatively (but a bit pointlessly), you could:
is_person(person(X)) :- person(X).
?- findall(X,is_person(X),ListOfPeople).
Here, Prolog collects all the X for which is_person(person(X)), which are all the X which appear in a (fact) person(X). Thus X is for example fred. We slap a person/1 around fred in the head of is_person/1. Done.

How can I go through a list of facts in Answer Set Prolog?

I have a list of facts like
student(mary).
student(john).
etc, and also
course(math).
course(a).
course(b).
etc, and
took(john,math).
...
I have to say if a student can or can not graduate.
To graduate a student have to have all the courses taken. But how can I say this without write all term in the rule?
what I think was
can_graduate(X) :- took_all_courses(X).
but I dont know how to explain the rule took all courses without writing all courses. Can someone help me?
thanks.
took_all_courses(Student) :-
student(Student),
forall( course(C), took(Student,C) ).
Since this is Answer-Set Prolog and not Prolog, higher-order predicates such as forall are not available. What you want to do is count firstly the number of courses and secondly the number of courses the student has taken. How about using aggregates for this?
took_all_courses(Student) :-
student(S),
TotalCourses = #max{C:course(C)}, CoursesTaken = #max{C:took(S,C)},
TotalCourses == CoursesTaken.
I've not tested, but that should work, you might have to play around a bit with the syntax of the aggregates depending on the version of the grounder you are using, (e.g. see Clingo 3 vs 4).

Is there a way to annotate the parameter and return value in Prolog?

parent(mel, joan).
parent(jane, betty).
parent(jane, tom).
parent(richard, adam).
parent(richard, rosa).
parent(joan, fran).
For example someone asks me to find all ancestors of a parent. I give him the code:
ancestor(P,C) :- parent(P, C).
ancestor(P,C) :- ancestor(P,P1), parent(P1, C).
But my friend still doesn't know how to use the predicate. Does he call it like
ancestor(richard, C) or ancestor(C, richard) ?
Is there a way to annotate that P is the parameter while C is the return value? And in a complex case, there will be predicates with different names, how should my user know which predicate is the final predicate he wants to use?
To help the human-readable meaning, you could add an extra predicate documenting the parameters as readable name/value pairs:
entry_ancestor_of(ancestor=P, descendent=C) :-
ancestor(P,C).
?- entry_ancestor_of(ancestor=richard, descendent=C).
C = adam .
Above, the suffix *ancestor_of* suggests param 1 is ancestor of param 2, so naming the predicate carefully can make it clearer.
Usually(convention), input parameters are the earlier parameters, and output parameters are later parameters, but where the predicate 'works both ways', ie. either could be input or output, this rule can't hold. This is the case for your predicate:
?- entry_ancestor_of(ancestor=X, descendent=adam).
X = richard .
Either parameter could be input or output, so there is no need to codify/explain them as such, although you might want to comment that it works both ways.
I would usually comment these 'flexible' predicates by putting an example of both of the above usages in a comment next to the predicate.
For entrypoint labelling, just do one or more of the following:
explicitly name the predicate as an entrypoint, as above
document using comments in the code which are the entrypoints
arrange the entrypoints in the same physical section with a comment
block saying that the predicates below are entrypoints.
Edit: Extra things re: coding guidelines / other answers.
In Coding guidelines for Prolog, section 3.8, it says 'For example, mother_of(A, B) is ambiguous;', so I gave bad advice on that.. perhaps acapelli's suggestion would be more useful on that.
In that document, also have a look at:
3.5 Choose sensible names for auxiliary predicates
3.8 Choose predicate names to help show the argument order
3.13 Decide whether predicate names should carry the types on which they operate
4.1 Begin every predicate (except perhaps auxiliary predicates) with an introductory comment in a well-defined format
The '?' system for identifying parameter types that will ness mentioned is on page 21.
a useful convention, sponsored for instance by Markus Triska, builds a predicate functor by joining the parameters 'names' - in a wide, applicable sense. Your example could be
parent_child(mel, joan).
...
ancestor_descendant(P, C) :- parent_child(P, C).
ancestor_descendant(A, D) :- ancestor_descendant(A, I), parent_child(I, D).
Also ISO-Prolog, and - for instance - SWI-Prolog library, attempt to follow this strategy.
For instance
atom_codes(Atom, Codes) :- ...
WRT to declare the type and status of arguments, some Prolog provide declarations - for instance Turbo Prolog, ECLiPSe, others... Sometime such declarations are required - usually to check correctness, often to speed up the computation.
SWI-Prolog offers 'just' structured comments, that IDE process automatically, and there has been a contribution aiming to exploit such declarations with runtime check.
Yes, with comments, and/or meaningful argument names,
% ancestor( ?Ancestor, ?Descendent).
ancestor(P,C) :- parent(P, C).
ancestor(P,C) :- ancestor(P,P1), parent(P1, C).
? means the argument can be used both as input (already set when the call is made), or for output (not yet set when the call is made).
The convention promoted in The Art of Prolog (I think) is that you place the name of the predicate after its first argument, to get at the intended argument ordering: P "is" ancestor C. Presumably "ancestor_of". But if you use that name, someone unfamiliar with that convention might read ancestor_of(P,C) as "ancestor of P is C", so it's a double-edged sword.

How to do this in one function

I was wondering how to do the answer (or first function) to this question in Prolog only using one predicate? The link I'm referring to is here.
Here's an example of what I mean by only calling one predicate:
reverse([X|Y],Z,W) :- reverse(Y,[X|Z],W).
reverse([],X,X).
What are you trying to do and why do you want just one clause for the predicate?
personally I believe that having the ability to write many clauses is one of the great things of prolog and the code is more elegant and readable that way
Anyway, you will probably want to use or. assuming that you have the following clauses:
foo(Arg11,Arg12,Arg13):-
(Body1).
foo(Arg21,Arg22,Arg23):-
(Body2).
foo(Arg31,Arg32,Arg33):-
(Body3).
you should first make sure that every clause has the same arguments (bye bye pattern matching there!):
foo(Arg1,Arg2,Arg3):-
(Body1b).
foo(Arg1,Arg2,Arg3):-
(Body2b).
foo(Arg1,Arg2,Arg3):-
(Body3b).
and then you will use or (;):
foo(Arg1,Arg2,Arg3):-
(Body1b)
; (Body2b)
; (Body3b).
for example,
reverse([X|Y],Z,W):-
reverse(Y,[X|Z],W).
reverse([],X,X).
will become:
reverse(X,Y,Z):-
X = [H|T],
reverse(T,[H|Y],X).
reverse(X,Y,Z):-
X = [],
Z = Y.
and then:
reverse(X,Y,Z):-
(X = [H|T],
reverse(T,[H|Y],X) )
; (X = [],
Z = Y). *%ew ew ugly!*
regarding the example on your first post, there are two different predicates, each having just one clause. the second predicate has 2 arguments while the first one has 1 therefore they are different. The only way to "merge" them would be by simply calling the second one as has_equal_sums(List, _) in the place of the first.
To be honest, I dont see the point of doing this; I doubt you will not get any significant speedup and the code becomes way messier.
Of course, it's your code and there can be restrictions we dont know (that's why I asked what you want to accomplish)

In Prolog, how can I check for N of elements in list A in list B?

I have these two lists =
fruits([banana, apple, mangoes, pears]).
foodILike([hamburgers, banana, shakes, fries]).
I want to write a prolog predicate that will return true as soon as it sees 1 items in the foodsILike list in the fruits list. How can I go about doing so?
First, for the plain answer:
fruitsILike(F) :-
fruits(Fs)
member(F, Fs),
foodILike(Ls),
member(F, Ls).
You could avoid the membership check by flattening the fruits and foods lists:
fruit(banana).
fruit(apple).
...
foodILike(hamburger).
foodILike(banana).
...
fruitsILike(F) :-
fruit(F),
foodILike(F).
That said, you seem to try and solve problems in Prolog using imperative idioms, and that won't work. First, predicates do not return anything. When calling a predicate, Prolog unifies its arguments with valid values according to the facts and rules in the program. Therefore, the "returned value" are the assignments to unbound variables. Second, Prolog does not do something "as soon as". It iterates over all possible solutions. You get the first solution, then the second solution, and so on.
member can 1) individually generate all the members of a given list and/or 2) give a yes/no answer as to whether a particular element is in a particular list. I believe you want to use the first form on fruits to generate each of the elements of fruit, and the second form on foodILike to see if any of those is present.

Resources