0
votes

I want to define facts which are true both ways (They all have an arity of 2). I had success with a fact expressing the relationship "opposite" this way:

oppositeDeclare(plus, minus).

opposite(X, Y) :- oppositeDeclare(Y, X).
opposite(X, Y) :- oppositeDeclare(X, Y).

I'm trying to make a simple equation solver, and I would also like to define that if A=B then B=A. I can't just write:

equal(A, B):-equal(B,A).

because I get out of local stack error. However I can't do the same as I did with the "opposite" fact because "equal" needs to work based on the some rules. ("opposite" got it's input from facts only).

Is there a way I can avoid defining all the rules for "equal" twice?

Edit:

I only want to declare simple mathematical facts to see if I can use Prolog to solve other more complicated tasks where I don't know the mechanism for the solution only simple facts.

So far I have used equal/2 to define things like: if A=B+C, then C=A-B. I want to define equal/2 two ways so that I don't have to define if B+C=A, then A-B=C. Ideally after the new rule it could solve an equation for c like this: a=(b+c)/d -> b+c=a/d -> c=(a/d)-b.

The reason I can't use swap is because I have recursive rules for equal/2.

Bear in mind that it will not always work even for simple equations, because not all necessary facts are defined.

Here's the current program with a query:

5 ?- equal(v, X).
X = opr(s, per, t) 

% operators: per, times, plus, minus
% equation(LHS, RHS): used to declare physics equations
% equal(LHS, RHS): checks equality in a query

equation(s, opr(v, times, t)). % s=v*t
equation(a, opr(opr(b, plus, c), per, d)). %  a=(b+c)/d

oppositeDeclare(plus, minus).
oppositeDeclare(per, times).

opposite(X, Y) :- oppositeDeclare(Y, X).
opposite(X, Y) :- oppositeDeclare(X, Y).

equal(R, opr(A, O, B)) :- equation(R, opr(A, O, B)).       
% if there's an equation R=A O B , then R = A O B, where O is an operator (+-*/)

equal(A, opr(R, OY, B)) :- equal(R, opr(A, OX, B)), opposite(OY, OX). 
%declaring in one go: if R=A/B then A=R*B, if R=A-B then A=R+B, if R=A+B then A=R-B, if R=A-B then A=R+B
1
You can - equally - apply the method you used for opposite/2 for equal/2 too. Often, some form of normalization is done first, though.false
As @false is saying, try making your facts different than your rules, as you did for opposite/2. For example, facts equal_item(a, b). equal_item(a, c). and then rule equals(A, B) :- equal_item(A, B) ; equal_item(B, A). The rule equal(A, B) :- equal(B, A). is circular logic and infinitely recursive.lurker

1 Answers

1
votes

I am not sure I understand you correctly, but aren't you after this simple code?

equal(X, X).

Could you please show some sample input and output that you would like to achieve by using equal/2?

And about opposites, I would write this that way:

oppositeDeclare(plus, minus).
oppositeDeclare(good, evil).
oppositeDeclare(windows, linux).

swap(P, X, Y) :-  permutation([X,Y], [X1,Y1]), call(P, X1, Y1).

opposite(X, Y) :- swap(oppositeDeclare, X, Y).

Anytime you would like to use predicate with arity 2 and try swapping arguments, you can use swap/3 in a way presented above.