Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SciPy LowLevelCallable from Lambdify #201

Merged
merged 9 commits into from
Oct 29, 2017
Merged

SciPy LowLevelCallable from Lambdify #201

merged 9 commits into from
Oct 29, 2017

Conversation

isuruf
Copy link
Member

@isuruf isuruf commented Oct 19, 2017

cc @BlackTeaAndCoffee

This creates a LowLevelCallable that can be used by scipy integrate functions without the overhead of python.

@isuruf
Copy link
Member Author

isuruf commented Oct 19, 2017

A simple example,

In [1]: import symengine as se
   ...: import numpy as np
   ...: from scipy import integrate
   ...: args = t, x = se.symbols("t, x")
   ...: 
   ...: lmb = se.lambdify(args, [se.exp(-x*t)/t**5], as_scipy=True)
   ...: lmb2 = se.lambdify(args, [se.exp(-x*t)/t**5], as_scipy=False)
   ...: 

In [2]: %timeit integrate.nquad(lmb, [[1, np.inf],[0, np.inf]])
1.39 ms ± 1.87 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [3]: %timeit integrate.nquad(lmb2, [[1, np.inf],[0, np.inf]])
51.5 ms ± 425 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

cc @bjodah

@@ -4579,6 +4604,16 @@ cdef class LambdaDouble(_Lambdify):
cpdef unsafe_complex(self, double complex[::1] inp, double complex[::1] out, int inp_offset=0, int out_offset=0):
self.lambda_double_complex[0].call(&out[out_offset], &inp[inp_offset])

cpdef as_scipy_low_level_callable(self):
from scipy import LowLevelCallable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the import of LowLevelCallable needed here?

@@ -4592,8 +4627,18 @@ IF HAVE_SYMENGINE_LLVM:
cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=0, int out_offset=0):
self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])

cpdef as_scipy_low_level_callable(self):
from scipy import LowLevelCallable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

@bjodah
Copy link
Contributor

bjodah commented Oct 19, 2017

This is really exciting and impressive (as always). I haven't used scipy's LowLevelCallable myself yet (I have been meaning to look into it). Right now I'm quite busy, but I can take a closer look at this PR this weekend.


def create_low_level_callable(lambdify, *args):
from scipy import LowLevelCallable
class LambdifyLowLevelCallable(LowLevelCallable):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this class need to be closure? Or could it be defined in a try/except block around from scipy import LowLevelCallable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to add the initialization time of scipy to symengine. That's why this is done inside a function.

@bjodah
Copy link
Contributor

bjodah commented Oct 29, 2017

Looks good to me. Too bad the LowLevelCallable isn't used much in scipy at the moment (that might change though).

@isuruf isuruf merged commit a12f736 into symengine:master Oct 29, 2017
@isuruf
Copy link
Member Author

isuruf commented Oct 29, 2017

Thanks for the review

@isuruf isuruf deleted the scipy branch October 29, 2017 17:52
@certik
Copy link
Contributor

certik commented Nov 2, 2017

Very impressive. Thanks @isuruf !

@BlackTeaAndCoffee
Copy link

BlackTeaAndCoffee commented Feb 13, 2018

Hi above all, thank you for this awesome tool, it will almost definitly do what i need.
but i get the following error, when i run your simple code above.

Traceback (most recent call last):
  File "foo.py", line 6, in <module>
    lmb = se.lambdify(args, [se.exp(-x*t)/t**5], as_scipy=True)
TypeError: lambdify() got an unexpected keyword argument 'as_scipy'

i have

>>> import symengine
>>> symengine__version__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'symengine__version__' is not defined
>>> symengine.__version__
'0.3.0'
>>> 

Best wishes Mustafa

@isuruf
Copy link
Member Author

isuruf commented Feb 13, 2018

@BlackTeaAndCoffee, you'll have to use the latest version of symengine.py and symengine for this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants