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.
Related
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
).
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.
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
| ?-
append([],U,U).
append([X|U1],U2,[W|U3]) :- **W = X** , append(U1,[X|U2],[I|Quyruk]) ,
**W = I**, U3 = Quyruk .
This code appends first two lists when I delete "W is X".
This code has unnecessary variables like "W is X" but they are about my question.
When I set any value to "W" between ":-" and ",append..." like "W is X" or "W = 3" or "W = 6" -- returns false.
Why can't I set any value to the W at that position in code but I CAN set "W = I" at the end of the code?
The query is append([1,2],[3],U). I want to get [2,1,3] at this code
at append([1,2,3],[4,5,6],U). I want to get [3,2,1,4,5,6].
append([1],[2,3],U). returns [1,2,3] , when I take the length of first list "1" (when first list only has one element) the code is perfect ; but when I take the length of first list >1 (when first list has more than one element) the code returns false.
In prolog, you can't assign variables, and then reassign them. Variables are unified and instantiated. Once instantiated, they cannot be re-instantiated inside of a clause. So if you have this inside of a clause:
W = X,
...
W = I,
Then first W is unified with X (=/2 is the unification operator). That means they either both now have the same value instantiated (if at least one was instantiated before), or their values will be forced to be identical instantiation later in the clause. When W = I is encountered later, then I must be unifiable with W or the clause will fail. If I has a specific value instantiated that is different from the instantiation of W (and, therefore, X), the clause will necessarily fail.
Let's see it happen (note I changed the name to my_append since Prolog rejects redefining the built-in predicate, append):
my_append([],U,U).
my_append([X|U1], U2, [W|U3]) :-
W = X,
my_append(U1, [X|U2], [I|Quyruk]),
write('I = '), write(I), write('; W = '), write(W), nl,
W = I,
U3 = Quyruk.
If we run:
?- my_append([1], [1,2], L).
I = 1; W = 1
L = [1,2,3]
yes
Life is good. Now let's try:
| ?- my_append([1,2], [3,4], L).
I = 2; W = 2 % This will be OK
I = 2; W = 1 % Uh oh... trouble
no
Prolog cannot unify 1 and 2, as I described above. They are two different values. So the predicate fails due to the W = I statement.
The solution is a little simpler than what you're attempting (although you are very close):
% Append empty to list gives the same list
my_append([], U, U).
% Append of [X|U1] and U2 is just append U1 and [X|U2]
% Or, thought of another way, you are moving elements of the first list
% over to the head of the second one at a time
my_append([X|U1], U2, U3) :-
my_append(U1, [X|U2], U3).
| ?- my_append([1,2,3],[4,5,6],L).
L = [3,2,1,4,5,6]
yes
The essence of this was in your code. Those other variables were just getting in the way (as C.B. pointed out). :)
The is operator is specifically used to compare or unify integers. W = I Is attempting to unify W with I (regardless of type). When you Unify W with X (assuming X is an integer), you have already unified W, and if X\=I (doesn't unify) you will return false.
In your example, W unifies with 1, but then you try to unify it with 2.
You have a lot of unnecessary variables, here is a very simple implementation of append:
append([],XS,XS).
append([X|XS],YS,[X|ZS]):- append(XS,YS,ZS).
To understand whats going wrong with your code, lets walk through it
append([],U,U).
append([X|U1],U2,[W|U3]) :- W is X , append(U1,[X|U2],[I|Quyruk]) , W = I, U3 = Quyruk .
?-append([1,2,3],[4,5,6],U).
I will use X1,X2,... to differentiate between different bindings.
In the first call, X unifies with 1, U1 unifies with [2,3] and U2 unifies with [4,5,6]. W and U3 are not yet bound before going into the horn clause.
W is X unifies W with 1.
append(U1,[X|U2],[I|Quyruk]) is calling append([2,3],[1,4,5,6],[I|Quyruk]). Already you should see that your recursion isn't working correctly.
I have this scenario wherein I get a linear equation in the Prolog query like below:
?- myquery( 3X + 5Y = 10, Result).
So my query has an equation 3X + 5Y = 10, which in general assumes the form AX + BY = C, where A=3, B=5 and C=10.
Now, in my prolog program, I am trying to define a predicate that can take in the expression mentioned in the query above. That is, I somehow want to get A, B and C values and also the operator involved (in the above case the plus operator) stored and then used on the logic that I define withing the program. I am wondering how this can be done.
To be more generic, the question is how do I identify the constants and the operator involved in an equation that is passed on through the goal/query?
SWI-Prolog has a constraint library clp(Q,R) that solve at symbolic level these equations:
[debug] ?- [library(clpq)].
% library(clpq) compiled into clpq 0,27 sec, 992 clauses
true.
?- {3 * X + 5 * Y = 10}.
{Y=2-3 rdiv 5*X}.
Eclipse will surely have something more advanced. These libraries aren't simple, tough...
Of interest to you, the Prolog syntax is used, as a host language, so the usual builtins could be applied for identify vars, constants, and the like.
The following transcript may prove illuminating:
32 ?- Term = (3*_X + 5*_Y = 10), functor(Term,F,A).
Term = 3*_G527+5*_G530=10
F = =
A = 2
33 ?- Term = (3*_X + 5*_Y = 10), arg(Arg,Term,Val).
Term = 3*_G459+5*_G462=10
Arg = 1
Val = 3*_G459+5*_G462 ; % user pressed ';' interactively
Term = 3*_G459+5*_G462=10
Arg = 2
Val = 10 ; % user pressed ';' interactively
No
35 ?- Term = (3*_X + 5*_Y = 10), arg(1,Term,Val1), functor(Val1,F1,A1),
arg(2,Val1,Val12).
Term = 3*_G693+5*_G696=10
Val1 = 3*_G693+5*_G696
F1 = +
A1 = 2
Val12 = 5*_G696
The last query reads: for Term as given, 1st arg of Term is Val1, the functor of Val1 is F1 with arity A1 (meaning, it has A1 args - subparts - itself), and 2nd arg of the term in Val1 is stored under Val12 name. To clarify, any symbolic data in Prolog is in the form of fff(aa,bb,cc,...) where fff is some name, called functor, and the "arguments" in that expression can be accessed through the arg call.
That means that the original expression (3*_X + 5*_Y = 10) is actually stored in Prolog as '='( '+'( '*'(3,_X), '*'(5,_Y)), 10). When you get to the atomic parts (functors with arity 0), you can check them further:
47 ?- arg(1,(3*X),V), functor(V,F,A), number(V).
X = _G441
V = 3
F = 3
A = 0
Yes
EDIT: to answer your other question (from the comments):
1 ?- (3*_X + 5*_Y = 10) = (A*X + B*Y = C).
A = 3
X = _G412
B = 5
Y = _G415
C = 10
Yes
If you insist on not writing out the multiplication sign * explicitly, you will have to represent your terms as strings, and to analyze that string. That would be a much more involved task.
EDIT: another thing to try is =.. predicate, called "Univ":
4 ?- (3*_X + 5*_Y = 10) =.. X.
X = [=, 3*_G454+5*_G457, 10]
Yes
5 ?- (3*_X + 5*_Y = 10) =.. X, X=[X1,X2,X3], X2 =.. Y.
X = [=, 3*_G545+5*_G548, 10]
X1 = =
X2 = 3*_G545+5*_G548
X3 = 10
Y = [+, 3*_G545, 5*_G548]
Yes
You can for example use term inspection predicates: arg/3, functor/3, var/1, (=..)/2 etc.
You might want to take a look at examples of symbolic differentiation implemented using term rewrite rules; they handle such expressions.
Here's a chapter (minus 1 page) from the book Clause and Effect that you might find useful:
Clause and Effect - Chapter Six: Term Rewriting
Another from The art of Prolog: advanced programming techniques
23 An equation solver
Programming in Prolog also has a section (7.11) on symbolic differentiation.