symengine / SymEngine.jl

Julia wrappers of SymEngine
MIT License
192 stars 43 forks source link

Can't create Add (sums) manually #231

Closed VisualCoder123 closed 2 years ago

VisualCoder123 commented 3 years ago

Hi!

For benchmarking purposes I have this code:

function trig_function(n::Int)    
    @vars x y
    operands = [sin(i*x) * cos(i * y) for i in 1:n]  
    return +(operands...)
end

Unfortunately, this code runs too long for my tasks (1.63 sec for n = 10000).

While working with symengine in Python I constructed the sum by hand using the Add class.

def trig_function(n):
    list_of_exprs = [None] * (n + 1)
    x, y = se.symbols("x y")

    for i in range(n + 1):
        list_of_exprs[i] = se.sin(i * x) * se.cos(i * y)

    res = se.Add(*list_of_exprs)
    return res

This function calculates the result in 0.062 sec (26 times faster).

If I will use "traditional" approach to calculating sum in python:

def trig_function_slow(n):
    res = 0
    x,y = se.symbols("x y")
    for i in range(n + 1):
        res += se.sin(i * x) * se.cos(i * y)

    return res

the result will calculate in 2.486 sec (1.5 times slower than Julia version).

I am not sure, but I think that the reason of achieved results is the following. When I'm using return +(operands...), it sums operands one by one (reducing operands) which means creation of new objects and garbage collection (just like in the slow python version). But when I generate Add object manually I create a sum object without generating intermediate objects.

Is there any way to create Add object and paste array of terms manually like I did it in Symengine.py?

isuruf commented 3 years ago

Currently there's no way to do it in Julia, because the C++ function is not wrapped in C.

There's a C++ function at https://github.com/symengine/symengine/blob/master/symengine/add.h#L161-L171, but there's no equivalent C function at https://github.com/symengine/symengine/blob/master/symengine/cwrapper.cpp#L525.

Can you open an issue in https://github.com/symengine/symengine?

VisualCoder123 commented 3 years ago

Currently there's no way to do it in Julia, because the C++ function is not wrapped in C.

There's a C++ function at https://github.com/symengine/symengine/blob/master/symengine/add.h#L161-L171, but there's no equivalent C function at https://github.com/symengine/symengine/blob/master/symengine/cwrapper.cpp#L525.

Can you open an issue in https://github.com/symengine/symengine?

Thank you for the answer! I created an issue.

isuruf commented 2 years ago

@VisualCoder123 or @jverzani, what's the signature of the method that julia dispatches a + b + c to? There's a basic_add_vec function in 0.8 that we can use.

VisualCoder123 commented 2 years ago
using SymEngine

@vars a b c
@which a + b + c
+(a, b, c, xs...) in Base at operators.jl:560

which leads to https://github.com/JuliaLang/julia/blob/eb0ab3c406bdbb13457935d1f5d3b0f90a91e570/base/operators.jl#L650 +(a, b, c, xs...) in Base at operators.jl:560, i.e. (:+)(a, b, c, xs...)

isuruf commented 2 years ago

Fixed in https://github.com/symengine/SymEngine.jl/pull/235