Prolog find minimum in list error - prolog

Im trying to make my code work, but somehow I got stuck on a problem, Im very newbie to prolog. This is my code.
dist(valmiera, riga, 107).
%dist(riga, valmiera, 107).
dist(cesis, riga, 70).
dist(valmiera, rujiena, 50).
dist(rujiena, valka, 30).
dist(valmiera, strenci, 200).
dist(strenci, valka, 30).
dist(valmiera, cesis, 40).
dist(liepaja, saldus, 100).
dist(saldus, riga, 200).
dist(liepaja, jelgava, 270).
dist(jelgava, riga, 50).
path(A,B,C,[A,B]):- dist(A,B,C).
path(A,B,D,[A|As]):- dist(A,W,C), path(W,B,E,As), D is C+E.
%, findMin(YList, E), path(A,B,X,E),!.
shortestPath(A,B,X,E):-findall(Y,path(A,B,S,Y),YList), findMin(YList, E), path(A,B,X,E),!.
findMin([],fail).
findMin([H],E):-E=H,!.
findMin([H,V],E):-H<V, E=H,!; V<H, E=V, !; H=:=V, E=H, !.
findMin([H|T],E):-findMin(T,U), H<U, E=H,!;findMin(T,U), U<H, E=U,!;findMin(T,U), U=:=H, E=U,!.
but when I call findMin() I get this error
uncaught exception: error(type_error(evaluable,'.'/2),(<)/2)
I'm realy stuck and don't know what to do. Any help will be appreciated.
Applications purpose is get shortest path by calling shortestPath(), paths are in dist (a,b,distance)

The exception is because the terms you are trying to compare are lists.
[liepaja,saldus,riga]<[liepaja,jelgava,riga] ?
An expression:
Term1 < Term2
succeeds if
eval(Term1) < eval(Term2)
So, Term1 and Term2 have to be evaluable terms (e.g., (1+1)<(2+2)).
Try to change the shortestPath/4 body:
shortestPath(A,B,X,E):-
findall(couple(W,P),path(A,B,W,P),WP_List),
findMin(WP_List, couple(Weight,ShortestPath)),...
In this way you have a list of couple(Weight,Path) and in findMin you can get the Weight per Path.

Related

Creating a Knowledge Base and Querying in Prolog

I want to create the Knowledge base equivalent to the statements as below in Prolog.
John likes all kind of food.
Apple and vegetable are food
Anything anyone eats and not killed is food.
Anil eats peanuts and still alive
Harry eats everything that Anil eats.
So this one of the version borrowed from here
Once this file is created I want to find the answer for the query "John likes peanuts." saying likes(john, peanut).
Attempt to write rules in Prolog from my side is as below
alive(anil).
eats(anil,peanut).
food(apple).
food(vegitables).
food(X):-likes(john,X).
eats(X,Y),not(killed(X)):-food(Y).
eats(anil,X):-eats(harry,X).
killed(X):-not(alive(X)).
alive(X):-not(killed(X)).
But I am getting the errors and warnings as below;
ERROR: No permission to modify static procedure `(',')/2'
Warning: Clauses of eats/2 are not together in the source-file
Warning: Current predicate: food/1
Warning: Use ':- discontiguous eats/2.' to suppress this message
Warning: Clauses of alive/1 are not together in the source-file
Warning: Current predicate: killed/1
Warning: Use ':- discontiguous alive/1.' to suppress this message
"John likes all kind of food."
likes(john,X) :- food(X).
"Apple and vegetable are food."
food(apple).
food(X) :- vegetable(X).
"Anything anyone eats and not killed is food."
food(X) :- eats(P,X), alive(P).
"Anil eats peanuts and still alive."
eats(anil,peanuts).
alive(anil).
"Harry eats everything that Anil eats."
eats(harry,X) :- eats(anil,X).
Asking
?- likes(john,X).
produces (in SWI Prolog)
70 ?- likes(john,X).
X = apple ;
ERROR: food/1: Undefined procedure: vegetable/1
Exception: (9) vegetable(_G19387424) ? fail
Exception: (8) food(_G19387424) ? fail
71 ?-
Fixing it with
:- dynamic(vegetable/1).
we get
75 ?- likes(john,X).
X = apple ;
X = peanuts ;
false.
and so, of course,
101 ?- likes(john,peanuts).
true .

Prolog output message understanding

This is a really quick one, I don't know the correct way to google it!
Say we have an output such it gives:
X = [4|_1218]
what generally has to be changed to get the output just to say 4?
member1(Head, [Head|_]):-!.
member1(Item, [_|Tail]):-
member1(Item, Tail).
findnotin([Head|_], RuledOut, [Head|_]):-
not(member1(Head, RuledOut)).
Edit Completedish program:
find_not_in([], _, _).
find_not_in([Head|Candidates], RuleOut, [Head|Legal]):-
not(member1(Head, RuleOut)),
find_not_in(Candidates, RuleOut, Legal).
find_not_in([_|Candidates], RuleOut, Legal):-
find_not_in(Candidates, RuleOut, Legal).

Prolog logical task

There is a logical problem:
four friends: Ivan, Petr, Mikhail, Sergey spent their time in different ways: two were playing chess, one read books, one watched TV. Find who does what if Sergey does not play chess and Petr did not watch TV.
Here is my solution:
PREDICATES
question(string,string,string,string)
friend(string)
readBook(string)
watchTV(string)
playsChess(string, string)
CLAUSES
friend(ivan).
friend(petr).
friend(mikhail).
friend(sergey).
readBook(X):-
friend(X).
watchTV(X):-
friend(X),
X<>"petr".
playsChess(X,Y):-
friend(X),
friend(Y),
X<>Y,
X<>"sergey",
Y<>"sergey".
question(A,B,C,D):-
friend(A),
friend(B),
friend(C),
friend(D),
playsChess(A,B),
readBook(C),
watchTV(D),
A<>B, A<>C, A<>D,
B<>C, B<>D,
C<>D.
GOAL
question(A,B,C,D).
I have the following solution:
A=ivan, B=petr, C=mikhail, D=sergey (1)
A=ivan, B=petr, C=sergey, D=mikhail (2)
A=ivan, B=mikhail, C=petr, D=sergey (3)
A=petr, B=ivan, C=mikhail, D=sergey (4)
A=petr, B=ivan, C=sergey, D=mikhail (5)
A=petr, B=mikhail, C=ivan, D=sergey (6)
A=petr, B=mikhail, C=sergey, D=ivan (7)
A=mikhail, B=ivan, C=petr, D=sergey (8)
A=mikhail, B=petr, C=ivan, D=sergey (9)
A=mikhail, B=petr, C=sergey, D=ivan (10)
10 Solutions
But some lines are redundant since they are combined A and B. For example lines (1) and (4) (A=ivan, B=petr and A=petr, B=ivan).
I tried to use ! here:
playsChess(X,Y):-!,
friend(X),
friend(Y),
X<>Y,
X<>"sergey",
Y<>"sergey".
but it has no effect.
So the question is: how can I get rid of excess solution results?
Consider using the variable you introduce for each friend to directly represent the activity corresponding to that person:
friends([ivan=Ivan,petr=Petr,mikhail=Mikhail,sergey=Sergey]) :-
Fs0 = [Ivan,Petr,Mikhail,Sergey],
dif(Sergey, chess),
dif(Petr, tv),
select(books, Fs0, Fs1),
select(tv, Fs1, [chess,chess]).
Example query and its result:
?- friends(Fs).
Fs = [ivan=books, petr=chess, mikhail=chess, sergey=tv] ;
Fs = [ivan=chess, petr=books, mikhail=chess, sergey=tv] ;
Fs = [ivan=chess, petr=chess, mikhail=books, sergey=tv] ;
Fs = [ivan=tv, petr=chess, mikhail=chess, sergey=books] ;
Fs = [ivan=chess, petr=chess, mikhail=tv, sergey=books] ;
false.
The simplest way to solve the problem would be to constrain A and B further and force one to be "greater" than the other. I'm not sure exactly if this is the syntax in Visual Prolog, but try this. Note the use of A > B instead of A <> B.
question(A,B,C,D):-
friend(A),
friend(B),
friend(C),
friend(D),
playsChess(A,B),
readBook(C),
watchTV(D),
A > B, A<>C, A<>D,
B<>C, B<>D,
C<>D.
By constraining with > instead of <> you will ensure that you won't have symmetrical cases. For example, a > b is false, but a < b is true. However, both a <> b and b <> a are true, so the <> gives both a, b and b, a.
Your cut (!) did nothing because when you use it on a predicate that has only one clause like this:
my_predicate(...) :- !, subqueries ...
It just tells Prolog not to backtrack beyond the beginning of the first subquery. Since there are no other my_predicate clauses to backtrack to anyway, it has no effect.

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

error message, not working properly - prolog

How to repair a program to be ready to be used with SWI Prolog?
Link to source: http://ai-programming.com/prolog_bot_tutorial.htm
chatterbot2:
I modified read_string and write_string to read and write:
knowledge_base([
['WHAT IS YOUR NAME',
['MY NAME IS CHATTERBOT2.',
'YOU CAN CALL ME CHATTERBOT2.',
'WHY DO YOU WANT TO KNOW MY NAME?']
],
['HI',
['HI THERE!',
'HOW ARE YOU?',
'HI!']
],
['HOW ARE YOU',
['I''M DOING FINE!',
'I''M DOING WELL AND YOU?',
'WHY DO YOU WANT TO KNOW HOW AM I DOING?']
],
['WHO ARE YOU',
['I''M AN A.I PROGRAM.',
'I THINK THAT YOU KNOW WHO I''M.',
'WHY ARE YOU ASKING?']
],
['ARE YOU INTELLIGENT',
['YES,OFCORSE.',
'WHAT DO YOU THINK?',
'ACTUALY,I''M VERY INTELLIGENT!']
],
['ARE YOU REAL',
['DOES THAT QUESTION REALLY MATERS TO YOU?',
'WHAT DO YOU MEAN BY THAT?',
'I''M AS REAL AS I CAN BE.']
] ]).
select(0, [H|_], H).
select(N, [_|T], L) :- N > 0, N1 is N - 1, select(N1, T, L).
list_length([], 0).
list_length([_|T], Length):- list_length(T, Length2), Length is Length2 + 1.
quit_session(X):- X = bye,
nl, write('IT WAS NICE TALKING TO YOU USER, SEE YOU NEXT TIME!').
no_response_found(ListOfResponse):-
list_length(ListOfResponse, NumOfResponse),
NumOfResponse == 0,
write('I''M NOT SURE IF I UNDERSTAND WHAT YOU ARE TALKING ABOUT.'), !.
no_response_found(_).
get_keyword(KeyList, [KeyList,_]).
get_response(RespList, [_, RespList]).
select_response(RespList, Response):-
list_length(RespList, NumOfResponse),
IndexOfResponse is integer(random(NumOfResponse)),
select(IndexOfResponse, RespList, Response), !.
select_response(_, _).
find_match(Input, [FirstRecord|RestDatabase], ListOfResponse):-
get_keyword(Keyword, FirstRecord),
Keyword == Input, get_response(ListOfResponse, FirstRecord), !;
find_match(Input, RestDatabase, ListOfResponse).
find_match(_, [_], _).
chatterbot2:-
repeat,
nl, write('>'),
read(Input),
knowledge_base(ListOfRecord),
find_match(Input, ListOfRecord, ListOfResponse),
no_response_found(ListOfResponse),
select_response(ListOfResponse, Response),
write(Response), nl,
quit_session(Input).
When I try to use it I get:
鐀1 ?- chatterbot2.
>hi.
I'M NOT SURE IF I UNDERSTAND WHAT YOU ARE TALKING ABOUT.
ERROR: random/1: Domain error: `not_less_than_one' expected, found `0'
Exception: (7) select_response([], _G492) ? creep
2 ?- chatterbot2.
>'What do you do ?'.
I'M NOT SURE IF I UNDERSTAND WHAT YOU ARE TALKING ABOUT.
ERROR: random/1: Domain error: `not_less_than_one' expected, found `0'
Exception: (7) select_response([], _G485) ? creep
3 ?- chatterbot2.
>'Dog is black'.
I'M NOT SURE IF I UNDERSTAND WHAT YOU ARE TALKING ABOUT.
ERROR: random/1: Domain error: `not_less_than_one' expected, found `0'
Exception: (7) select_response([], _G485) ? creep
4 ?-
EDIT:
With random value =/= 0 :
1 ?- chatterbot2.
>'NOT IN BASE'.
I'M NOT SURE WHAT ARE YOU TALKING ABOUT._G907
is it possible to delete that value of blank arguement _G907 ?> and become only sentence?
Your errors in this particular example are caused by your input. Your input is matched to the first entries in your knowledge_base. Since none of your inputs match, the list that is returned has length 0, causing a problem with the call to random, which seems to need a value of at least 1.
Try 'WHAT IS YOUR NAME' as input for example and see if that works.

Resources