Hi Jason,

I'm approaching this from the perspective that this is a bug in
cse/lambdify and that you want to identify which part of a large
expression tree triggers the bug. Since evaluating the whole
expression is slow I would start by testing smaller subexpressions and
work up from there. You can get something like that with:

from sympy.utilities.iterables import postorder_traversal

def cse_compare(expr, syms, vals):
    result = lambdify(syms, expr)(*vals)

    syms_all, vals_all = list(syms), list(vals)
    reps, [reduced_expr] = cse(expr)
    for csesym, cseexpr in reps:
        val = lambdify(syms_all, cseexpr)(*vals_all)
        syms_all.append(csesym)
        vals_all.append(val)
    result_cse = lambdify(syms_all, reduced_expr)(*vals_all)

    return abs(result - result_cse) / abs(result)

def cse_compare_bottom_up(expr):
    syms = list(expr.free_symbols)
    vals = list(np.random.random(len(syms)))

    def subexprs():
        seen = set()
        for e in postorder_traversal(expr):
            if e not in seen:
                yield e
                seen.add(e)

    # possibly better:
    #exprs = sorted(set(postorder_traversal(expr)), key=lambda e: e.count_ops())
    exprs = subexprs()

    for subexpr in exprs:
        print()
        print(subexpr)
        print(cse_compare(expr, syms, vals))

test_expr = (sin(x+1) + 2*cos(x-3)).expand(trig=True)
cse_compare_bottom_up(test_expr)


Oscar

On Fri, 23 Oct 2020 at 07:59, Jason Moore <[email protected]> wrote:
>
> Oscar,
>
> Yes I can try evaluating in different orders. That's an interesting idea.
>
> I also may be breaking lambdify with too many arguments. I can store the 
> numerical results of each subexpression in a dictionary, then identify the 
> minimal set of variables in each subsequent subexpression, and only lambdify 
> with that very much smaller set of arguments. Maybe that will fix it.
>
> I'll try both.
>
> Jason
> moorepants.info
> +01 530-601-9791
>
>
> On Fri, Oct 23, 2020 at 8:56 AM Oscar Gustafsson <[email protected]> 
> wrote:
>>
>> Yes, you are right that the email is about a different topic. However, it 
>> can be worth noting that evaluating floating-point expressions in different 
>> order, which is basically what you do using cse:s, can give different 
>> results due to the floating-point quantization/rounding happening at 
>> different places. Hence, it is not always obvious to tell if the results are 
>> "identical". If you are unlucky, the error propagation can be quite 
>> disastrous at times, but you are probably correct in that there is something 
>> else that is the primary issue here.
>>
>> BR Oscar
>>
>> Den tors 22 okt. 2020 kl 18:57 skrev Jason Moore <[email protected]>:
>>>
>>> As far as I understand the results should match to machine precision.
>>>
>>> We are able to match these kinds of models executed on different platforms 
>>> using different formulation techniques to machine precision (e-14 or more). 
>>> In fact, we use this to be able to verify that two independent modelers 
>>> have created the same model.
>>>
>>> The fact that my model can't get the same results with two numerical 
>>> evaluations of sympy code is concerning.
>>>
>>> My question in this email though, is how to improve the comparison code so 
>>> that it doesn't crash for large expressions.
>>>
>>> Jason
>>> moorepants.info
>>> +01 530-601-9791
>>>
>>>
>>> On Thu, Oct 22, 2020 at 6:49 PM Oscar Gustafsson 
>>> <[email protected]> wrote:
>>>>
>>>> How much do they differ? I checked the issue and the latest result wasn't 
>>>> that bad, although probably too much to blame floating-point errors. 
>>>> However, if you push the numerical range into e.g. denormalized numbers I 
>>>> guess it can simply be that. Not very likely though. Is it still that type 
>>>> of numerical errors?
>>>>
>>>> BR Oscar
>>>>
>>>> Den tors 22 okt. 2020 09:37Jason Moore <[email protected]> skrev:
>>>>>
>>>>> Howdy,
>>>>>
>>>>> I'm trying to track down a bug in this PR:
>>>>>
>>>>> https://github.com/pydy/pydy/pull/122
>>>>>
>>>>> I have quite large SymPy expressions which I evaluate with floating point 
>>>>> numbers. I also cse those expressions and evaluate those with the same 
>>>>> floating point numbers. I'm getting discrepancies in the results. I'd 
>>>>> like to eliminate the possibility that the cse'd expressions are 
>>>>> different from the original expression. I wrote this naive function to 
>>>>> make the comparison:
>>>>>
>>>>> def compare_cse(expr):
>>>>>
>>>>>     args = list(expr.free_symbols)
>>>>>     args.remove(TIME)
>>>>>     args += me.find_dynamicsymbols(expr)
>>>>>     args = list(sm.ordered(args))
>>>>>     vals = list(np.random.random(len(args)))
>>>>>
>>>>>     eval_expr = sm.lambdify(args, expr)
>>>>>     res = eval_expr(*vals)
>>>>>
>>>>>     replacements, reduced_expr = sm.cse(expr)
>>>>>     for repl in replacements:
>>>>>         var = repl[0]
>>>>>         sub_expr = repl[1]
>>>>>         eval_sub_expr = sm.lambdify(args, sub_expr)
>>>>>         vals.append(eval_sub_expr(*vals))
>>>>>         args.append(var)
>>>>>     eval_reduced_expr = sm.lambdify(args, reduced_expr[0])
>>>>>     cse_res = eval_reduced_expr(*vals)
>>>>>
>>>>>     np.testing.assert_allclose(res, cse_res)
>>>>>
>>>>> This seems to work for small expressions, but for the large expressions 
>>>>> run this actually kills my Python interpreter after some minutes.
>>>>>
>>>>> Is there a better way to write this? I need some way to verify that 
>>>>> numerical evaluation of a cse'd expression gives the same result as 
>>>>> numerical evaluation of the expression that can actually complete in a 
>>>>> reasonable amount of time.
>>>>>
>>>>> Jason
>>>>> moorepants.info
>>>>> +01 530-601-9791
>>>>>
>>>>> --
>>>>> You received this message because you are subscribed to the Google Groups 
>>>>> "sympy" group.
>>>>> To unsubscribe from this group and stop receiving emails from it, send an 
>>>>> email to [email protected].
>>>>> To view this discussion on the web visit 
>>>>> https://groups.google.com/d/msgid/sympy/CAP7f1Aivs53AcwyaoyO5%2Bzkn%2BPrX3TfoJJ5X85qQNZ6JRbo5JQ%40mail.gmail.com.
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google Groups 
>>>> "sympy" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send an 
>>>> email to [email protected].
>>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/sympy/CAFjzj-LQNBFoF7Q4Rb%2BZG3J35-Et9b__SED-DMJvwUYqyKYADQ%40mail.gmail.com.
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups 
>>> "sympy" group.
>>> To unsubscribe from this group and stop receiving emails from it, send an 
>>> email to [email protected].
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/sympy/CAP7f1AgdkaC0D69s_ohka_AjDFvKCD%2BMoVKyFhs0Vn2b_DtFkw%40mail.gmail.com.
>>
>> --
>> You received this message because you are subscribed to the Google Groups 
>> "sympy" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected].
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/sympy/CAFjzj-LFUSgmQ90Uok2LxKSTZ-bJKysCy%2BGqvs1wYtDErUAZNA%40mail.gmail.com.
>
> --
> You received this message because you are subscribed to the Google Groups 
> "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sympy/CAP7f1Ai1UbiR6vLZs7_PTmY2WOk-VpsqYTSsTm4KUi6e9Y78qQ%40mail.gmail.com.

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sympy/CAHVvXxRPevyn7SOROy04jSTe2hMkQbhkQafYBTTDMDYo18dTRQ%40mail.gmail.com.

Reply via email to