numbox 0.2.1__py3-none-any.whl → 0.2.2__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/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.2.1'
1
+ __version__ = '0.2.2'
@@ -0,0 +1,125 @@
1
+ from hashlib import md5
2
+ from inspect import getfile, getmodule
3
+ from io import StringIO
4
+ from numba import njit, typeof
5
+ from numba.core.types import Type
6
+ from typing import Any, Callable, NamedTuple, Optional, Sequence, Union
7
+
8
+ from numbox.core.configurations import default_jit_options
9
+ from numbox.core.work.lowlevel_work_utils import ll_make_work
10
+ from numbox.utils.highlevel import cres
11
+
12
+
13
+ def _file_anchor():
14
+ raise NotImplementedError
15
+
16
+
17
+ class End(NamedTuple):
18
+ name: str
19
+ init_value: Any
20
+ ty: Optional[type | Type] = None
21
+
22
+
23
+ class Derived(NamedTuple):
24
+ name: str
25
+ init_value: Any
26
+ derive: Callable
27
+ sources: Sequence[Union['Derived', End]]
28
+ ty: Optional[type | Type] = None
29
+
30
+
31
+ SpecTy = Derived | End
32
+
33
+
34
+ def _input_line(input_: End, ns):
35
+ name_ = input_.name
36
+ init_ = input_.init_value
37
+ ty_ = input_.ty
38
+ if ty_ is not None:
39
+ type_name = f"{name_}_ty"
40
+ ns[type_name] = ty_
41
+ return f"""{name_} = ll_make_work("{name_}", {init_}, (), None, {type_name})"""
42
+ return f"""{name_} = ll_make_work("{name_}", {init_}, (), None)"""
43
+
44
+
45
+ def get_ty(spec_):
46
+ return spec_.ty or typeof(spec_.init_value)
47
+
48
+
49
+ def _derived_cres(ty, sources: Sequence[End], derive, jit_options=None):
50
+ jit_options = jit_options if jit_options is not None else {}
51
+ sources_ty = []
52
+ for source in sources:
53
+ source_ty = get_ty(source)
54
+ sources_ty.append(source_ty)
55
+ derive_sig = ty(*sources_ty)
56
+ derive_cres = cres(derive_sig, **jit_options)(derive)
57
+ return derive_cres
58
+
59
+
60
+ def _derived_line(derived_: Derived, ns: dict, _make_args: list, jit_options=None):
61
+ name_ = derived_.name
62
+ init_ = derived_.init_value
63
+ sources_ = ", ".join([s.name for s in derived_.sources])
64
+ sources_ = sources_ + ", " if "," not in sources_ else sources_
65
+ ty_ = get_ty(derived_)
66
+ derive_ = _derived_cres(ty_, derived_.sources, derived_.derive, jit_options)
67
+ derive_name = f"{name_}_derive"
68
+ _make_args.append(derive_name)
69
+ ns[derive_name] = derive_
70
+ return f"""{name_} = ll_make_work("{name_}", {init_}, ({sources_}), {derive_name})"""
71
+
72
+
73
+ def _verify_access_nodes(
74
+ all_inputs_: Sequence[End],
75
+ all_derived_: Sequence[Derived],
76
+ access_nodes: Sequence[SpecTy]
77
+ ):
78
+ for access_node in access_nodes:
79
+ assert access_node in all_inputs_ or access_node in all_derived_, f"{access_node} cannot be reached"
80
+
81
+
82
+ def code_block_hash(code_txt: str):
83
+ """ Re-compile and re-save cache when source code has changed. """
84
+ return md5(code_txt.encode("utf-8")).hexdigest()
85
+
86
+
87
+ def make_graph(
88
+ all_inputs_: Sequence[End],
89
+ all_derived_: Sequence[Derived],
90
+ access_nodes: SpecTy | Sequence[SpecTy],
91
+ jit_options: Optional[dict] = None
92
+ ):
93
+ if isinstance(access_nodes, SpecTy):
94
+ access_nodes = (access_nodes,)
95
+ _verify_access_nodes(all_inputs_, all_derived_, access_nodes)
96
+ if jit_options is None:
97
+ jit_options = {}
98
+ jit_options = {**default_jit_options, **jit_options}
99
+ ns = {
100
+ **getmodule(_file_anchor).__dict__,
101
+ **{"jit_options": jit_options, "ll_make_work": ll_make_work, "njit": njit}
102
+ }
103
+ _make_args = []
104
+ code_txt = StringIO()
105
+ for input_ in all_inputs_:
106
+ line_ = _input_line(input_, ns)
107
+ code_txt.write(f"\n\t{line_}")
108
+ for derived_ in all_derived_:
109
+ line_ = _derived_line(derived_, ns, _make_args, jit_options)
110
+ code_txt.write(f"\n\t{line_}")
111
+ hash_ = code_block_hash(code_txt.getvalue())
112
+ code_txt.write(f"""\n\taccess_tuple = ({", ".join([n.name for n in access_nodes])})""")
113
+ code_txt.write(f"\n\treturn access_tuple")
114
+ code_txt = code_txt.getvalue()
115
+ make_params = ", ".join(_make_args)
116
+ make_name = f"_make_{hash_}"
117
+ code_txt = f"""
118
+ @njit(**jit_options)
119
+ def {make_name}({make_params}):""" + code_txt + f"""
120
+ return_node_ = {make_name}({make_params})
121
+ """
122
+ code = compile(code_txt, getfile(_file_anchor), mode="exec")
123
+ exec(code, ns)
124
+ return_node_ = ns["return_node_"]
125
+ return return_node_
numbox/core/work/node.py CHANGED
@@ -40,6 +40,13 @@ class Node(NodeBase):
40
40
  def _all_inputs_names(self):
41
41
  return self.all_inputs_names()
42
42
 
43
+ def all_end_nodes(self):
44
+ return list(self._all_end_nodes())
45
+
46
+ @njit(**default_jit_options)
47
+ def _all_end_nodes(self):
48
+ return self.all_end_nodes()
49
+
43
50
  @njit(**default_jit_options)
44
51
  def depends_on(self, obj_):
45
52
  return self.depends_on(obj_)
@@ -116,6 +123,31 @@ def ol_all_inputs_names(self_ty):
116
123
  return _
117
124
 
118
125
 
126
+ @njit(**default_jit_options)
127
+ def _all_end_nodes(node_, names_):
128
+ node = _cast(node_, NodeType)
129
+ for i in range(len(node.inputs)):
130
+ input_ = node.get_input(i)
131
+ name_ = input_.name
132
+ if name_ not in names_ and len(_cast(input_, NodeType).inputs) == 0:
133
+ names_.append(name_)
134
+ _all_end_nodes(input_, names_)
135
+
136
+
137
+ @overload_method(NodeTypeClass, "all_end_nodes", strict=False, jit_options=default_jit_options)
138
+ def ol_all_end_nodes(self_ty):
139
+ def _(self):
140
+ names = List.empty_list(unicode_type)
141
+ for i in range(len(self.inputs)):
142
+ input_ = self.get_input(i)
143
+ name_ = input_.name
144
+ if name_ not in names and len(_cast(input_, NodeType).inputs) == 0:
145
+ names.append(name_)
146
+ _all_end_nodes(input_, names)
147
+ return names
148
+ return _
149
+
150
+
119
151
  @overload_method(NodeTypeClass, "depends_on", strict=False, jit_options=default_jit_options)
120
152
  def ol_depends_on(self_ty, obj_ty):
121
153
  if isinstance(obj_ty, (Literal, UnicodeType,)):
numbox/core/work/work.py CHANGED
@@ -115,6 +115,13 @@ class Work(NodeBase):
115
115
  def _all_inputs_names(self):
116
116
  return self.all_inputs_names()
117
117
 
118
+ def all_end_nodes(self):
119
+ return list(self._all_end_nodes())
120
+
121
+ @njit(**default_jit_options)
122
+ def _all_end_nodes(self):
123
+ return self.all_end_nodes()
124
+
118
125
  @njit(**default_jit_options)
119
126
  def depends_on(self, obj_):
120
127
  return self.depends_on(obj_)
@@ -416,6 +423,14 @@ def ol_all_inputs_names(self_ty):
416
423
  return _
417
424
 
418
425
 
426
+ @overload_method(WorkTypeClass, "all_end_nodes", strict=False, jit_options=default_jit_options)
427
+ def ol_all_end_nodes(self_ty):
428
+ def _(self):
429
+ node = self.as_node()
430
+ return node.all_end_nodes()
431
+ return _
432
+
433
+
419
434
  @overload_method(WorkTypeClass, "depends_on", strict=False, jit_options=default_jit_options)
420
435
  def ol_depends_on(self_ty, obj_ty):
421
436
  if isinstance(obj_ty, (Literal, UnicodeType,)):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbox
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Author: Mikhail Goykhman
5
5
  License: MIT License (with Citation Clause)
6
6
 
@@ -49,7 +49,7 @@ Documentation is available at [numbox](https://goykhman.github.io/numbox).
49
49
  - **Any**: A lightweight structure that wraps any value into the same type leveraging a variant of the type erasure technique.
50
50
  - **Bindings**: JIT-wrappers of functions imported from dynamically linked libraries.
51
51
  - **Node** A lightweight JIT-compatible graph node with type-erased dependencies in a uniform dynamically-sized vector (numba List).
52
- - **proxy**: Create a proxy for a decorated function with specified signatures, enabling efficient JIT compilation and caching.
52
+ - **Proxy**: Create a proxy for a decorated function with specified signatures, enabling efficient JIT compilation and caching.
53
53
  - **Work**: JIT-compatible unit of calculation work with dependencies, inner states, and custom calculation.
54
54
 
55
55
  ## Installation
@@ -1,4 +1,4 @@
1
- numbox/__init__.py,sha256=PmcQ2PI2oP8irnLtJLJby2YfW6sBvLAmL-VpABzTqwc,22
1
+ numbox/__init__.py,sha256=QQ0yjZQnvXM7JeLLZEZWX6NmVUPu1lSROWOXF49_gug,22
2
2
  numbox/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  numbox/core/configurations.py,sha256=0bCmxXL-QMwtvyIDhpXLeT-1KJMf_QpH0wLuEvYLGxQ,68
4
4
  numbox/core/any/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -15,13 +15,14 @@ numbox/core/bindings/utils.py,sha256=aRtN8oUYBk9vgoUGaUJosGx0Za-vvCNwwbZg_g_-LRs
15
15
  numbox/core/proxy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  numbox/core/proxy/proxy.py,sha256=kGYlEdLK40lxxu56e_S32s9YuQ6AuQnFegt5uQrUw5w,3889
17
17
  numbox/core/work/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ numbox/core/work/builder.py,sha256=QaklRb-IciVNPlk1WnQ3Hfc8tHbWbuAQqdrlp51XCcM,3991
18
19
  numbox/core/work/combine_utils.py,sha256=qTVGke_ydzaTQ7o29DFjZWZzKjRNKb0L3yJMaR3TLII,2430
19
20
  numbox/core/work/loader_utils.py,sha256=g83mDWidZJ8oLWP3I3rK8aGISYOO2S-w6HDgtosCyck,1572
20
21
  numbox/core/work/lowlevel_work_utils.py,sha256=TgRRcNfks0oaOXGXXr3ptafd_Xv_lpmH8sjBrJ9bPuI,5748
21
- numbox/core/work/node.py,sha256=4-0p4o94bg54JOvmgAlEVlgR5tSev5SGTqMq9Ht3bd0,4076
22
+ numbox/core/work/node.py,sha256=CMolyoRQjG2A-pTQqZQ0kxKOYTKipWRC0mu8RWHuTUI,5096
22
23
  numbox/core/work/node_base.py,sha256=uI7asM2itQcHuOByXyJtqvrd4ovW6EXDRdHYp3JVHQ0,998
23
24
  numbox/core/work/print_tree.py,sha256=y2u7xmbHvpcA57y8PrGSqOunLNCqhgNXdVtXHqvy1M0,2340
24
- numbox/core/work/work.py,sha256=fdqeqtH8gDXkHFnc0lsFVCn5idP4reSBhYP_ccoiZBQ,13971
25
+ numbox/core/work/work.py,sha256=OZ9rRbaOAzQhvw2akORSlqPllwRe1BUhkMFWZOJSmo0,14369
25
26
  numbox/core/work/work_utils.py,sha256=3q_nnBdzuxWWcdFpbRL2H0T9ZNkUgx1J1uhiZkX3YG4,1039
26
27
  numbox/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
28
  numbox/utils/highlevel.py,sha256=gXYzLsFPKHQfGqaz-Z4DWcCQddv0dS6SKwIsM-_xjYg,1487
@@ -29,8 +30,8 @@ numbox/utils/lowlevel.py,sha256=ACpf8_HyOIsobPlZ31bapkEyuCsV5dojW3AFrcKykrw,1071
29
30
  numbox/utils/meminfo.py,sha256=ykFi8Vt0WcHI3ztgMwvpn6NqaflDSQGL8tjI01jrzm0,1759
30
31
  numbox/utils/timer.py,sha256=KkAkWOHQ72WtPjyiAzt_tF1q0DcOnCDkITTb85DvkUM,553
31
32
  numbox/utils/void_type.py,sha256=IkZsjNeAIShYJtvWbvERdHnl_mbF1rCRWiM3gp6II8U,404
32
- numbox-0.2.1.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
33
- numbox-0.2.1.dist-info/METADATA,sha256=Hk7ONk6PjPPkOpgYG7rgzUAICj86x4ubbLZ_JWepmP8,2792
34
- numbox-0.2.1.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
35
- numbox-0.2.1.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
36
- numbox-0.2.1.dist-info/RECORD,,
33
+ numbox-0.2.2.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
34
+ numbox-0.2.2.dist-info/METADATA,sha256=mbgQDgqnezAK4URoAhC4C4BHwCy5ThKSDkdTkkD6WVQ,2792
35
+ numbox-0.2.2.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
36
+ numbox-0.2.2.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
37
+ numbox-0.2.2.dist-info/RECORD,,
File without changes