Search code examples
matlabsymbolic-math

Why is isequaln(f, simplify(f)) false?


I have a function f that is defined as:

syms c a t
f = symfun(c + t - (2*(t - 2^(1/2)*(a*t)^(1/2))*(a - t/2))/(2*a - t), [c a t])

However, checking for equality with the simplified version yields:

isequaln(f, simplify(f))

ans =

     0

Is simplify not expected to return an exact equivalent of the original function?


Solution

  • The problem with isequaln

    The sym/isequaln is probably not the appropriate function to use to test the equality. From the help for sym/isequaln:

    isequaln(A,B) returns true iff A and B are identical treating NaNs as equal.

    As @Benoit_11 alludes to, the documentation is not entirely clear, but, like it's numeric equivalent, the function appears to be testing for equality, not identity (despite the unfortunate use of the word "identical"). The simplified function is an identity for the unsimplified function, but it is not an equivalence. As per the documentation, sym/isequaln may take into account things like assumptions and possibly simple relations, but it doesn't perform a transformations and simplifications internally. This is almost certainly because simplification is a computationally costly process, so it was likely a design decision to only include a few well-defined (but not well-documented) tests.

    A possible solution with pitfalls

    So, how can you proceed? In addition to sym/isequaln, the Symbolic Math toolbox includes isAlways to test equalities and and inequalities a bit more rigorously:

    syms c a t
    f = symfun(c + t - (2*(t - 2^(1/2)*(a*t)^(1/2))*(a - t/2))/(2*a - t), [c a t])
    g = simplify(f)
    isAlways(f==g)
    

    However, in R2014b this returns false and the following warning:

    Warning: Cannot prove 'c + t - ((2*t - 2*2^(1/2)*(a*t)^(1/2))*(a - t/2))/(2*a - t) == c +
    2^(1/2)*(a*t)^(1/2)'. 
    > In /Applications/MATLAB_R2014b.app/toolbox/symbolic/symbolic/symengine.p>symengine at 56
      In sym.isAlways at 38
    

    You should be aware that symbolic variables are assumed complex by default and that isAlways is trying to prove this relation for all possible combinations of complex values of c, a, and t. Simplification is also an ill-defined process – from the documentation for simplify:

    Simplification of mathematical expression is not a clearly defined subject. There is no universal idea as to which form of an expression is simplest. The form of a mathematical expression that is simplest for one problem might be complicated or even unsuitable for another problem.

    If you look closely at your original equation, you'll see that it contains a singularity that has been simplified away. In R2014b, evaluating g(1,1,2) returns 3, but evaluating f(1,1,2) returns:

    Error using mupadmex
    Error in MuPAD command: Division by zero. [_power]
      Evaluating: _symans_32_15992
    
    ...
    

    Using assumptions

    If you know something about your symbolic variables, you may be able to avoid this by applying assumptions, e.g.

    syms c a t
    f = symfun(c + t - (2*(t - 2^(1/2)*(a*t)^(1/2))*(a - t/2))/(2*a - t), [c a t])
    g = simplify(f)
    assume(t>2*a)
    isAlways(f==g)
    

    which now returns true. By the way, using @Benoit_11's example, syms a b; isAlways((a+b)^2==a^2+2*a*b+b^2) also returns true directly.