Calculation of graduation grade in Prolog - prolog

I have an error in my prolog program I try to calculate the CGPA in WinProlog and the code as follows:
grade(X).
start:-
( write('please enter ur cgpa'), read(X), X > 0 , X < 2,
write('ur cgpa is poor'), write(X)
; X >= 2, X < 3,
write('ur cgpa is good')
; X >= 3,
write('ur cgpa is excellent')
).
// comments
// %cgpa(X,good):-grade(X) , X>=2 , X<3.
// %cgpa(X,good):-grade(X) , X>=3 , write("your grade is excelent").
// is there anything missing, please help me

As #lurker noted, logical AND (,) and logical OR (;) are operators with different precedences. The expression doesn't necessarily bind the way you think it does. How does the expression
a , b ; c , d
bind? Is it...
AND having higher precendence than OR: (a,b) ; (c,d)
OR having higher precedence than AND: a , (b;c) , d
Equal precedence, left-associative: ( ( (a,b) ; c ) , d )
Equal precedence, right-associative: ( a , ( b ; (c,d)))
If you're not sure, make the binding clear with parentheses (but don't overdo it).
Further, one thing with Prolog is that alternatives are often better specified as individual clauses of a predicate rather than using the logical OR (;) operator. Something like this
evaluate_grade( X , poor ) :- X >= 0.0 , X < 2.0 .
evaluate_grade( X , good ) :- X >= 2.0 , X < 3.0 .
evaluate_grade( X , excellent ) :- X >= 3.0 .
is easier to debug, extend, modify and understand than your
( X>0 , X<2 ,
write('ur cgpa is poor') , write(X) ;
X>=2 , X<3,
write('ur cgpa is good') ;
X>=3 ,
write('ur cgpa is excellent')
)
Taking this approach also helps lead you to the Single Responsibility Principle — a fancy way of saying that things should do just one simple thing.
So, you might try decomposing the problem into smaller pieces that each do a single thing. Something like this:
start:-
read_grade(X) ,
evaluate_grade(X,R),
write('Your CGPA is ') ,
write(R) ,
nl
.
read_grade(X) :-
write('please enter your CGPA: ') ,
read(X),
number(X)
.
evaluate_grade( X , poor ) :- X >= 0.0 , X < 2.0 .
evaluate_grade( X , good ) :- X >= 2.0 , X < 3.0 .
evaluate_grade( X , excellent ) :- X >= 3.0 .

Related

Why would a provided prolog function not be allowed to be used twice in the program

error: Full stop in clause-body? Cannot redefine ,/2
I understand that the error is caused when our Prolog system already provides X/2, and you cannot redefine it. so you can either omit your own definition (thus, using the system-provided one instead) or rename your predicate - but im not understanding why I would be getting the error with this code
county_deaths(onedia,45).
county_deaths(essex,0).
county_deaths(franklin,0).
county_deaths(clinton,4).
county_deaths(fulton,19).
county_deaths(hamilton,1).
county_deaths(herkimer,3).
county_deaths(saratoga,14).
county_deaths(stLawrence,2).
county_deaths(warren,27).
county_deaths(washington,14).
county_deaths(lewis,5).
county_cases(clinton,95).
county_cases(essex, 36).
county_cases(franklin, 20).
county_cases(fulton, 196).
county_cases(hamilton, 5).
county_cases(herkimer, 103).
county_cases(lewis, 20).
county_cases(onedia, 917).
county_cases(saratoga, 463).
county_cases(stLawrence, 197).
county_cases(warren, 251).
county_cases(washington, 228).
start :-
findall( N , county_deaths(_,N), [N|Ns] ) ,
min_max( Ns , N , N , Min, Max ) ,
display_max(Max),
display_min(Min)
.
findall( N , county_cases(_,N), [N|Ns] ) ,
min_max( Ns , N , N , Min, Max ) ,
display_maxCase(Max),
display_minCase(Min)
.
min_max( [] , Min , Max , Min , Max ) .
min_max( [N|Ns] , X , Y , Min , Max ) :- N < X , !, min_max(Ns,N,Y,Min,Max) .
min_max( [N|Ns] , X , Y , Min , Max ) :- N > Y , !, min_max(Ns,X,N,Min,Max) .
min_max( [_|Ns] , X , Y , Min , Max ) :- min_max(Ns,X,Y,Min,Max) .
% multiple counties could have the same number of deaths, so
% we use findall/3 to enumerate all counties with the specified
% number of deaths.
display_max(N) :-
findall(C,county_deaths(C,N),Cs) ,
writeln(max_deaths:Cs:N)
.
display_min(N) :-
findall(C,county_deaths(C,N),Cs) ,
writeln(min_deaths:Cs:N)
.
display_maxCase(N) :-
findall(C,county_cases(C,N),Cs) ,
writeln(max_cases:Cs:N)
.
display_minCase(N) :-
findall(C,county_cases(C,N),Cs) ,
writeln(min_cases:Cs:N)
.
I believe the error is with the findall function - but that is something prolog provides and i need to use this method 3 times in my program. I have tried to solve this by renaming the method - but then it is no longer the provided findall function. how can i get around this error?

Finding the maximum number between three numbers using prolog

I have started learning prolog since yesterday and i am told to find the maximum number between three numbers. I am using SWI Prolog and this is the program i wrote so far.
% If-Elif-Else statement
gte(X,Y,Z) :- X > Y,write('X is greater').
gte(X,Y,Z) :- X =:= Y,write('X and Y are same').
gte(X,Y,Z) :- X < Y < Z,write('Y is greater').
gte(X,Y,Z) :- X < Z,write('Z is greater').
gte(X,Y,Z) :- X > Z,write('X is greater').
gte(X,Y,Z) :- Y > Z,write('Y is greater').
gte(X,Y,Z) :- Y < Z,write('Z is greater').
gte(X,Y,Z) :- X=:=Z,write('X and Z are same').
gte(X,Y,Z) :- Y=:=Z,write('Y and Z are same').
The output should've been ->
gte(12,24,36)
24 is greater.
True
instead its showing me this
Warning: c:/users/i3/documents/prolog/test.pl:3:
Warning: Singleton variables: [Z]
Warning: c:/users/i3/documents/prolog/test.pl:4:
Warning: Singleton variables: [Z]
Warning: c:/users/i3/documents/prolog/test.pl:5:
Warning: Singleton variables: [Z]
Warning: c:/users/i3/documents/prolog/test.pl:6:
Warning: Singleton variables: [Y]
Warning: c:/users/i3/documents/prolog/test.pl:7:
Warning: Singleton variables: [Y]
Warning: c:/users/i3/documents/prolog/test.pl:8:
Warning: Singleton variables: [X]
Warning: c:/users/i3/documents/prolog/test.pl:9:
Warning: Singleton variables: [X]
Warning: c:/users/i3/documents/prolog/test.pl:10:
Warning: Singleton variables: [Y]
Warning: c:/users/i3/documents/prolog/test.pl:11:
Warning: Singleton variables: [X]
true.
I cannot understand where is the error in this program.
A huge chunk of learning Prolog is learning to think recursively. So....
You should first solve the simplest problem: what is the greater of just 2 numbers? That's pretty easy, right?
max( X, X , X ) .
max( X, Y , X ) :- X > Y .
max( X, Y , Y ) :- X < Y .
Now that we can do that, expanding the solution space to consider 3 values is also easy: just determine the max value of the 1st two values, and then, the max of that and the 3rd value:
max( X , Y , Z , R ) :- max(X,Y,T), max(T,Z,R).
Further expanding the solution to consider any number of values is also easy: just repeat the above process until you've winnowed the list down to a single value.
max( [Z] , Z ) . % the max of a 1-item list is that item.
max( [X,Y|Zs] , M ) :- % the max of a list of 2+ items can be found by...
max(X,Y,Z) , % - find the max of the first two items, and
max([Z|Zs],M) % - recursing down, replacing those two items with that max value
. % Easy!
[Edited to note]
The basic algorithm for determining the maximum value of a list of number is:
While the list is of length greater than 1,
Determine the greater of the 1st two elements of the list
[Recursively replace the 1st two elements of the list with the greater of the two values
So on each iteration of the recursion, the length of the source list is reduced by 1 and the head of the list is always the current high-water mark, the current maximum value. Once the length of the list has been reduced to one, we have solved the problem at hand.
One could coalesce max/3 and max/2 into a single predicate:
max( [X] , X ) .
max( [X,Y|Zs] , R ) :- X =:= Y , max( [X|Zs] , R ) .
max( [X,Y|Zs] , R ) :- X > Y , max( [X|Zs] , R ) .
max( [X,Y|Zs] , R ) :- X < Y , max( [Y|Zs] , R ) .
But I think that finding the maximum of 2 values is a common enough special case that it's worth breaking it out into its own predicate: max(X,Y,Max).
One could also use a helper predicate with an extra argument that explicitly carries the extra state, the current high value, thus:
max( [X|Xs] , R ) :- max(Xs,X,R) .
max( [] , R , R ) .
max( [X|Xs] , Y , R ) :- X =:= Y , max(Xs,Y,R) .
max( [X|Xs] , Y , R ) :- X < Y , max(Xs,Y,R) .
max( [X|Xs] , Y , R ) :- X > Y , max(Xs,X,R) .
So in the above, we simply pop off the head of the source list and invoke the helper with its accumulator seeded with that value. Once the source list is exhausted, the accumulator contains the desired result.
TIMTOWTDI[1] as they say.
[1] There's more than one way to do it

How can I do cryptarithmetics in Prolog?

Each of the 7 different letters stands for a different digit. The aim is to find a substitution of digits for the letters such that the resulting sum is arithmetically correct. The solution should then produce all of the combinations of the digits that satisfy the addition problem above. Putting in a query such as crypto(P,I,N,G,O,F,U) should return your solution.
The cryptarithmetic puzzle goes like this:
P I N G
P O N G
+ F U N
---------
I G N I P
Use clpfd! Based on my previous answer to a very similar question, we run the following query:
?- Eq = ([P,I,N,G] + [P,O,N,G] + [F,U,N] #= [I,G,N,I,P]),
crypt_arith_(Eq,Zs),
labeling([],Zs).
Eq = ([7,1,9,4] + [7,0,9,4] + [6,2,9] #= [1,4,9,1,7]), Zs = [7,1,9,4,0,6,2]
; Eq = ([8,1,4,7] + [8,3,4,7] + [9,2,4] #= [1,7,4,1,8]), Zs = [8,1,4,7,3,9,2]
; Eq = ([8,1,4,7] + [8,9,4,7] + [3,2,4] #= [1,7,4,1,8]), Zs = [8,1,4,7,9,3,2]
; false.
Assuming this is a simple substitution cipher we're talking about (and just for fun), I'll take a stab at it. One should note that this is completely untested.
I'm going to set this up in a generic way, so you can say something like:
substitution_cipher( CipherExpr , CipherResult , Expr , Result , Key ).
We'll make the rule that the enciphered stuff is represented by atoms, so you can say something like this:
substitution_cipher( ping + pong + fun , ignip , Expr , Sum , Key ) .
And get the results you'd expect.
So...
First, you need the set (discrete, unique) of characters found in the cipher text:
character_set( Expr , Charset ) :-
setof( C , A^Cs^( atoms_in_expression( Expr , A ) , atom_chars(A,Cs) , member(C,Cs) ) , Charset ) .
atom_in_expression( Expr , Value ) :- atom(Expr) .
atom_in_expression( Expr , Value ) :-
Expr =.. [ _ , Left , Right ] ,
(
values( Left , Value )
;
values( Right, Value
) .
The above walks the parse tree of an expression like a * b + c * d, finding each of the leaf nodes (atoms), deconstructing them into the characters that comprise them. setof/3 ensures that the resulting list is sorted and unique.
Once you have that, you need a way of generating all the possible keys (key == mapping between a character and a digit). We want to be able to say something like
generate_key( [a,b,c] , Key )
and get back
Key = [a:1,b:2,c:3]
etc.
So:
generate_key( Charset , Key ) :-
generate_key( Charset , [] , Key ) .
generate_key( [] , Key , Key ) . % when we've exhausted the character set, we're done.
generate_key( [C|Cs] , Acc , Key ) :- % otherwise...for each character
digit(D) , % find a digit
\+ member( _:D , Acc ) , % that hasn't yet been used
generate_key( Cs , [C:D|Acc] , Key ) % map it to the character and recurse down.
.
digit(D) :- between(0,9,X) , atom_number(D,X).
Then you need a way to decode a cipher expression like
ping + pong + fun
and [try to] turn it back into proper numbers. This isn't much different than walking the parse tree and enumerating the leaf node atoms, but here we need to get them back into numeric form.
If the expression is an atom, we
decompose it into its constituent characters,
using our key, map each character to its corresponding digit,
then we turn that list of digits back into a number
decode( Key , CipherExpr , PlainExpr ) :-
atom(CipherExpression) ,
atom_chars(CipherExpression,Cs) ,
findall( D , ( member(C,Cs), member(C:D,Key) -> true ; D=C ) , Ds ) ,
number_chars( PlainExpr , Ds )
.
The general case is easy. An infix expression like ping + pong is really the prolog term +(ping,pong). We:
Decompose a infix term like ping + pong into an operator (+) and its left and right sub-expressions.
Then we recursively decode the left and right sub-expressions
Finally, we reassemble the [decoded] expression.
decode( Key , CipherExpr , PlainExpr ) :-
CipherExpr =.. [Op,L,R] ,
decode(L,L1) ,
decode(R,R1) ,
PlainExpr =.. [Op,L1,R1]
.
Then you can put it all together:
substitition_cipher( CipherExpr , CipherResult , PlainExpr , PlainResult , Key ) :-
character_set( CipherExpr = CipherResult , Charset ) ,
generate_key( Charset, Key ) ,
decode( Key , CipherExpr , PlainExpr ) ,
decode( Key , CipherResult , PlainResult ) ,
PlainResult =:= PlainExpr
.

Take a positive integer n and produce a list that prints out a list in prolog?

I am trying to write a prolog rule to take a positive integer n and gives back a list that counts down from n to 0, including negatives. So spiralDown(4,L) would return L=[4,-4,3,-3,2,-2,1,-1,0]. I got it to return the positive values but cant get it to return the negative values.
ruleOne(-1,[]).
ruleOne(X,[H|T]) :-
Y is X-1,
H=X,
ruleOne(Y,T).
This is an attempt at a solution that has deficiencies, but it would point you in the correct direction, I hope:
spiral_down(N, [N, Minus_N|Rest]) :-
succ(N0, N),
Minus_N is -N,
spiral_down(N0, Rest).
spiral_down(0, [0]).
Here's one solution:
spiral_down(Hi,Ns) :-
integer(Hi) ,
Hi >= 0 ,
Lo is -Hi ,
spiral_down(Hi,Lo,Ns)
.
spiral_down( Hi , Hi , [Hi] ) .
spiral_down( Hi , Lo , [Hi|Ns] ) :-
Hi > Lo ,
H1 is Hi-1 ,
spiral(H1,Lo,Ns)
.
And another:
spiral_down( 0 , [] ) .
spiral_down( M , [M,N|Xs]) :-
M > 0 ,
N is -M ,
M1 is M-1 ,
spiral_down( M1 , Xs )
.

Unifying a number to a list in Prolog

Alright, so I'm working on a homework assignment, this is supposed to be a four function calculator taking in a list of strings [three, times, two] for example, and output a number. It only considers the numbers from one to twenty in its initial list. The following code is all my own. It runs up to the point where it takes in the last item in the list (that I've been using to test it, but the problem is for any of the inputs) in numberize and then will not unify.
calculator([twenty, times, three, plus, five, divided_by, two],Total).
I know the solution must be an easy one, but I'm not experienced enough yet in Prolog to figure it out.
My question is: how do I fix my code so that it runs the way I want it to?
calculator(X,Total):-
numberize(X,L),
reverse(L,L1),
func(L1,Total).
numberize([X,Y|T],L):-
str2num(X,X1),
numberize(T,[Y,X1|L]).
numberize([X],L):-
str2num(X,X1),
%somehow add on the X1 to the front of L without any errors and it's golden
/*Whatever that line is*/L is [X1|L].
func([X1,X,Z1|T], Total):-
(X == times, times(X1,Z1,Ttl));
(X == plus, plus(X1,Z1,Ttl));
(X == divided_by, divided_by(X1,Z1,Ttl));
(X == minus, minus(X1,Z1,Ttl)),
func([Ttl|T],Total).
str2num(one, X):- X is 1.
str2num(two, X):- X is 2.
str2num(three, X):- X is 3.
str2num(four, X):- X is 4.
str2num(five, X):- X is 5.
str2num(six, X):- X is 6.
str2num(seven, X):- X is 7.
str2num(eight, X):- X is 8.
str2num(nine, X):- X is 9.
str2num(ten, X):- X is 10.
str2num(eleven, X):- X is 11.
str2num(twelve, X):- X is 12.
str2num(thirteen, X):- X is 13.
str2num(fourteen, X):- X is 14.
str2num(fifteen, X):- X is 15.
str2num(sixteen, X):- X is 16.
str2num(seventeen, X):- X is 17.
str2num(eighteen, X):- X is 18.
str2num(nineteen, X):- X is 19.
str2num(twenty, X):- X is 20.
times(X,Y,Prod):-
Prod is X*Y.
plus(X,Y,Sum):-
Sum is X+Y.
divided_by(X,Y,Quo):-
Quo is X/Y.
minus(X,Y,Dif):-
Dif is X-Y.
Small style remark: use facts for str2num/2: just str2num(one, 1). instead of str2num(one, X):- X is 1., etc. Added benefit is that now the predicate can be used both ways, like str2num(Word, 1).
As for the main question, you are almost correct.
The whole numberize predicate can be as simple as this:
numberize([X], [N]) :-
str2num(X, N).
numberize([X, Op | T], [N, Op | NewT]) :-
str2num(X, N),
numberize(T, NewT).
Let's test it:
?- numberize([one, plus, two, minus, three], L).
L = [1, plus, 2, minus, 3]
But you need to remove call to reverse from calculator:
calculator(X,Total):-
numberize(X,L),
func(L,Total).
You have almost correct func predicate. One problem: in Prolog you should have braces around disjunction:
func([X1,X,Z1|T], Total):-
(
X == times, times(X1,Z1,Ttl)
;
X == plus, plus(X1,Z1,Ttl)
;
X == divided_by, divided_by(X1,Z1,Ttl)
;
X == minus, minus(X1,Z1,Ttl)
),
func([Ttl|T],Total).
The second problem: when your list reduced to one number (think how func([1,plus,2], Total) will call func([3], Total) the predicate will fail. All you need to fix this is the rule that Total of a list with just 1 number is the number itself:
func([X], X).
Now the whole thing works:
?- calculator([one, plus, two], Total).
Total = 3
?- calculator([one, plus, two, minus, four], Total).
Total = -1
The way I'd approach this is to start by defining a grammar for arithmetic expressions. The "standard" way of defining grammars is left-recursive. Since prolog does recursive descent parsing, the grammar can't be left-recursive. Every iteration has to remove something from the token stream, lest you go in to the death spiral of infinite recursion. Here's my non-left recursive grammar for a 4-banger calculator like yours:
expression : multiplicative_expression '+' expression
| multiplicative_expression '-' expression
| multiplicative_expression
;
multiplicative_expression : factor '*' multiplicative_expression
| factor '/' multiplicative_expression
| factor '%' multiplicative_expression
| factor
;
factor : '-' value
| '(' expression ')'
| value
;
value : number
Once we have the grammar, the prolog code pretty much writes itself. First, some facts to work with. We need a list of operators and their types (along with the equivalent prolog operator:
operator( plus , additive , '+' ) .
operator( minus , additive , '-' ) .
operator( times , multiplicative , '*' ) .
operator( divided_by , multiplicative , '/' ) .
operator( modulo , multiplicative , 'mod' ) .
And a words-to-numbers-map:
number_word( zero , 0 ).
number_word( one , 1 ).
...
number_word( nineteen , 19 ) .
number_word( twenty , 20 ) .
And we need our interface predicate, calculate/2:
%--------------------------------------------------------------------
% we can calculate a result if Expr is a valid expression
% that consumes all the available tokens in the token stream
%---------------------------------------------------------------------
calculate(Expr,Result) :- expr( Expr , Result , [] ) .
That invokes the "start symbol" of the grammar, expr/3. expr/3 (and the other worker predicates) are pretty much direct restatements of the grammar, with the additional requirement that they need to hand back the unconsumed portion of the input token stream. The parse is successful, if, at the end of the day, the token stream is empty:
expr( Xs , Result , Tail ) :- % per the grammar, an expression is
mult( Xs , LHS , [Sym|X1] ) , % - a multiplicative expression, followed by
operator( Sym , additive , Op ) , % - an infix additive operator, followed by
expr( X1 , RHS , X2 ) , % - another expression
Term =.. [Op,LHS,RHS] , % * in which case, we construct the proper prolog structure
Result is Term , % * in which case, we evaluate the result in the usual way
Tail = X2 % * and unify any remaining tokens with the Tail
. %
expr( Xs , Result , Tail ) :- % alternatively, an expression is simply
mult( Xs , Result , Tail ) % - a single multiplicative expression
. %
The worker predicate for multiplicative terms, mult/3 is pretty much identical — a direct restatement of the grammar:
mult( Xs , Result, Tail ) :- % a multiplicative expression is
factor( Xs , LHS , [Sym|X1] ) , % - a factor, followed by
operator( Sym , multiplicative , Op ) , % - an infix multiplicative operator, followed by
mult( X1 , RHS , X2 ) , % - another factor
evaluate( Op , LHS , RHS , Result ) , % * in which case, we evalute the result in the usual way
Tail = X2 % * and unify any remaining tokens with the tail
. %
mult( Xs , Result , Tail ) :- % alternatively, a multiplicative expression is simply
factor( Xs , Result , Tail ) % - a single factor
. %
Finally, since we're not wrassling with higher-precedence operations like unary minus, exponentiation or parentheses that change operator precedence, a factor is simply a number word that can be converted into an integer value:
factor( [X|Xs] , Value , Xs ) :- % a factor is simply
number_word(X,Value) % - a number value (in our case, a word that we convert to an integer)
.
and a simple helper to evaluate each subexpression as needed:
evaluate( Op , LHS , RHS , Result ) :- % to evaluate an infix term,
Term =.. [Op,LHS,RHS] , % - use univ to convert to the correct prolog structure, and
Result is Term % evaluate it as the result
. %

Resources