numbox 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of numbox might be problematic. Click here for more details.

numbox/core/proxy.py ADDED
@@ -0,0 +1,87 @@
1
+ import inspect
2
+ from llvmlite import ir # noqa: F401
3
+ from numba import njit
4
+ from numba.core import cgutils # noqa: F401
5
+ from numba.core.typing.templates import Signature
6
+ from numba.extending import intrinsic # noqa: F401
7
+ from types import FunctionType as PyFunctionType
8
+ from typing import List, Optional, Tuple
9
+
10
+
11
+ def make_proxy_name(name):
12
+ return f'__{name}'
13
+
14
+
15
+ def make_params_strings(func):
16
+ func_params = inspect.signature(func).parameters
17
+ func_params_str = ', '.join(
18
+ [k if v.default == inspect._empty else f'{k}={v.default}' for k, v in func_params.items()]
19
+ )
20
+ func_names_params_str = ', '.join(func_params.keys())
21
+ return func_params_str, func_names_params_str
22
+
23
+
24
+ def proxy(sig, jit_options: Optional[dict] = None):
25
+ """ Create a proxy for the decorated function `func` with the given signature(s) `sig`.
26
+
27
+ The original function `func` will be eagerly JIT-compiled with the given signature(s).
28
+ A proxy with the name `func_proxy_name` will be created to call `func` in the LLVM scope.
29
+ The original function's variable will be bound to the proxy, i.e., calling the decorated
30
+ function will call the proxy.
31
+
32
+ The proxy is a JIT-compiled wrap that invokes the intrinsic that *declares* the `func`
33
+ and calls it with the original arguments. Declaration instructions are relatively cheap
34
+ to statically link into (potential) caller's LLVM code, which is the main motivation behind
35
+ this decorator.
36
+
37
+ Machine code for `func` can be cached when so specified in `jit_options`, in which case its
38
+ JIT-compilation will load the `func` into the LLVM scope. Caching option is the other major
39
+ motivation for this decorator, without the need to cache one can avoid static linking
40
+ of the callee's LLVM code into the caller's by simply ignoring the former.
41
+
42
+ In case when more than one signature is provided as the `sig` parameter, it is assumed
43
+ that the first signature is the 'main' one while the other ones are supplied to
44
+ allow for the `Omitted` types with default values for (some of) the parameters.
45
+
46
+ See tests for some examples of the use cases.
47
+ """
48
+ main_sig = isinstance(sig, Signature) and sig or isinstance(sig, (List, Tuple)) and sig[0]
49
+ jit_options = isinstance(jit_options, dict) and jit_options or {}
50
+ jit_opts = jit_options.copy()
51
+ jit_opts.update(jit_opts, inline='always')
52
+
53
+ def wrap(func):
54
+ assert isinstance(func, PyFunctionType)
55
+ func_jit = njit(sig, **jit_options)(func)
56
+ llvm_cfunc_wrapper_name = func_jit.get_compile_result(main_sig).fndesc.llvm_cfunc_wrapper_name
57
+ func_args_str, func_names_args_str = make_params_strings(func)
58
+ func_proxy_name = make_proxy_name(func.__name__)
59
+ code_txt = f"""
60
+ @intrinsic
61
+ def _{func_proxy_name}(typingctx, {func_names_args_str}):
62
+ def codegen(context, builder, signature, args):
63
+ func_ty_ll = ir.FunctionType(
64
+ context.get_data_type(main_sig.return_type),
65
+ [context.get_data_type(arg) for arg in main_sig.args]
66
+ )
67
+ f = cgutils.get_or_insert_function(builder.module, func_ty_ll, "{llvm_cfunc_wrapper_name}")
68
+ return builder.call(f, args)
69
+ return main_sig, codegen
70
+
71
+ @njit(sig, **jit_opts)
72
+ def {func_proxy_name}({func_args_str}):
73
+ return _{func_proxy_name}({func_names_args_str})
74
+ """
75
+ ns = {
76
+ **inspect.getmodule(func).__dict__,
77
+ **{
78
+ 'cgutils': cgutils, 'intrinsic': intrinsic, 'ir': ir, 'jit_opts': jit_opts, 'njit': njit,
79
+ 'sig': sig, 'main_sig': main_sig
80
+ }
81
+ }
82
+ if ns.get(func_proxy_name) is not None:
83
+ raise ValueError(f"Name {func_proxy_name} in module {inspect.getmodule(func)} is reserved")
84
+ code = compile(code_txt, inspect.getfile(func), mode='exec')
85
+ exec(code, ns)
86
+ return ns[func_proxy_name]
87
+ return wrap
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbox
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Author: Mikhail Goykhman
5
5
  License: MIT License (with Citation Clause)
6
6
 
@@ -36,4 +36,15 @@ Description-Content-Type: text/markdown
36
36
  License-File: LICENSE
37
37
 
38
38
  # numbox
39
- A toolbox of low-level utilities for work with numba
39
+
40
+ A toolbox of low-level utilities for working with [numba](https://numba.pydata.org/).
41
+
42
+ ## Tools
43
+
44
+ - **Any**: A lightweight structure that wraps any value into the same type leveraging a variant of the type erasure technique.
45
+ - **proxy**: Create a proxy for a decorated function with specified signatures, enabling efficient JIT compilation and caching.
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ pip install numbox
@@ -0,0 +1,14 @@
1
+ numbox/__init__.py,sha256=uZsygMXMKRw-7qhWojAjnpm8GFPXU92xW6XA8O5GwFY,22
2
+ numbox/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ numbox/core/any_type.py,sha256=CvEwFk7EcuFwg5VqDJrYQYmWp_t3Kil92wC7gUOEl-Y,1711
4
+ numbox/core/declare_func.py,sha256=zjlou3avyybHvpqNfp9D1_1kaOxLiGSxXtxiXlLsSPQ,150876
5
+ numbox/core/meminfo.py,sha256=-b7wlCRyqOZjvKjEuwNwzqE4XvnEWxu3I2k4DEP3Cqk,1755
6
+ numbox/core/proxy.py,sha256=kGYlEdLK40lxxu56e_S32s9YuQ6AuQnFegt5uQrUw5w,3889
7
+ numbox/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ numbox/utils/highlevel.py,sha256=hAmF2y2ayPJT0qpwHrGDt09R4-6Ts9sTkCTh-8FTIUU,319
9
+ numbox/utils/lowlevel.py,sha256=6CRfFbMeBZGM7hqPAQzyClzU_e_IsNpqONJknFWGzJM,1405
10
+ numbox-0.1.3.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
11
+ numbox-0.1.3.dist-info/METADATA,sha256=VOYJC8CJ4qWajTGPcv7LkzoefGEqWHY13rjvtQM354I,2271
12
+ numbox-0.1.3.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
13
+ numbox-0.1.3.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
14
+ numbox-0.1.3.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- numbox/__init__.py,sha256=mdp2CftfqYbdKtP-eWv1z7rAUycYv6X1ntXSMUf8Kss,22
2
- numbox/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- numbox/core/any_type.py,sha256=CvEwFk7EcuFwg5VqDJrYQYmWp_t3Kil92wC7gUOEl-Y,1711
4
- numbox/core/meminfo.py,sha256=-b7wlCRyqOZjvKjEuwNwzqE4XvnEWxu3I2k4DEP3Cqk,1755
5
- numbox/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- numbox/utils/highlevel.py,sha256=hAmF2y2ayPJT0qpwHrGDt09R4-6Ts9sTkCTh-8FTIUU,319
7
- numbox/utils/lowlevel.py,sha256=6CRfFbMeBZGM7hqPAQzyClzU_e_IsNpqONJknFWGzJM,1405
8
- numbox-0.1.2.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
9
- numbox-0.1.2.dist-info/METADATA,sha256=-xVLPSJg3MLfTBO61O1pEzpgA8wa9fPIxGp0abcpVEs,1926
10
- numbox-0.1.2.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
11
- numbox-0.1.2.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
12
- numbox-0.1.2.dist-info/RECORD,,
File without changes