Why is Prolog being a jerk - prolog

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

Related

Using attribute_goal/2 the right way in SICStus Prolog

I'm writing a "solver" using the SICStus Prolog attributed variables interface:
:- module(attach2, [attach2/2]).
:- use_module(library(atts)).
:- attribute att/2.
attach2(X,Y) :- put_atts(X,att(X,Y)),
put_atts(Y,att(Y,X)).
verify_attribute(_,_,[]).
attribute_goal(V,(true,G,true,G,true)) :- get_atts(V,att(X,Y)), G = attach2(X,Y).
Sample query:
| ?- attach2(X,Y), copy_term(X,Xc,Xcc), copy_term(Y,Yc,Ycc), copy_term(X+Y,XYc,XYcc).
Xcc = attach2:(true,attach2(Xc,_A),true,attach2(Xc,_A),true),
Ycc = attach2:(true,attach2(Yc,_B),true,attach2(Yc,_B),true),
XYc = _C+_D,
XYcc = (attach2:attach2(_C,_D),attach2:attach2(_D,_C)),
attach2(X,Y),
attach2(Y,X) ? ;
no
If I change attribute_goal/2 to ...
attach2(X,Y) :- put_atts(X,att(X,Y)),
put_atts(Y,att(X,Y)).
... the answer get better:
| ?- attach2(X,Y), copy_term(X,Xc,Xcc), copy_term(Y,Yc,Ycc), copy_term(X+Y,XYc,XYcc).
Xcc = attach2:(true,attach2(Xc,_A),true,attach2(Xc,_A),true),
Ycc = attach2:(true,attach2(_B,Yc),true,attach2(_B,Yc),true),
XYc = _C+_D,
XYcc = attach2:attach2(_C,_D),
attach2(X,Y) ? ;
no
My conclusion from this:
copy_term/3 collects goals from attribute_goal/2 and if it encounters more than one attributed variable, then it removes trivial true and duplicate goals.
It this essentially right?

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

Why does this Prolog code not write my list to a file?

The following rules should write my List to a stream associated with a file, but instead it is a never ending stream of incomprehensible characters. Help.
writeListToFile(List, File) :- open(File, write, Stream),
\+ writeListToStream(Stream, List),
close(Stream).
writeListToStream(Stream, List) :- member(Element, List),
write(Stream, Element),
write(Stream, ' '),
fail.
This occurs even when using a simple list like
List = ['a', 'b'].
Upon executing
writeListToFile(List, 'output.txt').
my SWI-Prolog does not respond and I see the file filling up with endless lines of
"_G889 _G892 _G895 _G898 _G901 _G904 _G907 _G910 _G913 _G916 _G919
_G922 _G925 _G928 _G931 _G934 _G937 _G940 _G943 _G946 _G949 _G952 _G955 _G958 _G961 _G964 _G967 _G970 _G973 _G976 _G979 _G982 _G985 _G988 _G991 _G994 _G997 _G1000 _G1003 _G1006 _G1009 _G1012 _G1015 _G1018"
etc.

Fact appears only once in the Knowledge Base

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

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