As is often the case in symbolic computing a seemingly innocent question like "is this expression equivalent to that one" will in full generality be unsolvable. Even determining that two distinct equations have the same left hand sides and the same right hand sides is undecidable due to Richardson's theorem:
https://en.wikipedia.org/wiki/Richardson%27s_theorem
Of course there are many cases where this problem is decidable but as is usually the case in symbolic computing there needs to be some restriction on the problem space. In particular we need either or both of:
- We need to define some class of possible equations or expressions that we want to be able to handle.
- We need to define what sort of manipulation is allowable to transform one equation into an another.
In your two examples both equations are polynomial equations involving two variables with rational or float coefficients so we could take that as the class of allowable equations. The floats are a potential obstacle but I will presume that converting them to the most likely rational number with nsimplify
will be acceptable in your use case. In that case our equations are polynomial equations involving multiple variables but with rational coefficients.
Now what kind of manipulation is allowed? Only certain manipulations of a polynomial equation would necessarily give another polynomial equation:
- Adding or subtracting polynomials from both sides.
- Multiplying both sides by either a rational number or a polynomial.
- Raising both sides to an integer power.
An important equation her arises:
Would you consider (x - 1)**2 = 0
to be equivalent to (x - 1) = 0
?
In some contexts it is important to distinguish the multiplicity of factors/roots of polynomials but in others it is not.
Another consideration is whether you want the equations to be equivalent modulo some assumptions for example we might say that (x - 1)**2 = y**2
is equivalent to x - 1 = y
if say y
was constrained to be nonnegative. There are many possible assumptions that you could impose so I won't try to consider those.
Create the equations (by parsing strings or anything else) and convert the floats to rational:
In [3]: a = Eq(y, x**2 + 0.5)
In [4]: b = Eq(2*y, 2*x**2 + 1)
In [5]: a
Out[5]:
2
y = x + 0.5
In [6]: b
Out[6]:
2
2⋅y = 2⋅x + 1
In [7]: a = nsimplify(a) # float to rational
In [8]: a
Out[8]:
2 1
y = x + ─
2
Now convert to expressions by subtracting the sides:
In [9]: a = a.lhs - a.rhs
In [10]: b = b.lhs - b.rhs
In [11]: a
Out[11]:
2 1
- x + y - ─
2
In [12]: b
Out[12]:
2
- 2⋅x + 2⋅y - 1
This last step assumed that you didn't mind if both equations had say a + 1
on each side that would have cancelled. Maybe you do care about that or maybe you don't: it depends on the situation. Here is an example of when you might care (if this equation was allowable in your problem space):
In [19]: eq = Eq(x + 1/x, 1/x)
In [20]: eq
Out[20]:
1 1
x + ─ = ─
x x
In [21]: solve(eq)
Out[21]: []
In [22]: eq.lhs - eq.rhs
Out[22]: x
In [23]: solve(eq.lhs - eq.rhs)
Out[23]: [0]
At this stage it seems that for the equations to be equivalent you would allow only that one is a multiple of the other but what are we allowed to multiply by? I'm going to presume that the only allowable difference here is a factor that is an explicit rational number. In that case we can make both polynomials canonical by making them monic:
In [16]: monic(a)
Out[16]:
2 1
x - y + ─
2
In [17]: monic(b)
Out[17]:
2 1
x - y + ─
2
In [18]: monic(a) == monic(b)
Out[18]: True
More complex notions of equivalence could be defined than this but it is sufficient for the examples given. You can generalise the problem by generalising the constraints on the problem but there can be no algorithmic answer to the problem without some constraints.