How to get Prolog to display a list - prolog

university(a60, 'Anglia Ruskin University', 'Eastern', 14200, 'www.anglia.ac.uk').
university(b22, 'University of Bedfordshire', 'Eastern', 9900, 'www.beds.ac.uk').
university(e14, 'University of East Anglia', 'Eastern', 10500, 'www.uea.ac.uk').
university(e70, 'The University of Essex', 'Eastern', 14450, 'www.essex.ac.uk').
program(computer_science, a60, graduate).
program(computer_science, b22, graduate).
program(computer_science, e14, undergraduate).
program(computer_science, e70, undergraduate).
program(math, a60 , graduate).
program(math, b22, graduate).
program(math, e14, undergraduate).
recommend_university(UcasCode, Degree, Location, TuitionLower, TuitionUpper, Program, University) :-
university(UcasCode, University, Location, Tuition, Website),
program_offered(UcasCode, Program, Degree),
Tuition >= TuitionLower,
Tuition =< TuitionUpper.
program_offered(UcasCode, Program, Degree) :-
university(UcasCode, _, _, _, _),
program(Program, UcasCode, Degree).
query_university :-
write('Please enter the location: '),
read(Location),
write('Please enter the tuition range lower bound: '),
read(TuitionLower),
write('Please enter the tuition range upper bound: '),
read(TuitionUpper),
write('Please enter the program of study: '),
read(Program),
write('Please enter the level of study (undergraduate or graduate): '),
read(Degree),
recommend_university(UcasCode, Degree, Location, TuitionLower, TuitionUpper, Program, University),
write('The recommended university is: '),
write(University), nl;
write('Sorry, there are no recommended Universities').
I am trying to get the system to recommend a list of universities based on criteria and display the list of universities matching the criteria.
However, after entering your preferences, the program moves straight to display 'Sorry, there are no recommended universities'. This message should only appear when there are no universities that match the criteria

Related

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.

New to Prolog - procedure `temp(A)' does not exist Reachable from: weather(A) go

I've typed out code from a textbook and don't understand where the error lies. It seems to be at weather(Weather),
The error is:
procedure `temp(A)' does not exist
Reachable from:
weather(A)
go
/* Weather knowledge base */
weather(good):-
temp(high),
humidity(dry),
sky(sunny).
weather(bad):-
(humidity(wet);
temp(low);
sky(cloudy)).
/* interface */
go:-
write('Is the temperature high or low? '),
read(Temp), nl,
write('Is the sky sunny or cloudy? '),
read(Sky), nl,
write('Is the humidity dry or wet? '),
read(Humidity), nl,
assert(temp(Temp)),
assert(sky(Sky)),
assert(humidity(Humidity)),
weather(Weather),
write('The weather is '), write(Weather),
retractall(temp( __ )),
retractall(sky( __ ) ),
retractall(humidity( _) ).
If you are using SWI-Prolog, you should declare temp/1, humidity/1, and sky/1 as dynamic, by inserting these three lines in your code.
:- dynamic temp/1.
:- dynamic humidity/1.
:- dynamic sky/1.
Moreover, if your run your program you get a warning: Singleton-marked variable appears more than once: __.
You should replace __ with _ in your code to avoid this.

gprolog expert system - issues reading user input

I'm working through this prolog expert system example that accepts user input. I am having issues with the way user_input is read. I am using gprolog.
animal(dog) :-
is_true('has fur'),
is_true('says woof').
animal(cat) :-
is_true('has fur'),
is_true('says meow').
animal(duck) :-
is_true('has feathers'),
is_true('says quack').
is_true(Question) :-
write('Does the animal have the following attribute: '),
write(Question), write('? '),
read_string(user_input,"\n","\r",End,Response), Response == "yes". /*this line*/
go:-
animal(Animal),
write('I guess that the animal is: '),
write(Animal).
go:-
write('I cannot recognize your animal').
I am getting:
uncaught exception: error(existence_error(procedure,read_string/5),is_true/1)
It's the same error if I try:
read_string(user_input,"\n","\r",_,Response), Response == "yes".

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 Query Exercise - Beginner

I'm a begginer at Prolog and I need some help with this exercise, this is the knowledge base provided:
album(‘R. Stevie Moore’, ‘Manuscription’).
album(‘Lane Steinberg’, ‘Manuscription’).
album(‘R. Stevie Moore’, ‘The Yung & Moore Show’).
album(‘Yukio Yung’, ‘The Yung & Moore Show’).
album(‘Jessie Evans’, ‘Autonervous’).
album(‘Bettina Koster’, ‘Autonervous’).
album(‘Lucia Pamela’, ‘Walkin on the moon’).
album(‘Shooby Taylor’, ‘The Human Horn’).
album(‘Tiny Tim’, ‘God Bless Tiny Tim’).
album(‘The Legendary Stardust Cowboy’, ‘Rock-It to Stardom’).
vinil(‘Rock-It to Stardom’).
vinil(‘Walking on the Moon’).
cd( ‘God Bless Tiny Tim’).
cd(‘Walking on the Moon’).
cd(‘Autonervous’).
cd(‘Manuscription’).
cassette(‘The Human Horn’).
cassette(‘The Yung & Moore Show’).
mp3(‘Walkin on the Moon’).
I need to make a query that will return to me all the albums that were made by only one musician.
Thanks for your help :)
In the comments you have provided your code album(X,B),album(Y,C), B \= C. Actually, this is not too far away from a correct solution.
A correct solution could be:
one_musician_album(X) :-
album(A, X),
\+ (album(B, X), A \= B).
The meaning of the predicate is: an album X is a "one-musician album" if this album is authored by some musician A and it's not possible to find a different musician B authored the album X.
Test run:
?- one_musician_album(X).
X = 'Walkin on the moon' ;
X = 'The Human Horn' ;
X = 'God Bless Tiny Tim' ;
X = 'Rock-It to Stardom'.
To get all answers you have to type ';' after each answer.
Maybe this is not needed for you, but it's possible to get all answers in a list with findall:
?- findall(X, one_musician_album(X), Albums).
Albums = ['Walkin on the moon', 'The Human Horn', 'God Bless Tiny Tim', 'Rock-It to Stardom'].
Here is a generalization, based on 'all solutions' builtin bagof/3.
Note that
?- bagof(A, album(A,T), As).
T = 'Autonervous',
As = ['Jessie Evans', 'Bettina Koster'] ;
T = 'God Bless Tiny Tim',
As = ['Tiny Tim']
....
then, restricting the authors (As) to be a list of a single element, we get albums with a single author
?- bagof(A, album(A,T), [A]).
A = 'Tiny Tim',
T = 'God Bless Tiny Tim' ;
...
then, we could use findall/3, as in the good answer by Sergey, or, again, bagof/3, with explicit quantification:
?- bagof(T, A^bagof(A, album(A, T), [A]), Ts).
Ts = ['God Bless Tiny Tim', 'Rock-It to Stardom', 'The Human Horn', 'Walkin on the moon'].

Resources