PROLOG Asignation problems - prolog

I have to solve a problem involving the WWESupercard game. The idea is to to take 2 cards and make them fight, comparing each stat alone and every combination, making 10 comparations in total. A fighter wins if it gets more than 50% of the fights (6/10).
The problem I have is that the "is" statement is not working for me.
This are some of the "solutions" I've tried so far, using only the base stats and no combinations for faster testing, none of them are working as I intend:
leGana(X,Y) :- T is 0,
((A is 0, (pwr(X,Y) -> A1 is A+1));
(B is 0, (tgh(X,Y) -> B1 is B+1));
(C is 0, (spd(X,Y) -> C1 is C+1));
(D is 0, (cha(X,Y) -> D1 is D+1))),
T1 is T+A1+B1+C1+D1, T1 > 2.
leGana(X,Y) :- T is 0,
((pwr(X,Y) -> T is T+1);
(tgh(X,Y) -> T is T+1);
(spd(X,Y) -> T is T+1);
(cha(X,Y) -> T is T+1)),
T1 > 2.
I've tried other ways, but I keep getting the same 2 error, most of the times:
It fails on "T is T+1" saying "0 is 0+1" and failing
On example 1, it does the "A1 is A+1", getting "1 is 0+1", but then it jumps directly to the last line of the code, getting "T1 is 0+1+_1543+_1546 ..."
Also, sorry if the way I wrote the code is not correct, it's my first time asking for help here, so any advice is welcome.

Prolog is a declarative language, which means that a variable can only have a single value.
If you do this:
X is 1, X is 2.
it will fail because you're trying to say that X has both the value 1 and the value 2, which is impossible ... that is is is not assignment but a kind of equality that evaluates the right-hand side.
Similarly
X = 1, X = 2.
will fail.
If you want to do the equivalent of Python's
def f(x):
result = 1
if x == 0:
result += 1
return result
then you need to do something like this:
f(X, Result) :-
Result1 = 1,
( X = 0
-> Result is Result1 + 1
; Result = Result1
).

Related

Finding consistent assignments for logical formulas

I am about to implement a prover for logical terms in Prolog. My current code is not really presentable, therefore, I will just state, what I want my program to do and hopefully you can give me some good advice for that :)
It should take a list of variables (so to say the logical arguments) and secondly a logical formula containing these arguments (e.g. 'not'(A 'and' B) 'or' 'not'(B 'and' C) 'or' ... and so forth).
As output I would like my program to respond with the possible consistent assignments. The single arguments can either be true (1) or false (0).
So I aim for a return like A=0, B=0, C=0 ; A=1 and so forth.
I am happy for every help concerning my program :)
There are several ways one could approach this. One way that is convenient in terms of syntax would be to define operators, something like this:
:- op(500, fx, not).
:- op(600, xfx, and).
:- op(700, xfx, or).
(I am just guessing at reasonable precedence settings here, but just for illustration. See the op documentation for details.)
Having done that, you can write an expression such as: A and B and Prolog will "see" it as and(A, B):
| ?- write_canonical(A and B).
and(_23,_24)
From there, you need to have a way to evaluate an expression. There are lots of questions on SO here in this regard (do a search in this site on [prolog] boolean expression evaluation), but I'll provide a simple example. It's now all about how you want to represent a result, and about recursion.
When it comes to representing a result, you could use Prolog's success/fail mechanism since you are dealing with boolean results. Or, you can have an explicit result, such as 0 and 1. Let's try 0 and 1 since that's your representation for true and false.
% Describe a valid boolean
bool(0).
bool(1).
% The evaluation of a valid boolean is itself
exp_eval(X, X) :- bool(X).
% Evaluation of an 'and' expression
exp_eval(and(A, B), Result) :-
exp_eval(A, ResultA),
exp_eval(B, ResultB),
Result #= ResultA * ResultB.
% Evaluation of an 'or' expression
exp_eval(or(A, B), Result) :-
exp_eval(A, ResultA),
exp_eval(B, ResultB),
% Just a little trick to get 1 if either ResultA or ResultB or both are 1
Result #= (ResultA + ResultB + 1) // 2.
% Evaluation of a 'not' expression
exp_eval(not(A), Result) :-
exp_eval(A, ResultNot),
Result #= 1 - ResultNot. % 0 ---> 1, and 1 ---> 0
Instead of calculating "boolean" 1/0 results as I've done above, you could, instead, assert them as facts like so:
bool_not(0, 1).
bool_not(1, 0).
bool_and(0, 0, 0).
bool_and(0, 1, 0).
bool_and(1, 0, 0).
bool_and(1, 1, 1).
bool_or(0, 0, 0).
bool_or(0, 1, 1).
bool_or(1, 0, 1).
bool_or(1, 1, 1).
And then, for example, instead of Result #= (ResultA + ResultB + 1) // 2 you could just have, bool_or(ResultA, ResultB, Result).
Now that we can evaluate expressions, we want a solver:
solve(Exp) :-
term_variables(Exp, Variables),
maplist(bool, Variables), % Variables should be valid booleans
exp_eval(Exp, 1). % We only want true results for the expression
Note that in the original problem statement, it's said that the variable list would be given as an argument, but you can use term_variables/2 to obtain the variables from an expression.
Then you can run the solver:
| ?- solve(not(A and B) or not(B and C)).
A = 0
B = 0
C = 0 ? a
A = 0
B = 0
C = 1
A = 0
B = 1
C = 0
A = 0
B = 1
C = 1
A = 1
B = 0
C = 0
A = 1
B = 0
C = 1
A = 1
B = 1
C = 0
no
| ?-
I don't know what your representation is for an expression. But whatever it is, you can map it to the above solution. What I've shown is simple and clear. You could skip the op/3 stuff and use standard term expressions, like, or(not(and(A,B)), not(and(B,C))) using the above code. If you have your input as some kind of token sequence, like, [not, (, A, and, B, ...] then you'll have to do a little list processing.

Why can't my rule solve for X in a simple algebraic equation?

I'm new to Prolog, so please be gentle.
This is my rule:
solve(X) :- A = B, A is (7 * (X - 2)), B is (3 * (X + 4)).
Obviously, the correct answer here is 6.5. If I give that to Prolog, it confirms:
| ?- solve(6.5).
yes
However, if I ask Prolog to do the dirty work, it throws an error:
| ?- solve(X).
uncaught exception: error(instantiation_error,(is)/2)
I fully concede that whatever is going on here is due to my misunderstanding of Prolog. Can someone explain to me how I might get this to work or why it won't work?
In Prolog, is is an arithmetic evaluation operator. It calculates the result of an expression on its right side, and assigns it to a variable on its left side.
The expression to be evaluated must contain only numbers and arithmetic operators/functions. In other words, to evaluate an expression, is must already know all the numbers in it.
Another way of saying this is that is is "unidirectional", unlike the = which is bi-directional. Which is what you expected. And that is the meaning of the error that you got.
Solving such equations - constraints - is a job for a constraint solver.
You can use a library for this, available in SWI-Prolog at least: library(clpr) and library(clpq).
Here from the top level for Reals:
?- use_module(library(clpr)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}.
X = 6.5 ;
false.
Or, if you use Rationals:
?- use_module(library(clpq)).
true.
?- {7 * (X - 2) = 3 * (X + 4)}, R is float(X).
X = 13 rdiv 2,
R = 6.5.
If you want to do it yourself, it will be of course much more work. You would have to write code like
...,
( ground(X)
-> 7 * (X - 2) =:= 3 * (X + 4)
; X is (3*4 + 2*7) / (7 - 3)
),
...
By the way, what you are doing: A = B, A is ..., B is ....
This is a bit dangerous, for example:
?- A = B, A is 3 - 2, B is sin(pi/2).
false.
?- 3 - 2 =:= sin(pi/2).
true.
3 - 2 evaluates to the integer 1; then, sin(pi/2) evaluates to the floating point number 1.0, and this does not unify with the integer 1. So, the first query fails!
?- 1 = 1.0.
false.
Prolog works by unification. It tries to make structures the same.
So, for example, if I try to unify [3, X, 5] with [3, 4, 5] that works fine and X = 4.
In your code you are first saying A = B. That's fine as initially A and B are not instantiated so you are basically tying their destinies to each other - if A is later instantiated then B automatically is too, or visa-versa.
Then you go on to ask A is (7 * (X - 2)). Now if you have already unified X with 6.5 then this can be evaluated - A is then unified with 7 * (6.5 - 2) or 31.5. But remember that A was already unified with B, so B now also is 31.5.
Now you say B is (3 * (X + 4)). So with X unified to 6.5 and B unified with 31.5 this is the same as 31.5 is (3 * (6.5 + 4)). The right hand side is 31.5 so this is 31.5 is 31.5 which is true.
So, solving for solve(6.5) works.
However, if you try to solve for X then the first predicate works just fine. But the second one doesn't. It's like me asking "What's 7 times the number that is 2 less than the number I'm thinking of?" Unless I tell you the number I'm thinking of you can't give me an answer. The same for Prolog. It gets stuck and reports an error.

Prolog - adding two arguments, even if one is not a number

in Prolog, how should I proceed when I want to add two arguments, even if one is not a number. So for instance, if I enter add2args(1,2,R). the result should be R = 3. If I enter add2args(1,x,R). the result should be R=1+x.
So far I have this:
add_2args(X,Y,R):- number(X),number(Y), R is (X+Y).
Which allows me to add two numbers, but I don't know how I can get it to print out anything other than true and false if X and Y are not numbers which is normal since number(X) checks if X is a number or not. What other rule do I have to add to get the desired result?
Prolog will view an expression symbolically (as a Prolog term) unless explicitly evaluated with something like is/2. So the simplest way to do this in your case would be the following:
add_2args(X, Y, R) :-
( number(X), number(Y) % Both X and Y are numbers, then...
-> R is X + Y % Evaluate the expression
; R = X + Y % Else, just unify R with the expression
).
The R = X + Y will not evaluate the expression but only unify the term X + Y with R. This is also a nice "Prolog beginner's guide" illustration for the difference between =/2 and is/2. If you wrote, for example, R = 2 + 3, then did a write(R) you would see 2 + 3, not 5. You could subsequently do, Result is R which would then evaluate the expression R and yield Result = 5.
| ?- R = 2 + 3, Result is R.
R = 2+3
Result = 5
yes
| ?-

Use of conditionals in Prolog

I am confused about how conditionals are used in prolog. While Example 1 is the case for a conditional, Example 2 shows a case where it says NewPos = Exit on the other side of the -> operator. Is it checking if NewPos is equal to Exit or is it the case that the value Exit is being assigned to NewPos? Shouldn't an is be used to assign values in prolog?
Sorry if this is a very basic syntax question.
Example 1
Current = b(_,Cost,NewPos),
( Exit=none -> backtrack_path(Current,Visited,RPath)
; Exit=b(5,5) -> backtrack_path(Current,Visited,RPath)
Example 2
Current = b(_,Cost,NewPos),
( Exit=none -> backtrack_path(Current,Visited,RPath)
; otherwise -> NewPos = Exit,
backtrack_path(Current,Visited,RPath)
For a more detailed look at the Prolog -> operator, see What's the meaning of Prolog operator '->'. Your examples are covered below.
Example 1:
Current = b(_,Cost,NewPos),
Unifies Current with the term, b(_, Cost, NewPos). Unficiation in Prolog is not the same as assignment. In unification, Prolog will attempt to match the two arguments of =/2 possibly instantiating variables on either side to achieve the unification. If, for example, Current, Cost and NewPos are all uninstantiated, then Current will be instantiated with b(_, Cost, NewPos) (using the same variables, Cost and NewPos. If, later on, Cost is instantiated with, say, 10, then Current will also become, b(_, 10, NewPos), in effect.
( Exit=none -> backtrack_path(Current,Visited,RPath)
; Exit=b(5,5) -> backtrack_path(Current,Visited,RPath)
; has lower precedence than ->, so this is, in effect:
( Exit=none
-> backtrack_path(Current,Visited,RPath)
; ( Exit=b(5,5)
-> backtrack_path(Current,Visited,RPath),
...
),
...
)
Exit = none will attempt to unify Exit and the atom, none. It will succeed if Exit is uninstantiated (and will then instantiate Exit with none), or can succeed if Exit is already instantiated as none. It will fail if Exit is instantiated with any term that doesn't match none.
If Exit = none succeeds, then the first backtrack_path(Current, Visited, RPath) is called. If it fails, then an attempt is made to unify Exit with b(5,5). If the prior Exit = none failed, then we got to this point because Exit was already unified with something that didn't match none, and it will succeed Exit = b(5,5) only if it was already unified with a term that looks like, b(X, Y). Otherwise, it will also fail. If it succeeds, then, again, backtrack_path(Current, Visited, RPath) will be called.
Example 2:
Current = b(_,Cost,NewPos),
( Exit=none -> backtrack_path(Current,Visited,RPath)
; otherwise -> NewPos = Exit,
backtrack_path(Current,Visited,RPath)
, has highest precedence, followed by ->, followed by ;. So this is effectively:
Current = b(_,Cost,NewPos),
( Exit=none
-> backtrack_path(Current,Visited,RPath)
; ( otherwise
-> ( NewPos = Exit,
backtrack_path(Current,Visited,RPath),
...
),
...
),
...
)
See the discussion above about unification. If Exit = none succeeds, then backtrack_path(Current, Visited, RPath) is called. Otherwise, then then otherwise call is done (NOTE that if otherwise is a block of code, then operator precedence can affect the grouping I show above, so I'm assuming otherwise is a block which has precedence over the following ->).
If otherwise succeeds, then Prolog attempts NewPos = Exit, and if that succeeds, it will move on to call, backtrack_path(Current, Visited, RPath). If the NewPos = Exit unification fails, then, in this case, lacking an "else" or "OR" (;) type of expression, it might backtrack all the way to Current = b(_, Cost, NewPos). Where it backtracks to depends completely upon what other code you have in this clause (it's a bit hypothetically presented, so it could be anything).
Regarding is/2
is/2 is used to (a) evaluate a numeric expression as its second argument, and (b) unify the result of the expression evaluation with the first argument. Here are some examples, also showing the contrast with =/2 (unification):
| ?- X = A + B.
X = A+B
yes
Here, X is unified with the term, A + B. So X is now instantiated with the term A+B (which is the term, '+'(A, B))
| ?- A = 2, B = 3, X = A + B.
A = 2
B = 3
X = 2+3
yes
X is unified with the term, A + B. A is unified with 2 (and so A is instantiated with the value 2), and B is unified with 3. So X is unified with 2+3 (or `'+'(2,3)).
| ?- A = 2, B = 3, X is A + B.
A = 2
B = 3
X = 5
yes
The expression on the right hand side of is (the second argument to is/2) is evaluated yielding 5. Then X is instantiated to 5.
| ?- A = 2, X is A + B.
uncaught exception: error(instantiation_error,(is)/2)
B isn't instantiated, so the expression, A + B cannot be evaluated, so is/2 fails due to an instantiation error.
| ?- A = 2, B = 3, Z = 5, Z is A + B.
A = 2
B = 3
Z = 5
yes
A, B, and Z are all instantiated to numeric values, and Z is A + B succeeds since A + B evaluates to 5, which is unifiable with Z which also has the value 5.
| ?- A = 2, B = 3, Z = 4, Z is A + B.
no
A, B, and Z are all instantiated to numeric values, and Z is A + B fails since A + B evaluates to 5, which is not unifiable with Z which has the value 4.
| ?- A = 2, B = 3, X = A + B, Z is X.
A = 2
B = 3
X = 2+3
Z = 5
yes
X is unified with the term, A + B, which is the term 2 + 3 since A has been instantiated with 2, and B with 3. Z is unified with the evaluation of the expression X (which is 2 + 3) and so has the value 5.

How to write kind of Conditional Planning in Prolog?

I tried to write a prolog code that can understand student program written in C#. Now I'm stuck in the process of recognizing the 'if' statement in student's program. For example:
The following is the code that I expect from the student.
int d = int.Parse(Console.ReadLine()); // value d is inputted by user
int s = 0;
if (d>0)
s = 2;
else if (d==0)
s = 1;
else
s = 0;
I defined the goal of this expected code as:
goal:-
hasVarName(Vid_s, s),
hasVarName(Vid_d, d),
hasVarValue(Vid_d, Vd),
((not(gt(Vd,0)); hasVarValue(Vid_s, 2)), %eq: [Vd>0] -> [val_s = 2]
((gt(Vd,0); not(eq(Vd,0)); hasVarValue(Vid_s, 1)), %eq: [~(Vd>0)^(Vd=0)] -> [val_s = 1]
((gt(Vd,0); eq(Vd,0); hasVarValue(Vid_s, 0). %eq: [~(Vd>0)^~(Vd=0)] -> [val_s = 0]
The problem is how can I represent the above student code in prolog facts and rules, to find out that the goal is satisfied for any possible conditions.
I tried to change the first part of the student code to become facts like the following, but don't really know how to represent the student's 'if' statement as facts/rules in prolog (I guess, I should not change it to prolog 'if', right?)
hasVarName(varID_d, d)
hasVarValue(varID_d, val_d) %it is unknown, so I represent it as symbol 'val_d'
hasVarName(varID_s, s)
hasVarValue(varID_s, 0)
And another one, in my goal, when I have comparison such as gt(Vd,0) I think I cannot use the prolog greater than operator, neither Vd> 0 nor Vd #> 0 cause the value in Vd is actually a certain value entered by user, but it is represented as symbolic value (in this case it is: val_d).
Note: using the above goal, I think the defined goal will be satisfied if student code is changed to the following code.
int d = int.Parse(Console.ReadLine()); // value d is inputted by user
int s = 0;
if (d>0)
s = 2;
else if (d==0)
s = 1;
or
int d = int.Parse(Console.ReadLine()); // value d is inputted by user
int s = 10; // any random initialization
if (d>0)
{
int x = 2; // unnecessary step, but still Ok.
s = x;
}
else if (d==0)
s = 1;
else
s = 0;
But again, I need help/idea how this code can be represented in prolog as action/rule/fact to meet the goal.
Any help is really appreciated.
Many thanks
I guess you tried to model if-then-else via implication, using
the following boolean identity:
A -> B == ~A v B.
Instead of using conjunctions of implications, it is easier
to use disjunction to choose between branches, and conjunction
along the control flow. But that you exclude previous if-conditions
via negation is still necessary.
Take your example:
if (d>0)
s = 2;
else if (d==0)
s = 1;
else
s = 0;
You can use CLP( * ) to model it. Add extra variables so that
variables are not overridden, but this is not a problem in the
small above snippet. In CLP( * ) the above snippet becomes, I
am using CLP(FD) for simplicity:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.3.0)
Copyright (c) 1990-2012 University of Amsterdam, VU Amsterdam
?- use_module(library(clpfd)).
?- [user].
that_if(D, S) :-
(D #> 0, S #= 2;
D #=< 0, D #= 0, S #= 1;
D #=< 0, D #\= 0, S #= 0)
^D
In a decent CLP( * ) system you can arbitrarily instantiate or
constrain D or S in a query. We get for example already
in CLP(FD):
/* What conditions give result S #= 1 ? */
?- S #= 1, that_if(D, S).
S = 1,
D = 0 .
/* What results give condition D #= 1 */
?- D #= 1, that_if(D, S).
D = 1,
S = 2 ;
false.
/* What conditions give a result S #=< 1 */
?- S #=< 1, that_if(D, S).
S = 1,
D = 0 ;
S = 0,
D in inf.. -1.
/* What results give a condition D #>= 0 */
?- D #>= 0, that_if(D, S).
S = 2,
D in 1..sup ;
D = 0,
S = 1 ;
false.
Bye
Usually a language implementation requires an abstract syntax tree, where it's convenient to specify the semantic actions that implements the constructs we are allowed to express.
You seem skipping the phase of building the syntax tree, and (by hand?) represent the intermediate level of the program.
If you stick to such medium level representation, you can use a recursive term (an abstract tree, in effect) like if(Condition, Then, Else) where each var it's in turn a syntax tree.
Otherwise, a more practical representation (usually applied for imperative language), use the concepts of basic blocks (an instruction sequence without jumps) and then labels, to describe the execution flow.
The result it's a graph, and the behaviour of the program is determined by the 'topology' of that representation.
goal:-
hasVarName(Vid_s, s),
hasVarName(Vid_d, d),
hasVarValue(Vid_d, Vd),
%eq: [Vd>0] -> [val_s = 2]
((not(gt(Vd,0)); hasVarValue(Vid_s, 2), goto(label(0))),
%eq: [~(Vd>0)^(Vd=0)] -> [val_s = 1]
((gt(Vd,0); not(eq(Vd,0)); hasVarValue(Vid_s, 1), goto(label(0))),
%eq: [~(Vd>0)^~(Vd=0)] -> [val_s = 0]
((gt(Vd,0); eq(Vd,0); hasVarValue(Vid_s, 0)), % the goto is useless here...
label(0),
.....
Note that I didn't pay any attention to describe correctly your sample program, just placed the jumps to show this possibility...
edit I think that the general problem can't be solved, being equivalent to the halting problem for a Turing Machine. For the particular case at hand, without loops, I would attack the problem using abstract interpretation on the AST. I.e. an interpreter that computes what's interesting.
If it's feasible depends on the generality of your target programs. You should be able to partition the integer domain for each variable involved in each condition point. Things become rapidly complex...
Specifically, at the condition point of the IF THEN ELSE attempt to partition the domain. Using such approach, let Prolog execute the IF testing both branches, propagating the values. But, as I said, is not really easy...

Resources