GithubHelp home page GithubHelp logo

jni / llc-tools Goto Github PK

View Code? Open in Web Editor NEW
21.0 2.0 6.0 18 KB

Decorators to make it easier to write SciPy LowLevelCallables

License: BSD 3-Clause "New" or "Revised" License

Python 100.00%

llc-tools's Introduction

llc-tools

Decorators to make it easier to write SciPy LowLevelCallables

llc-tools's People

Contributors

grlee77 avatar jni avatar kne42 avatar pdn4kd avatar rgommers avatar trhallam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

llc-tools's Issues

Create documentation on ReadTheDocs

The two blog posts that motivated this library contain some useful references for documentation:

https://ilovesymposia.com/2017/03/12/scipys-new-lowlevelcallable-is-a-game-changer/

https://ilovesymposia.com/2017/03/15/prettier-lowlevelcallables-with-numba-jit-and-decorators/

Currently, llc-tools doesn't have any documentation. It would be good to put some on ReadTheDocs or GitHub Pages.

Other useful references:

https://docs.scipy.org/doc/scipy/reference/generated/scipy.LowLevelCallable.from_cython.html

https://docs.scipy.org/doc/scipy/reference/ccallback.html

Sample code on your blog not working

I followed your code on https://ilovesymposia.com/2017/03/15/prettier-lowlevelcallables-with-numba-jit-and-decorators/

import numba
from numba import cfunc, carray, jit
from numba.types import intc, CPointer, float64, intp, voidptr, uint8
from scipy import LowLevelCallable

def jit_filter_function(filter_function):
    """Decorator for use with scipy.ndimage.generic_filter."""
    jitted_function = numba.jit(filter_function, nopython=True)

    @cfunc(intc(CPointer(float64), intp, CPointer(float64), voidptr))
    def wrapped(values_ptr, len_values, result, data):
        values = carray(values_ptr, (len_values,), dtype=float64)
        result[0] = jitted_function(values)
        return 1
    return LowLevelCallable(wrapped.ctypes)

@jit_filter_function
def fmin(values):
    result = np.inf
    for v in values:
        if v < result:
            result = v

Encountered the following error

LoweringError: Caused By:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 238, in run
    stage()
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 644, in stage_nopython_backend
    self._backend(lowerfn, objectmode=False)
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 599, in _backend
    lowered = lowerfn()
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 586, in backend_nopython_mode
    self.flags)
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 882, in native_lowering_stage
    lower.lower()
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 135, in lower
    self.lower_normal_function(self.fndesc)
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 176, in lower_normal_function
    entry_block_tail = self.lower_function_body()
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 201, in lower_function_body
    self.lower_block(block)
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 216, in lower_block
    self.lower_inst(inst)
  File "/usr/local/Cellar/python/2.7.13_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/contextlib.py", line 35, in __exit__
    self.gen.throw(type, value, traceback)
  File "/usr/local/lib/python2.7/site-packages/numba/errors.py", line 265, in new_error_context
    six.reraise(type(newerr), newerr, sys.exc_info()[2])
  File "/usr/local/lib/python2.7/site-packages/numba/errors.py", line 259, in new_error_context
    yield
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 216, in lower_block
    self.lower_inst(inst)
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 305, in lower_inst
    return self.lower_setitem(inst.target, inst.index_var, inst.value, signature)
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 390, in lower_setitem
    signature.args[2])
  File "/usr/local/lib/python2.7/site-packages/numba/targets/base.py", line 648, in cast
    "Cannot cast %s to %s: %s" % (fromty, toty, val))
LoweringError: Cannot cast none to float64: %".117" = load i8*, i8** %"$0.10"
File "<ipython-input-52-1ddc111374d6>", line 13
[1] During: lowering "result[0] = $0.10" at <ipython-input-52-1ddc111374d6> (13)

Failed at nopython (nopython mode backend)
Cannot cast none to float64: %".117" = load i8*, i8** %"$0.10"
File "<ipython-input-52-1ddc111374d6>", line 13
[1] During: lowering "result[0] = $0.10" at <ipython-input-52-1ddc111374d6> (13)
LoweringErrorTraceback (most recent call last)
<ipython-input-52-1ddc111374d6> in <module>()
     15     return LowLevelCallable(wrapped.ctypes)
     16 
---> 17 @jit_filter_function
     18 def fmin(values):
     19     result = np.inf
<ipython-input-52-1ddc111374d6> in jit_filter_function(filter_function)
      8     jitted_function = numba.jit(filter_function, nopython=True)
      9 
---> 10     @cfunc(intc(CPointer(float64), intp, CPointer(float64), voidptr))
     11     def wrapped(values_ptr, len_values, result, data):
     12         values = carray(values_ptr, (len_values,), dtype=float64)
/usr/local/lib/python2.7/site-packages/numba/decorators.pyc in wrapper(func)
    251         if cache:
    252             res.enable_caching()
--> 253         res.compile()
    254         return res
    255 
/usr/local/lib/python2.7/site-packages/numba/ccallback.pyc in compile(self)
     65             cres = self._cache.load_overload(self._sig, self._targetdescr.target_context)
     66             if cres is None:
---> 67                 cres = self._compile_uncached()
     68                 self._cache.save_overload(self._sig, cres)
     69             else:
/usr/local/lib/python2.7/site-packages/numba/ccallback.pyc in _compile_uncached(self)
     78 
     79         # Compile native function
---> 80         cres = self._compiler.compile(sig.args, sig.return_type)
     81         assert not cres.objectmode  # disabled by compiler above
     82         fndesc = cres.fndesc
/usr/local/lib/python2.7/site-packages/numba/dispatcher.pyc in compile(self, args, return_type)
     78                                       impl,
     79                                       args=args, return_type=return_type,
---> 80                                       flags=flags, locals=self.locals)
     81         # Check typing error if object mode is used
     82         if cres.typing_error is not None and not flags.enable_pyobject:
/usr/local/lib/python2.7/site-packages/numba/compiler.pyc in compile_extra(typingctx, targetctx, func, args, return_type, flags, locals, library)
    761     pipeline = Pipeline(typingctx, targetctx, library,
    762                         args, return_type, flags, locals)
--> 763     return pipeline.compile_extra(func)
    764 
    765 
/usr/local/lib/python2.7/site-packages/numba/compiler.pyc in compile_extra(self, func)
    358         self.lifted = ()
    359         self.lifted_from = None
--> 360         return self._compile_bytecode()
    361 
    362     def compile_ir(self, func_ir, lifted=(), lifted_from=None):
/usr/local/lib/python2.7/site-packages/numba/compiler.pyc in _compile_bytecode(self)
    720         """
    721         assert self.func_ir is None
--> 722         return self._compile_core()
    723 
    724     def _compile_ir(self):
/usr/local/lib/python2.7/site-packages/numba/compiler.pyc in _compile_core(self)
    707 
    708         pm.finalize()
--> 709         res = pm.run(self.status)
    710         if res is not None:
    711             # Early pipeline completion
/usr/local/lib/python2.7/site-packages/numba/compiler.pyc in run(self, status)
    244                     # No more fallback pipelines?
    245                     if is_final_pipeline:
--> 246                         raise patched_exception
    247                     # Go to next fallback pipeline
    248                     else:
LoweringError: Caused By:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 238, in run
    stage()
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 644, in stage_nopython_backend
    self._backend(lowerfn, objectmode=False)
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 599, in _backend
    lowered = lowerfn()
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 586, in backend_nopython_mode
    self.flags)
  File "/usr/local/lib/python2.7/site-packages/numba/compiler.py", line 882, in native_lowering_stage
    lower.lower()
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 135, in lower
    self.lower_normal_function(self.fndesc)
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 176, in lower_normal_function
    entry_block_tail = self.lower_function_body()
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 201, in lower_function_body
    self.lower_block(block)
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 216, in lower_block
    self.lower_inst(inst)
  File "/usr/local/Cellar/python/2.7.13_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/contextlib.py", line 35, in __exit__
    self.gen.throw(type, value, traceback)
  File "/usr/local/lib/python2.7/site-packages/numba/errors.py", line 265, in new_error_context
    six.reraise(type(newerr), newerr, sys.exc_info()[2])
  File "/usr/local/lib/python2.7/site-packages/numba/errors.py", line 259, in new_error_context
    yield
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 216, in lower_block
    self.lower_inst(inst)
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 305, in lower_inst
    return self.lower_setitem(inst.target, inst.index_var, inst.value, signature)
  File "/usr/local/lib/python2.7/site-packages/numba/lowering.py", line 390, in lower_setitem
    signature.args[2])
  File "/usr/local/lib/python2.7/site-packages/numba/targets/base.py", line 648, in cast
    "Cannot cast %s to %s: %s" % (fromty, toty, val))
LoweringError: Cannot cast none to float64: %".117" = load i8*, i8** %"$0.10"
File "<ipython-input-52-1ddc111374d6>", line 13
[1] During: lowering "result[0] = $0.10" at <ipython-input-52-1ddc111374d6> (13)

Failed at nopython (nopython mode backend)
Cannot cast none to float64: %".117" = load i8*, i8** %"$0.10"
File "<ipython-input-52-1ddc111374d6>", line 13
[1] During: lowering "result[0] = $0.10" at <ipython-input-52-1ddc111374d6> (13)

ValueError: Invalid scipy.LowLevelCallable signature on Windows

Thanks a lot for posting these recipes. I am trying to get your jit_filter_function decorator to work, but I get the same error as in one of the comments on your blog post:

ValueError: Invalid scipy.LowLevelCallable signature "long (double *, longlong, double *, void *)". Expected one of: ['int (double *, intptr_t, double *, void *)', 'int (double *, npy_intp, double *, void *)', 'int (double *, long long, double *, void *)']

This is with Python 3.6 on Windows and

>>> numba.__version__
'0.35.0+10.g143f70e'
>>> scipy.__version__
'0.19.1'

I have tried to modify this line

@cfunc(intc(CPointer(float64), intp, CPointer(float64), voidptr))

in any way I could think of, but am unable to produce a signature that scipy.LowLevelCallable likes. What am I missing?

TypingError: got an unexpected keyword argument 'ddof' using jit_filter_function on Windows

Hello! First I'd like to say this decorator has been great to work with, really appreciate jit_filter_function. I'm running into an error that pops up when adding the 'ddof' argument to np.nanstd within the filter function.

This code runs without flaw

@jit_filter_function
def fstd(values):
    values[values == 0] = np.nan
    result = np.nanstd(values)
    return result
std = generic_filter(<2d_numpy_array>, fstd, footprint=np.ones((5, 5)))

However, adding the ddof argument like this

@jit_filter_function
def fstd(values):
    values[values == 0] = np.nan
    result = np.nanstd(values, ddof=1)
    return result
std = generic_filter(<2d_numpy_array>, fstd, footprint=np.ones((5, 5)))

Throws this:

Traceback (most recent call last):
  File "C:/Users/jbrown/AppData/Roaming/JetBrains/PyCharmCE2021.1/scratches/hr_class_master.py", line 301, in <module>
    main()
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\memory_profiler.py", line 1186, in wrapper
    val = prof(func)(*args, **kwargs)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\memory_profiler.py", line 759, in f
    return func(*args, **kwds)
  File "C:/Users/jbrown/AppData/Roaming/JetBrains/PyCharmCE2021.1/scratches/hr_class_master.py", line 149, in main
    def fstd(values):
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\llc\ndimage.py", line 48, in jit_filter_function
    def wrapped(values_ptr, len_values, result, data):
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\decorators.py", line 282, in wrapper
    res.compile()
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler_lock.py", line 35, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\ccallback.py", line 67, in compile
    cres = self._compile_uncached()
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\ccallback.py", line 81, in _compile_uncached
    return self._compiler.compile(sig.args, sig.return_type)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\dispatcher.py", line 129, in compile
    raise retval
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\dispatcher.py", line 139, in _compile_cached
    retval = self._compile_core(args, return_type)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\dispatcher.py", line 152, in _compile_core
    cres = compiler.compile_extra(self.targetdescr.typing_context,
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler.py", line 716, in compile_extra
    return pipeline.compile_extra(func)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler.py", line 452, in compile_extra
    return self._compile_bytecode()
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler.py", line 520, in _compile_bytecode
    return self._compile_core()
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler.py", line 499, in _compile_core
    raise e
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler.py", line 486, in _compile_core
    pm.run(self.state)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler_machinery.py", line 368, in run
    raise patched_exception
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler_machinery.py", line 356, in run
    self._runPass(idx, pass_inst, state)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler_lock.py", line 35, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler_machinery.py", line 311, in _runPass
    mutated |= check(pss.run_pass, internal_state)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\compiler_machinery.py", line 273, in check
    mangled = func(compiler_state)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\typed_passes.py", line 105, in run_pass
    typemap, return_type, calltypes, errs = type_inference_stage(
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\typed_passes.py", line 83, in type_inference_stage
    errs = infer.propagate(raise_errors=raise_errors)
  File "C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\typeinfer.py", line 1086, in propagate
    raise errors[0]
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function nanstd at 0x000001BA5B414F70>) found for signature:
 
 >>> nanstd(array(float64, 1d, C), ddof=Literal[int](1))
 
There are 2 candidate implementations:
  - Of which 2 did not match due to:
  Overload in function 'np_nanstd': File: numba\np\arraymath.py: Line 1231.
    With argument(s): '(array(float64, 1d, C), ddof=int64)':
   Rejected as the implementation raised a specific error:
     TypingError: got an unexpected keyword argument 'ddof'
  raised from C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\numba\core\typing\templates.py:791

During: resolving callee type: Function(<function nanstd at 0x000001BA5B414F70>)
During: typing of call at C:/Users/jbrown/AppData/Roaming/JetBrains/PyCharmCE2021.1/scratches/hr_class_master.py (151)


File "hr_class_master.py", line 151:
    def fstd(values):
        <source elided>
        values[values == 0] = np.nan
        result = np.nanstd(values, ddof=1)
        ^

During: resolving callee type: type(CPUDispatcher(<function main.<locals>.fstd at 0x000001BA0DBF04C0>))
During: typing of call at C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\llc\ndimage.py (50)

During: resolving callee type: type(CPUDispatcher(<function main.<locals>.fstd at 0x000001BA0DBF04C0>))
During: typing of call at C:\Users\jbrown\AppData\Local\Programs\Python\Python38\lib\site-packages\llc\ndimage.py (50)


File "..\..\..\..\Local\Programs\Python\Python38\lib\site-packages\llc\ndimage.py", line 50:
    def wrapped(values_ptr, len_values, result, data):
        <source elided>
        values = carray(values_ptr, (len_values,), dtype=float64)
        result[0] = jitted_function(values)
        ^

Is this functionality to be added, or error with the code itself? I'm using Python 3.8 on Windows

Pass arguments to the LowLevelCallable

@cfunc(intc(CPointer(float64), intp, CPointer(float64), voidptr))
def function(values_ptr, len_values, result, data):
  ...
  weights = carray(data, (1,), double)[0]
  ...

weights = [0.6, 0.8, 0.4]
seq = ctypes.c_double * len(weights)
arr = seq(*weights)
ptr = ctypes.cast(ctypes.pointer(arr), ctypes.c_void_p)
ndi.generic_filter(image, LowLevelCallable(function.ctypes, ptr), footprint=footprint)

Source:
scipy doc

Improve our testing

In #11, @trhallam added some basic tests (๐ŸŽ‰!). We can be more elaborate:

  • ensure that running the function with a lowlevelcallable and a Python callable (the un-decorated function) gives the same results
  • ensure that lowlevelcallable is faster than pure python
  • ensure that providing input array as output gives the desired results (not sure yet whether this is technically possible from the SciPy side).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.