mathnet / mathnet-symbolics

Math.NET Symbolics
http://symbolics.mathdotnet.com
MIT License
341 stars 66 forks source link

Expression.Zero.Equals() Bug? #82

Closed mpp closed 3 years ago

mpp commented 4 years ago

Hi, I just updated the nuget package reference from 0.20.0 to 0.21.0 and I'm experiencing a different behavior when I compare two expressions.

As example I need to compare B/2 + H and 0.5B + H and verify that they're equivalent.

What I'm used to do is:

var left = "B/2 + H";
var right = "0.5B + H";
Expression e = Infix.ParseOrThrow(left + "-(" + right + ")");
e = Algebraic.Expand(e);
// With the old version I could do this
var areEquivalent = Infix.Format(expression).Trim() == "0";

But with the new version Infix.Format(expression).Trim() returns 0*B.

Is there a better way to do it? I tried Expression.Zero.Equals(e) but it return false. Is it the expected behavior?

Thanks

cdrnet commented 3 years ago

Yes, this is an aspect which has changed multiple times unfortunately.

Originally the library was pure in the sense that it only supported integers (or rational numbers as fractions of two integers), symbols and a set of operators and functions. For convenience, the parser supported the decimal point notation as shortcut, so "0.5" was parsed into a rational number "1/2".

However, the notation "0.5" actually has a different meaning to "1/2". I understand "0.5" as approximation of a real number (we cannot actually fully represent real numbers). Hence "0.5" - "0.5" is not actually zero "0", but rather an approximation of zero "0.0". So I had added explicit support for approximation terms in expressions.

In the implementation of approximations up to 0.21, terms like "0.0 x" were intentionally not reduced to "0.0". That's what you noticed in your case as well, with the "0 B" term. Since this property also breaks many algebraic algorithms, I've decided to change this in v0.22 as compromise such that "0.0 * x" now indeed does simplify to "0.0" (but not to zero/"0"). However, one aspect which was also confusing is that approximations with a zero decimal part were rendered the same way as integers, so this was changed as well in v0.22 where they now always have a decimal point.

All in all, in v0.22 instead of "0 B" you should now get "0.0" (provided you write "0.5 B", not "0.5B"). Note that this "0.0" is of course not equal to "0".

Btw, in C# it's a bit easier to use SymbolicExpression, e.g.

SymbolicExpression.Parse("B/2 + H - (0.5*B + H)").Expand().RealNumberValue // 0.0 - check if .Type is really RealNumber first
mpp commented 3 years ago

Thank you for the exhaustive response! I'll update and I'll also try that SymbolicExpression, thanks again!