Turning a relation into a fact - prolog

I would like to ask a very basic question in prolog. I have a list of lists that looks like [[a_1,a],[a_2,c],[a_3,e,f]]. I would like to create a relation which gets that list and adds an infix to each one of those sublists. For example I would like to insert x as infix: x([[a_1,a]),x([a_2,c]),x([a_3,e,f]]). The goal is to make the relation to be a fact. I was trying to use findall but without any success.
Example:
turn([[a_1,a],[a_2,c],[a_3,e,f]]).
Output:
[x([a_1,a]),x([a_2,c]),x([a_3,e,f])].
How to implement it?

[x([a])] is not, in and of itself, a fact. It's just a different Prolog term form. A fact is a term that is asserted in the database, doesn't represent a predicate, and can be queried. Sounds like you don't want to convert to "facts", but you just want to convert to a different term form.
It would be easy in this case with maplist:
turn_item(X, x(X)).
turn(TermList, NewTermList) :-
maplist(turn_item, TermList, NewTermList).
Then:
| ?- turn([[a_1,a],[a_2,c],[a_3,e,f]], L).
L = [x([a_1,a]),x([a_2,c]),x([a_3,e,f])]
yes

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.

List a given number of element in a list prolog

I am trying to list a given number of elements i have stored in List , my code is as follows
er(Person,List) :- findall(A, descendant(Person, A), List).
when i type the code below into prolog i get all of the elements that match my query.
er(james,X).
What i am trying to achieve is ask prolog to list a given amount of element say for example
er(james,3).
Prolog will only return at most 3 element from the list . I researched a bit and found that i can use findnsols instead of the findall operator but i couldn't find a practical way to implement it in my code .
Well, the obvious way would be to say something like this:
er(P,N,L) :-
findnsols(N,A,descendant(P,A),L)
.
But you seem not to want to do that. You might consider something like this:
er(P,L) :-
var(L),
findall(A,descendant(P,A),L)
.
er(P,L) :-
nonvar(L),
length(L,N),
findnsols(N,A,descendant(P,A),L)
.
If you want all the solutions back, just invoke it like this:
er(james,L).
If you want to limit things, like this:
er(james,[A,B,C]).
or (since length/2 can be generative):
length(5,L) , er(james,L).

Prolog: find a supplier who supply all parts

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

In Prolog (SWI), how to build a knowledge base of user supplied pairs and assert to be equal

I am very new to Prolog and trying to learn.
For my program, I would like to have the user provide pairs of strings which are "types of".
For example, user provides at command line the strings "john" and "man". These atoms would be made to be equal, i.e. john(man).
At next prompt, then user provides "man" and "tall", again program asserts these are valid, man(tall).
Then the user could query the program and ask "Is john tall?". Or in Prolog: john(tall) becomes true by transitive property.
I have been able to parse the strings from the user's input and assign them to variables Subject and Object.
I tried a clause (where Subject and Object are different strings):
attribute(Subject, Object) :-
assert(term_to_atom(_ , Subject),
term_to_atom(_ , Object)).
I want to assert the facts that Subject and Object are valid pair. If the user asserts it, then they belong to together. How do I force this equality of the pairs?
What's the best way to go about this?
Questions of this sort have been asked a lot recently (I guess your professors all share notes or something) so a browse through recent history might have been productive for you. This one comes to mind, for instance.
Your code is pretty wide of the mark. This is what you're trying to do:
attribute(Subject, Object) :-
Fact =.. [Object, Subject],
assertz(Fact).
Using it works like this:
?- attribute(man, tall).
true.
?- tall(X).
X = man.
So, here's what you should notice about this code:
We're using =../2, the "univ" operator, to build structures from lists. This is the only way to create a fact from some atoms.
I've swapped subject and object, because doing it the other way is almost certainly not what you want.
The predicate you want is assertz/1 or asserta/1, not assert/2. The a and z on the end just tells Prolog whether you want the fact at the beginning or end of the database.
Based on looking at your code, I think you have a lot of baggage you need to shed to become productive with Prolog.
Prolog predicates do not return values. So assert(term_to_atom(... wasn't even on the right track, because you seemed to think that term_to_atom would "return" a value and it would get substituted into the assert call like in a functional or imperative language. Prolog just plain works completely differently from that.
I'm not sure why you have an empty variable in your term_to_atom predicates. I think you did that to satisfy the predicate's arity, but this predicate is pretty useless unless you have one ground term and one variable.
There is an assert/2, but it doesn't do what you want. It should be clear why assert normally only takes one argument.
Prolog facts should look like property(subject...). It is not easy to construct facts and then query them, which is what you'd have to do using man(tall). What you want to say is that there is a property, being tall, and man satisfies it.
I would strongly recommend you back up and go through some basic Prolog tutorials at this point. If you try to press forward you're only going to get more lost.
Edit: In response to your comment, I'm not sure how general you want to go. In the basic case where you're dealing with a 4-item list with [is,a] in the middle, this is sufficient:
build_fact([Subject,is,a,Object], is_a(Subject, Object)).
If you want to isolate the first and last and create the fact, you have to use univ again:
build_fact([Subject|Rest], Fact) :-
append(PredicateAtoms, [Object], Rest),
atomic_list_concat(PredicateAtoms, '_', Predicate),
Fact =.. [Predicate, Subject, Object].
Not sure if you want to live with the articles ("a", "the") that will wind up on the end though:
?- build_fact([john,could,be,a,man], Fact).
Fact = could_be_a(john, man)
Don't do variable fact heads. Prolog works best when the set of term names is fixed. Instead, make a generic place for storing properties using predefined, static term name, e.g.:
is_a(john, man).
property(man, tall).
property(john, thin).
(think SQL tables in a normal form). Then you can use simple assertz/1 to update the database:
add_property(X, Y) :- assertz(property(X, Y)).

Convert list into functor parameter

I got stuck to implement a logic. At some instance in my program I have a list say named as List.
The length of this List is variable and I don't know in advance. Now I have to pass this list in a functor to create a fact and I am unable to implement it. For eg:
if List is [first] then it should add the fact functor(first).
if List is [first,second] then it should add the fact functor(first,second).
if List is [first,second,third] then it should add the fact functor(first,second,third).
and so on...
I was trying by =.. but here I am unable to map that variable length constraint. For fixed length I am able to perform but I don't know in advance that how many elements will be there in list.
Any suggestions to implement this logic. Thanks.
I don't quite understand your problem with =.. but this worked for me:
assert_list(List) :-
Term =.. [my_functor|List],
assert(Term).
Note that I use my_functor instead of simply functor because functor/3 is a built-in predicate so you cannot assert ternary functor facts (functor(first, second, third)).
Calling it:
?- assert_list([first,second,third]).
true.
Checking that it works:
?- listing(my_functor).
:- dynamic user:my_functor/3.
user:my_functor(first, second, third).
true.
Note that technically, the different n-ary my_functor/n predicates are not the same predicates. You must use different queries in your program for each n. To circumvent this, you could simply assert the list as one and only argument of my_functor:
?- List = [first, second, third],
assert(my_functor(List)).
true.
?- listing(my_functor).
:- dynamic user:my_functor/3.
user:my_functor([first, second, third]).
true.
My SWI-Prolog version is 5.7.5.

Resources