Fact appears only once in the Knowledge Base - prolog

I have this KB (Knowledge Base):
%artist(ArtistId, ArtistName, YearofDebut).
%album(AlbumId, AlbumName, YearOfRelease, Artists).
%song(AlbumId, Songname, Duration).
%artist/3
artist(1, 'MIEIC', 2006).
artist(2, 'John Williams', 1951).
artist(3, 'LEIC', 1995).
artist(4, 'One Hit Wonder', 2013).
%album/4
album(a1, 'MIEIC Reloaded', 2006,[1]).
album(a2, 'Best Of', 2015, [2]).
album(a3, 'Legacy', 2014, [1,3]).
album(a4, 'Release', 2013, [4]).
%song/3
song(a1, 'Rap do MIEIC', 4.14).
song(a2, 'Indiana Jones', 5.25).
song(a1, 'Pop do MIEIC', 4.13).
song(a2, 'Harry Potter', 5.13).
song(a1, 'Rock do MIEIC', 3.14).
song(a2, 'Jaws', 3.04).
song(a2, 'Jurassic Park', 5.53).
song(a2, 'Back to the Future', 3.24).
song(a2, 'Star Wars', 5.20).
song(a2, 'E.T. the Extra-Terrestrial', 3.42).
song(a3, 'Legacy', 3.14).
song(a3, 'Inheritance', 4.13).
song(a4, 'How did I do it?', 4.05).
And I want a query that asks if an album is a single (Got only one song).
recentSingle(+AlbumId).
recentSingle(a1) ?
No
recentSingle(a4) ?
Yes
How do I search in the whole KB and check if it only appears once?
ANSWER:
recentSingle(AlbumId) :- album(AlbumId, _, Year, _),
Year > 2010,
\+ isNotSingle(AlbumId).
isNotSingle(AlbumId) :- song(AlbumId, Name1, _),
song(AlbumId, Name2, _),
Name1 \= Name2.
Regards

Try something like this
recentSingle(X) :- aggregate_all(count, song(X, _, _), Count), Count = 1.
This should work too
recentSingle(X) :- aggregate_all(count, song(X, _, _), 1).

Related

Prolog find father_in_law

m([ himu, eric, shawn, wasim, steve,
korim, mark, romiz, yash, ben, mathew,protik,
labib, tim, sam, richard, sultan,liton,sazid]).
f([ soma, sarah, priti, anika, rokeya, marry,
lucy, rimi, kani, buni, sanjida, raidah, maria, hema,
cathrin, pauly,lili]).
%third generation
family([wasim, priti, [soma]]).
family([korim, anika, [eric, marry]]).
family([yash,lili,[protik]]).
%second generation
family([mark, lucy, [wasim, rimi]]).
family([ben, sanjida, [priti, mathew]]).
family([romiz, kani, [anika, yash]]).
family([sazid, raidah, [korim]]).
%first generation
family([tim, maria, [lucy]]).
family([sam, hema, [ben]]).
family([richard, cathrin, [romiz]]).
family([sultan, pauly, [sazid,liton]]).
parent(tim,lucy).
parent(maria,lucy).
parent(sam,ben).
parent(hema,ben).
parent(richard,romiz).
parent(cathrin,romiz).
parent(sultan,sazid).
parent(pauly,sazid).
parent(pauly,liton).
parent(sultan,liton).
parent(sam,korim).
parent(raidah,korim).
parent(romiz,anika).
parent(romiz,yash).
parent(kani,anika).
parent(kani,yash).
parent(ben,priti).
parent(ben,mathew).
parent(sanjida,priti).
parent(sanjida,mathew).
parent(mark,wasim).
parent(mark,rimi).
parent(lucy,wasim).
parent(lucy,rimi).
parent(korim,eric).
parent(korim,marry).
parent(anika,eric).
parent(anika,marry).
parent(wasim,soma).
parent( priti, soma).
parent(yash,protik).
parent(lili,protik).
father_in_law(X, Y) :-
male(X) ,family([Z,Y|[_]]),parent(X, Z).
Here for father_in_law I only get wife's father_in_law. But I want also husband's father_in_law in this. Unable to understand how. Is this possible?
You need to change to:
male([ himu, eric, shawn, wasim, steve,
korim, mark, romiz, yash, ben, mathew,protik,
labib, tim, sam, richard, sultan,liton,sazid]).
female([ soma, sarah, priti, anika, rokeya, marry,
lucy, rimi, kani, buni, sanjida, raidah, maria, hema,
cathrin, pauly,lili]).
father_in_law(X, Y) :-
male(XM) ,member(X,XM),family([Z,Y,[_|_]]),parent(X, Z).
father_in_law(X, Y) :-
male(XM) ,member(X,XM),family([Y,Z,[_|_]]),parent(X, Z).
This gets husband's father_in_law.

Why is Prolog being a jerk

sorted.csv
01Vbe,2r5/3Qnk1p/8/4B2b/Pp2p3/1P2P3/5PPP/3R2K1 w - - 3 32,d1d6 c8c1 d6d1 c1d1 d7d1 h5d1,600,80,100,63
3,advantage endgame fork long,https://lichess.org/b334W1Ga#63
01GC2,3b4/pp2kprp/8/1Bp5/4R3/1P6/P4PPP/1K6 b - - 0 22,e7f8 e4e8,600,82,89,374,endgame mate mateIn1 on
eMove,https://lichess.org/6c75Zk3T/black#44
file_line reads the code line by line as posted in this answer:
Read a file line by line in Prolog
stuff(Lines) :- findall(Tags,
(
file_line("data/athousand_sorted.csv", Line),
csv_fen(Line, Fen, Moves, Id, Tags),
maplist(atom_string, TagsAtom, Tags),
tags_with(TagsAtom, mateIn1)
),
Lines).
csv_fen(Line, Fen, Moves, Id, Tags) :- split_string(Line, ",", "", [Id, Fen, Moves, _, _, _, _, Tags|
_]).
tags_with(Tags, Tag) :- split_string(Tags, " ", "", Ls), member(Tag, Ls).
maplist(atom_string, XYZ), doesn't work for string read from a file,
though this works on the repl.
?- maplist(atom_string, Tags, ["mateIn1"]).
I want to filter lines of this file that has mateIn1 tags.
Does this give you a hint? (Is Tags a list of strings?)
?- csv_fen("id,fen,move,b1,b2,b3,b4,tags", Fen, Moves, Id, Tags).
Fen = "fen",
Moves = "move",
Id = "id",
Tags = "tags".

How to delete entry from rdf file in prolog

I want to write a program in Prolog where a menu is given to the users. They choose to either add data, see existing data based on surname or age, or/and delete data based on surname or age. I don't know how to delete an entry based on age or surname. Here is what I've written. Can anyone tell me what I do wrong? Thank you.
:- use_module(library(semweb/rdf_db)).
:- use_module(library(semweb/rdf_http_plugin)).
:- use_module(library(semweb/turtle)).
:- dynamic id/1.
id(1).
run :- nl,
write('Option 1: Load new path'),nl,
write('Option 2: Create new user'),nl,
write('Option 3: Display data based on Surname'),nl,
write('Option 4: Display data based on Age'),nl,
write('Option 5: Delete data based on Surname'),nl,
write('Option 6: Delete data based on Age'),nl,
write('Option 7: Exit'),nl, %It saves the program before exiting
write('Option(1-7): '), read(X), nl,
( shouldExit(X)
; (option(X), run)
; (nl, write('Invalid option.'), nl, run)
).
shouldExit(7) :- save.
option(1) :- write('Give path for rdf file'), read(Path), doOpen(Path).
option(2) :- doRead.
option(3) :- write('Surname: '), read(Surname), findS(Surname).
option(4) :- write('Age: '), read(Age), findA(Age).
option(5) :- write('Surname: '), read(Surname), delS(Surname).
option(6) :- write('Age: '), read(Age), delA(Age).
/*Enter new user*/
doRead :- rdf_register_prefix(foaf,'http://xmlns.com/foaf/0.1/'),
write('Surname:'), read(Surname),
write('First Name:'), read(FirstName),
write('Age:'), read(Age),
id(N),
New is N+1,
retract(id(N)),
asserta(id(New)),
atom_concat('foaf:person', N, Person),
rdf_assert(Person, rdf:type, foaf:'Person'),
rdf_assert(Person, foaf:surname, literal(Surname)),
rdf_assert(Person, foaf:firstName, literal(FirstName)),
rdf_assert(Person, foaf:age, literal(Age)).
/*Display data based on Surname*/
findS(Surname) :- rdf(X, foaf:surname, literal(Surname)),
rdf(X, foaf:firstName, literal(FirstName)),
rdf(X, foaf:age, literal(Age)),
write('Found '), write(FirstName), write(' '),
write(Surname), write(', '), write(Age), nl, fail.
/*Display data based on Age*/
findA(Age) :- rdf(X, foaf:surname, literal(Surname)),
rdf(X, foaf:firstName, literal(FirstName)),
rdf(X, foaf:age, literal(Age)),
write('Found '), write(FirstName), write(' '),
write(Surname), write(', '), write(Age), nl, fail.
/*Loads the file from the path the user asks ''*/
doOpen(Path) :- rdf_load(Path).
/*Saves the changes before exiting*/
save :- rdf_save(Path, [foaf]).
/*Deletes user based on their surname*/
/*delS(Surname) :- .*/
/*Deletes user based on their age*/
delA(Age) :- rdf(X, foaf:surname, literal(Surname)),
rdf(X, foaf:firstName, literal(FirstName)),
rdf(X, foaf:age, literal(Age)),
retract(rdf(Surname, FirstName, Age)).
I don't know it, so this is a guess, but you are using:
retract(rdf(Surname, FirstName, Age)).
and that is Prolog retract/1, I think you need rdf_retractall instead.

I wrote a prolog code for my family tree. What's the problem with this code?

/*facts*/
female(Sufia).
female(Bilkis).
female(Nasima).
female(Rabeya).
female(NWife).
female(Eva).
female(Rekha).
female(Shammi).
female(Shanta).
female(TWife).
female(NSWife).
female(Jui).
female(SHWife).
female(TSWife).
male(Anowar).
male(Shahidul).
male(Khazal).
male(Shafik).
male(Nahid).
male(Jahorul).
male(Naim).
male(Tanim).
male(Raiyan).
male(NSon).
male(JHusband).
male(Jubayer).
male(Shoddo).
male(TSon).
male(NSSon).
male(JSon).
male(SHSon).
male(TSSon).
parent(Anowar,Shahidul).
parent(Anowar,Nasima).
parent(Anowar,Shafik).
parent(Shahidul,Nahid).
parent(Shahidul,Eva).
parent(Nasima,Rekha).
parent(Nasima,Shammi).
parent(Nasima,Shanta).
parent(Shafik,Tanim).
parent(Shafik,Raiyan).
parent(Nahid,NSon).
parent(Rekha,Jui).
parent(Rekha,Jubayer).
parent(Shammi,Shoddo).
parent(Tanim,TSon).
parent(NSon,NSSon).
parent(Jui,JSon).
parent(Shoddo,SHSon).
parent(TSon,TSSon).
/*rules*/
mother(X,Y):-parent(X,Y),female(X).
father(X,Y):-parent(X,Y),male(X).
son(X,Y):-parent(X,Y),male(X).
daughter(X,Y) :- female(X),parent(X,Y).
sister(X,Y) :- female(Y),parent(Par,X),parent(Par,Y), X \= Y.
child(X, Y) :-parent(Y, X).
sibling(X,Y):-parent(Z,X),parent(Z,Y),X\=Y.
grandparent(X,Z):-parent(X,Y),parent(Y,Z).
firstCousin(X,Y):-grandparent(Z,X),grandparent(Z,Y),X\=Y.
secondCousin(X,Y):-grandparent(A,X),grandparent(B,Y),sibling(A,B),A\=B.
firstcousinOnceRemoved(X,Y):-child(X,Z),cousin(Z,Y).
firstcousinTwiceRemoved(X,Y):-grandparent(X,Z),cousin(Z,Y).
You need to quote every name, otherwise these symbols are variables, not atoms.
Otherwise, just lowercase the first letter. To illustrate this last option, using my pet project, here is the graph:
as obtained from this source
:- module(answer_so, [answer_so/0]).
:- use_module(genealogy).
answer_so :- genealogy(answer_so, 'Answer SO').
parent_child(P,C) :- parent(P,C).
female(sufia).
female(bilkis).
female(nasima).
female(rabeya).
female(nwife).
female(eva).
female(rekha).
female(shammi).
female(shanta).
female(twife).
female(nswife).
female(jui).
female(shwife).
female(tswife).
male(anowar).
male(shahidul).
male(khazal).
male(shafik).
male(nahid).
male(jahorul).
male(naim).
male(tanim).
male(raiyan).
male(nson).
male(jhusband).
male(jubayer).
male(shoddo).
male(tson).
male(nsson).
male(json).
male(shson).
male(tsson).
parent(anowar,shahidul).
parent(anowar,nasima).
parent(anowar,shafik).
parent(shahidul,nahid).
parent(shahidul,eva).
parent(nasima,rekha).
parent(nasima,shammi).
parent(nasima,shanta).
parent(shafik,tanim).
parent(shafik,raiyan).
parent(nahid,nson).
parent(rekha,jui).
parent(rekha,jubayer).
parent(shammi,shoddo).
parent(tanim,tson).
parent(nson,nsson).
parent(jui,json).
parent(shoddo,shson).
parent(tson,tsson).
Seems there are no marriages...

Prolog - fail; true

I have some problem with my code here.
Let's say I have a knowledge base like this:
university('University of Cambridge', 1, 'United Kingdom', 90.3, 92.8, 89.4).
university('University of Oxford', 2, 'United Kingdom', 88.9, 94.8, 88.0).
university('ETH Zurich - Swiss Federal Institute of Technology', 3, 'Switzerland', 86.4, 94.4, 92.2).
university('University of Edinburgh', 4, 'United Kingdom', 83.7, 88.8, 83.6).
Then I call it out like this:
(Ignore the checkC(Country)/checkC(_))
checkC(Country):-
university(U, R, Country, _, _, _),nl,
write('University: '),write(U),nl,
write('Rank: '),write(R),nl,
write('Country: '),write(Country),nl,
fail; true, nl,
write('************'), nl,nl.
checkC(_):-
write('Country not found'),nl,nl.
My question is, why is it if the user inputs a random country name not within the knowledge base, the write('Country not found') won't come out, I found out that it has something to do with the fail; true.
Any help?
While the fail; true trick is nice for the command line, gathering multiple solutions is usually done via the predicates findall, bagof and setof.
I used format for readabilities sake.
checkC(X):-
findall( [U,R,X], university(U,R,X,_,_,_), List),
(List = [] ->
write('Country not found\n\n');
writeCountries(List)).
writeCountries([]).
writeCountries([X|R]):-
writeCountries(R),
format('University: ~w~nRank: ~w~nCountry: ~w~n~n',X).
If you are using swipl, maplist comes in handy:
checkC(X):-
findall( [U,R,X], university(U,R,X,_,_,_), List),
(List = [] ->
write('Country not found\n\n');
maplist(format('University: ~w~nRank: ~w~nCountry: ~w~n~n'),List)).
If you don't have format/2 look if you have writef/2 or printf/2.

Resources