mapFolding 0.8.6__py3-none-any.whl → 0.9.1__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.
- mapFolding/__init__.py +60 -13
- mapFolding/basecamp.py +32 -17
- mapFolding/beDRY.py +4 -5
- mapFolding/oeis.py +94 -7
- mapFolding/someAssemblyRequired/RecipeJob.py +103 -0
- mapFolding/someAssemblyRequired/__init__.py +71 -50
- mapFolding/someAssemblyRequired/_theTypes.py +11 -15
- mapFolding/someAssemblyRequired/_tool_Make.py +36 -9
- mapFolding/someAssemblyRequired/_tool_Then.py +59 -25
- mapFolding/someAssemblyRequired/_toolboxAntecedents.py +159 -272
- mapFolding/someAssemblyRequired/_toolboxContainers.py +155 -70
- mapFolding/someAssemblyRequired/_toolboxPython.py +168 -44
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +154 -39
- mapFolding/someAssemblyRequired/toolboxNumba.py +72 -230
- mapFolding/someAssemblyRequired/transformationTools.py +370 -141
- mapFolding/syntheticModules/{numbaCount_doTheNeedful.py → numbaCount.py} +7 -4
- mapFolding/theDao.py +19 -16
- mapFolding/theSSOT.py +165 -62
- mapFolding/toolboxFilesystem.py +1 -1
- mapfolding-0.9.1.dist-info/METADATA +177 -0
- mapfolding-0.9.1.dist-info/RECORD +47 -0
- tests/__init__.py +44 -0
- tests/conftest.py +75 -7
- tests/test_computations.py +92 -10
- tests/test_filesystem.py +32 -33
- tests/test_other.py +0 -1
- tests/test_tasks.py +1 -1
- mapFolding/someAssemblyRequired/newInliner.py +0 -22
- mapfolding-0.8.6.dist-info/METADATA +0 -190
- mapfolding-0.8.6.dist-info/RECORD +0 -47
- {mapfolding-0.8.6.dist-info → mapfolding-0.9.1.dist-info}/WHEEL +0 -0
- {mapfolding-0.8.6.dist-info → mapfolding-0.9.1.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.6.dist-info → mapfolding-0.9.1.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.8.6.dist-info → mapfolding-0.9.1.dist-info}/top_level.txt +0 -0
|
@@ -1,46 +1,39 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Numba-specific
|
|
2
|
+
Numba-specific Tools for Generating Optimized Code
|
|
3
3
|
|
|
4
|
-
This module provides specialized tools
|
|
5
|
-
|
|
4
|
+
This module provides specialized tools for transforming standard Python code into
|
|
5
|
+
Numba-accelerated implementations. It implements a comprehensive transformation
|
|
6
|
+
assembly-line that:
|
|
6
7
|
|
|
7
|
-
1.
|
|
8
|
-
2.
|
|
9
|
-
3.
|
|
10
|
-
4.
|
|
8
|
+
1. Converts dataclass-based algorithm implementations into Numba-compatible versions.
|
|
9
|
+
2. Applies appropriate Numba decorators with optimized configuration settings.
|
|
10
|
+
3. Restructures code to work within Numba's constraints.
|
|
11
|
+
4. Manages type information for optimized compilation.
|
|
11
12
|
|
|
12
|
-
The
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
of generic code transformation tools in the package, allowing similar approaches to be
|
|
16
|
-
applied to other acceleration technologies.
|
|
17
|
-
|
|
18
|
-
This module works in conjunction with transformation tools to convert the general-purpose
|
|
19
|
-
algorithm implementation into a highly-optimized Numba version.
|
|
13
|
+
The module bridges the gap between readable, maintainable Python code and
|
|
14
|
+
highly-optimized numerical computing implementations, enabling significant
|
|
15
|
+
performance improvements while preserving code semantics and correctness.
|
|
20
16
|
"""
|
|
21
17
|
|
|
22
18
|
from collections.abc import Callable, Sequence
|
|
23
|
-
from mapFolding.
|
|
24
|
-
from mapFolding.someAssemblyRequired import
|
|
25
|
-
from mapFolding.someAssemblyRequired.transformationTools import Z0Z_inlineThisFunctionWithTheseValues, Z0Z_lameFindReplace, Z0Z_makeDictionaryReplacementStatements, astModuleToIngredientsFunction, shatter_dataclassesDOTdataclass, write_astModule
|
|
26
|
-
from mapFolding.theSSOT import ComputationState, DatatypeFoldsTotal as TheDatatypeFoldsTotal, DatatypeElephino as TheDatatypeElephino, DatatypeLeavesTotal as TheDatatypeLeavesTotal
|
|
27
|
-
|
|
19
|
+
from mapFolding.someAssemblyRequired import Make, NodeTourist, RecipeSynthesizeFlow, Then, ast_Identifier, str_nameDOTname, IngredientsFunction
|
|
20
|
+
from mapFolding.someAssemblyRequired.transformationTools import ( makeNewFlow, write_astModule, )
|
|
28
21
|
from numba.core.compiler import CompilerBase as numbaCompilerBase
|
|
29
|
-
from
|
|
30
|
-
from typing import Any, cast, Final, TYPE_CHECKING, TypeAlias
|
|
22
|
+
from typing import Any, cast, Final, TYPE_CHECKING, TypeGuard
|
|
31
23
|
import ast
|
|
32
24
|
import dataclasses
|
|
33
25
|
|
|
34
26
|
try:
|
|
35
27
|
from typing import NotRequired
|
|
36
28
|
except Exception:
|
|
37
|
-
from typing_extensions import NotRequired
|
|
29
|
+
from typing_extensions import NotRequired # pyright: ignore[reportShadowedImports]
|
|
38
30
|
|
|
39
31
|
if TYPE_CHECKING:
|
|
40
32
|
from typing import TypedDict
|
|
41
33
|
else:
|
|
42
34
|
TypedDict = dict[str,Any]
|
|
43
35
|
|
|
36
|
+
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
44
37
|
theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
|
|
45
38
|
|
|
46
39
|
class ParametersNumba(TypedDict):
|
|
@@ -52,17 +45,17 @@ class ParametersNumba(TypedDict):
|
|
|
52
45
|
debug: NotRequired[bool]
|
|
53
46
|
error_model: str
|
|
54
47
|
fastmath: bool
|
|
55
|
-
forceinline: bool
|
|
48
|
+
forceinline: NotRequired[bool]
|
|
56
49
|
forceobj: NotRequired[bool]
|
|
57
|
-
inline: str
|
|
50
|
+
inline: NotRequired[str]
|
|
58
51
|
locals: NotRequired[dict[str, Any]]
|
|
59
|
-
looplift: bool
|
|
60
|
-
no_cfunc_wrapper: bool
|
|
61
|
-
no_cpython_wrapper: bool
|
|
52
|
+
looplift: NotRequired[bool]
|
|
53
|
+
no_cfunc_wrapper: NotRequired[bool]
|
|
54
|
+
no_cpython_wrapper: NotRequired[bool]
|
|
62
55
|
no_rewrites: NotRequired[bool]
|
|
63
56
|
nogil: NotRequired[bool]
|
|
64
|
-
nopython: bool
|
|
65
|
-
parallel: bool
|
|
57
|
+
nopython: NotRequired[bool]
|
|
58
|
+
parallel: NotRequired[bool]
|
|
66
59
|
pipeline_class: NotRequired[type[numbaCompilerBase]]
|
|
67
60
|
signature_or_function: NotRequired[Any | Callable[..., Any] | str | tuple[Any, ...]]
|
|
68
61
|
target: NotRequired[str]
|
|
@@ -78,6 +71,7 @@ parametersNumbaSuperJit: Final[ParametersNumba] = { **parametersNumbaDefault, 'n
|
|
|
78
71
|
parametersNumbaSuperJitParallel: Final[ParametersNumba] = { **parametersNumbaSuperJit, '_nrt': True, 'parallel': True, }
|
|
79
72
|
"""Speed, no helmet, concurrency, no talking to non-jitted functions."""
|
|
80
73
|
parametersNumbaMinimum: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': True, 'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': False, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': False, 'forceobj': True, 'parallel': False, }
|
|
74
|
+
parametersNumbaLight: Final[ParametersNumba] = {'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': True}
|
|
81
75
|
|
|
82
76
|
Z0Z_numbaDataTypeModule: str_nameDOTname = 'numba'
|
|
83
77
|
Z0Z_decoratorCallable: ast_Identifier = 'jit'
|
|
@@ -91,7 +85,7 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
91
85
|
warnings.warn(f"Removed decorator {ast.unparse(decoratorItem)} from {astCallable.name}")
|
|
92
86
|
return astCallable
|
|
93
87
|
|
|
94
|
-
def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None: #
|
|
88
|
+
def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None: # pyright: ignore[reportUnusedFunction]
|
|
95
89
|
if isinstance(signatureElement.annotation, ast.Subscript) and isinstance(signatureElement.annotation.slice, ast.Tuple):
|
|
96
90
|
annotationShape: ast.expr = signatureElement.annotation.slice.elts[0]
|
|
97
91
|
if isinstance(annotationShape, ast.Subscript) and isinstance(annotationShape.slice, ast.Tuple):
|
|
@@ -125,10 +119,10 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
125
119
|
list_arg4signature_or_function: list[ast.expr] = []
|
|
126
120
|
for parameter in ingredientsFunction.astFunctionDef.args.args:
|
|
127
121
|
# For now, let Numba infer them.
|
|
122
|
+
signatureElement: ast.Subscript | ast.Name | None = makeSpecialSignatureForNumba(parameter)
|
|
123
|
+
if signatureElement:
|
|
124
|
+
list_arg4signature_or_function.append(signatureElement)
|
|
128
125
|
continue
|
|
129
|
-
# signatureElement: ast.Subscript | ast.Name | None = makeSpecialSignatureForNumba(parameter)
|
|
130
|
-
# if signatureElement:
|
|
131
|
-
# list_arg4signature_or_function.append(signatureElement)
|
|
132
126
|
|
|
133
127
|
if ingredientsFunction.astFunctionDef.returns and isinstance(ingredientsFunction.astFunctionDef.returns, ast.Name):
|
|
134
128
|
theReturn: ast.Name = ingredientsFunction.astFunctionDef.returns
|
|
@@ -152,213 +146,61 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
152
146
|
ingredientsFunction.astFunctionDef.decorator_list = [astDecorator]
|
|
153
147
|
return ingredientsFunction
|
|
154
148
|
|
|
149
|
+
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
155
150
|
@dataclasses.dataclass
|
|
156
151
|
class SpicesJobNumba:
|
|
157
152
|
useNumbaProgressBar: bool = True
|
|
158
153
|
numbaProgressBarIdentifier: ast_Identifier = 'ProgressBarGroupsOfFolds'
|
|
159
|
-
parametersNumba =
|
|
154
|
+
parametersNumba: ParametersNumba = dataclasses.field(default_factory=ParametersNumba) # type: ignore
|
|
160
155
|
|
|
161
|
-
|
|
162
|
-
class
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
# Source
|
|
170
|
-
source_astModule = parsePathFilename2astModule(theNumbaFlow.pathFilenameSequential)
|
|
171
|
-
sourceCountCallable: ast_Identifier = theNumbaFlow.callableSequential
|
|
172
|
-
|
|
173
|
-
sourceLogicalPathModuleDataclass: str_nameDOTname = theNumbaFlow.logicalPathModuleDataclass
|
|
174
|
-
sourceDataclassIdentifier: ast_Identifier = theNumbaFlow.dataclassIdentifier
|
|
175
|
-
sourceDataclassInstance: ast_Identifier = theNumbaFlow.dataclassInstance
|
|
176
|
-
|
|
177
|
-
sourcePathPackage: PurePosixPath | None = theNumbaFlow.pathPackage
|
|
178
|
-
sourcePackageIdentifier: ast_Identifier | None = theNumbaFlow.packageIdentifier
|
|
179
|
-
|
|
180
|
-
# ========================================
|
|
181
|
-
# Filesystem (names of physical objects)
|
|
182
|
-
pathPackage: PurePosixPath | None = None
|
|
183
|
-
pathModule: PurePosixPath | None = PurePosixPath(getPathRootJobDEFAULT())
|
|
184
|
-
""" `pathModule` will override `pathPackage` and `logicalPathRoot`."""
|
|
185
|
-
fileExtension: str = theNumbaFlow.fileExtension
|
|
186
|
-
pathFilenameFoldsTotal: PurePosixPath = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
|
|
187
|
-
|
|
188
|
-
# ========================================
|
|
189
|
-
# Logical identifiers (as opposed to physical identifiers)
|
|
190
|
-
# ========================================
|
|
191
|
-
packageIdentifier: ast_Identifier | None = None
|
|
192
|
-
logicalPathRoot: str_nameDOTname | None = None
|
|
193
|
-
""" `logicalPathRoot` likely corresponds to a physical filesystem directory."""
|
|
194
|
-
moduleIdentifier: ast_Identifier = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
|
|
195
|
-
countCallable: ast_Identifier = sourceCountCallable
|
|
196
|
-
dataclassIdentifier: ast_Identifier | None = sourceDataclassIdentifier
|
|
197
|
-
dataclassInstance: ast_Identifier | None = sourceDataclassInstance
|
|
198
|
-
logicalPathModuleDataclass: str_nameDOTname | None = sourceLogicalPathModuleDataclass
|
|
199
|
-
|
|
200
|
-
# ========================================
|
|
201
|
-
# Datatypes
|
|
202
|
-
DatatypeFoldsTotal: TypeAlias = TheDatatypeFoldsTotal
|
|
203
|
-
DatatypeElephino: TypeAlias = TheDatatypeElephino
|
|
204
|
-
DatatypeLeavesTotal: TypeAlias = TheDatatypeLeavesTotal
|
|
205
|
-
|
|
206
|
-
def _makePathFilename(self,
|
|
207
|
-
pathRoot: PurePosixPath | None = None,
|
|
208
|
-
logicalPathINFIX: str_nameDOTname | None = None,
|
|
209
|
-
filenameStem: str | None = None,
|
|
210
|
-
fileExtension: str | None = None,
|
|
211
|
-
) -> PurePosixPath:
|
|
212
|
-
if pathRoot is None:
|
|
213
|
-
pathRoot = self.pathPackage or PurePosixPath(Path.cwd())
|
|
214
|
-
if logicalPathINFIX:
|
|
215
|
-
whyIsThisStillAThing: list[str] = logicalPathINFIX.split('.')
|
|
216
|
-
pathRoot = pathRoot.joinpath(*whyIsThisStillAThing)
|
|
217
|
-
if filenameStem is None:
|
|
218
|
-
filenameStem = self.moduleIdentifier
|
|
219
|
-
if fileExtension is None:
|
|
220
|
-
fileExtension = self.fileExtension
|
|
221
|
-
filename: str = filenameStem + fileExtension
|
|
222
|
-
return pathRoot.joinpath(filename)
|
|
223
|
-
|
|
224
|
-
@property
|
|
225
|
-
def pathFilenameModule(self) -> PurePosixPath:
|
|
226
|
-
if self.pathModule is None:
|
|
227
|
-
return self._makePathFilename()
|
|
228
|
-
else:
|
|
229
|
-
return self._makePathFilename(pathRoot=self.pathModule, logicalPathINFIX=None)
|
|
230
|
-
|
|
231
|
-
def __post_init__(self):
|
|
232
|
-
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(self.state.mapShape))
|
|
233
|
-
|
|
234
|
-
if self.moduleIdentifier is None: # type: ignore
|
|
235
|
-
self.moduleIdentifier = pathFilenameFoldsTotal.stem
|
|
236
|
-
|
|
237
|
-
if self.pathFilenameFoldsTotal is None: # type: ignore
|
|
238
|
-
self.pathFilenameFoldsTotal = pathFilenameFoldsTotal
|
|
239
|
-
|
|
240
|
-
if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.dataclassIdentifier and self.dataclassInstance: # type: ignore
|
|
241
|
-
self.shatteredDataclass = shatter_dataclassesDOTdataclass(self.logicalPathModuleDataclass, self.dataclassIdentifier, self.dataclassInstance)
|
|
242
|
-
|
|
243
|
-
# ========================================
|
|
244
|
-
# Fields you probably don't need =================================
|
|
245
|
-
# Dispatcher =================================
|
|
246
|
-
sourceDispatcherCallable: ast_Identifier = theNumbaFlow.callableDispatcher
|
|
247
|
-
dispatcherCallable: ast_Identifier = sourceDispatcherCallable
|
|
248
|
-
# Parallel counting =================================
|
|
249
|
-
sourceDataclassInstanceTaskDistribution: ast_Identifier = theNumbaFlow.dataclassInstanceTaskDistribution
|
|
250
|
-
sourceConcurrencyManagerNamespace: ast_Identifier = theNumbaFlow.concurrencyManagerNamespace
|
|
251
|
-
sourceConcurrencyManagerIdentifier: ast_Identifier = theNumbaFlow.concurrencyManagerIdentifier
|
|
252
|
-
dataclassInstanceTaskDistribution: ast_Identifier = sourceDataclassInstanceTaskDistribution
|
|
253
|
-
concurrencyManagerNamespace: ast_Identifier = sourceConcurrencyManagerNamespace
|
|
254
|
-
concurrencyManagerIdentifier: ast_Identifier = sourceConcurrencyManagerIdentifier
|
|
156
|
+
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
157
|
+
class be:
|
|
158
|
+
@staticmethod
|
|
159
|
+
def Call(node: ast.AST) -> TypeGuard[ast.Call]:
|
|
160
|
+
return isinstance(node, ast.Call)
|
|
161
|
+
@staticmethod
|
|
162
|
+
def Return(node: ast.AST) -> TypeGuard[ast.Return]:
|
|
163
|
+
return isinstance(node, ast.Return)
|
|
255
164
|
|
|
256
165
|
def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
listAllIngredientsFunctions = [
|
|
261
|
-
(ingredientsInitialize := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableInitialize)),
|
|
262
|
-
(ingredientsParallel := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableParallel)),
|
|
263
|
-
(ingredientsSequential := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableSequential)),
|
|
264
|
-
(ingredientsDispatcher := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableDispatcher)),
|
|
265
|
-
]
|
|
266
|
-
|
|
267
|
-
# Inline functions ========================================================
|
|
268
|
-
dictionaryReplacementStatements = Z0Z_makeDictionaryReplacementStatements(numbaFlow.source_astModule)
|
|
269
|
-
# NOTE Replacements statements are based on the identifiers in the _source_, so operate on the source identifiers.
|
|
270
|
-
ingredientsInitialize.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsInitialize.astFunctionDef, dictionaryReplacementStatements)
|
|
271
|
-
ingredientsParallel.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsParallel.astFunctionDef, dictionaryReplacementStatements)
|
|
272
|
-
ingredientsSequential.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsSequential.astFunctionDef, dictionaryReplacementStatements)
|
|
273
|
-
|
|
274
|
-
# assignRecipeIdentifiersToCallable. =============================
|
|
275
|
-
# TODO How can I use `RecipeSynthesizeFlow` as the SSOT for the pairs of items that may need to be replaced?
|
|
276
|
-
# NOTE reminder: you are updating these `ast.Name` here (and not in a more general search) because this is a
|
|
277
|
-
# narrow search for `ast.Call` so you won't accidentally replace unrelated `ast.Name`.
|
|
278
|
-
listFindReplace = [(numbaFlow.sourceCallableDispatcher, numbaFlow.callableDispatcher),
|
|
279
|
-
(numbaFlow.sourceCallableInitialize, numbaFlow.callableInitialize),
|
|
280
|
-
(numbaFlow.sourceCallableParallel, numbaFlow.callableParallel),
|
|
281
|
-
(numbaFlow.sourceCallableSequential, numbaFlow.callableSequential),]
|
|
282
|
-
for ingredients in listAllIngredientsFunctions:
|
|
283
|
-
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
284
|
-
updateCallName = NodeChanger(ifThis.isCall_Identifier(source_Identifier), Then.DOTfunc(Then.replaceWith(Make.Name(recipe_Identifier))))
|
|
285
|
-
updateCallName.visit(ingredients.astFunctionDef)
|
|
286
|
-
|
|
287
|
-
ingredientsDispatcher.astFunctionDef.name = numbaFlow.callableDispatcher
|
|
288
|
-
ingredientsInitialize.astFunctionDef.name = numbaFlow.callableInitialize
|
|
289
|
-
ingredientsParallel.astFunctionDef.name = numbaFlow.callableParallel
|
|
290
|
-
ingredientsSequential.astFunctionDef.name = numbaFlow.callableSequential
|
|
291
|
-
|
|
292
|
-
# Assign identifiers per the recipe. ==============================
|
|
293
|
-
listFindReplace = [(numbaFlow.sourceDataclassInstance, numbaFlow.dataclassInstance),
|
|
294
|
-
(numbaFlow.sourceDataclassInstanceTaskDistribution, numbaFlow.dataclassInstanceTaskDistribution),
|
|
295
|
-
(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.concurrencyManagerNamespace),]
|
|
296
|
-
for ingredients in listAllIngredientsFunctions:
|
|
297
|
-
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
298
|
-
updateName = NodeChanger(ifThis.isName_Identifier(source_Identifier), Then.DOTid(Then.replaceWith(recipe_Identifier)))
|
|
299
|
-
update_arg = NodeChanger(ifThis.isArgument_Identifier(source_Identifier), Then.DOTarg(Then.replaceWith(recipe_Identifier)))
|
|
300
|
-
updateName.visit(ingredients.astFunctionDef)
|
|
301
|
-
update_arg.visit(ingredients.astFunctionDef)
|
|
302
|
-
|
|
303
|
-
updateConcurrencyManager = NodeChanger(ifThis.isCallAttributeNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
|
|
304
|
-
, Then.DOTfunc(Then.replaceWith(Make.Attribute(Make.Name(numbaFlow.concurrencyManagerNamespace), numbaFlow.concurrencyManagerIdentifier))))
|
|
305
|
-
updateConcurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
306
|
-
|
|
307
|
-
# shatter Dataclass =======================================================
|
|
308
|
-
instance_Identifier = numbaFlow.dataclassInstance
|
|
309
|
-
getTheOtherRecord_damn = numbaFlow.dataclassInstanceTaskDistribution
|
|
310
|
-
shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, instance_Identifier)
|
|
311
|
-
ingredientsDispatcher.imports.update(shatteredDataclass.ledger)
|
|
312
|
-
|
|
313
|
-
# Change callable parameters and Call to the callable at the same time ====
|
|
314
|
-
# TODO How can I use ast and/or other tools to ensure that when I change a callable, I also change the statements that call the callable?
|
|
315
|
-
# Asked differently, how do I integrate separate statements into a "subroutine", and that subroutine is "atomic/indivisible"?
|
|
316
|
-
# sequentialCallable =========================================================
|
|
317
|
-
ingredientsSequential.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
318
|
-
astCallSequentialCallable = Make.Call(Make.Name(numbaFlow.callableSequential), shatteredDataclass.listName4Parameters)
|
|
319
|
-
changeReturnSequentialCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.fragments4AssignmentOrParameters)))
|
|
320
|
-
ingredientsSequential.astFunctionDef.returns = shatteredDataclass.signatureReturnAnnotation
|
|
321
|
-
replaceAssignSequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.replaceWith(Make.Assign(listTargets=[shatteredDataclass.fragments4AssignmentOrParameters], value=astCallSequentialCallable)))
|
|
322
|
-
|
|
323
|
-
unpack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
324
|
-
repack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.insertThisBelow([shatteredDataclass.repack]))
|
|
325
|
-
|
|
326
|
-
changeReturnSequentialCallable.visit(ingredientsSequential.astFunctionDef)
|
|
327
|
-
replaceAssignSequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
328
|
-
unpack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
329
|
-
repack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
330
|
-
|
|
331
|
-
ingredientsSequential.astFunctionDef = Z0Z_lameFindReplace(ingredientsSequential.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name) # type: ignore
|
|
332
|
-
|
|
333
|
-
# parallelCallable =========================================================
|
|
334
|
-
ingredientsParallel.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
335
|
-
replaceCall2concurrencyManager = NodeChanger(ifThis.isCallAttributeNamespace_Identifier(numbaFlow.concurrencyManagerNamespace, numbaFlow.concurrencyManagerIdentifier), Then.replaceWith(Make.Call(Make.Attribute(Make.Name(numbaFlow.concurrencyManagerNamespace), numbaFlow.concurrencyManagerIdentifier), listArguments=[Make.Name(numbaFlow.callableParallel)] + shatteredDataclass.listName4Parameters)))
|
|
336
|
-
|
|
337
|
-
# NOTE I am dissatisfied with this logic for many reasons, including that it requires separate NodeCollector and NodeReplacer instances.
|
|
338
|
-
astCallConcurrencyResult: list[ast.Call] = []
|
|
339
|
-
get_astCallConcurrencyResult: NodeTourist = NodeTourist(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)), lambda node: NodeTourist(be.Call, Then.appendTo(astCallConcurrencyResult)).visit(node)) # pyright: ignore[reportUnknownArgumentType, reportUnknownLambdaType]
|
|
340
|
-
get_astCallConcurrencyResult.visit(ingredientsDispatcher.astFunctionDef)
|
|
341
|
-
replaceAssignParallelCallable = NodeChanger(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)), Then.DOTvalue(Then.replaceWith(astCallConcurrencyResult[0])))
|
|
342
|
-
replaceAssignParallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
343
|
-
changeReturnParallelCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.countingVariableName)))
|
|
344
|
-
ingredientsParallel.astFunctionDef.returns = shatteredDataclass.countingVariableAnnotation
|
|
345
|
-
|
|
346
|
-
unpack4parallelCallable = NodeChanger(ifThis.isAssignAndValueIsCallAttributeNamespace_Identifier(numbaFlow.concurrencyManagerNamespace, numbaFlow.concurrencyManagerIdentifier), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
347
|
-
|
|
348
|
-
unpack4parallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
349
|
-
replaceCall2concurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
350
|
-
changeReturnParallelCallable.visit(ingredientsParallel.astFunctionDef)
|
|
351
|
-
|
|
352
|
-
ingredientsParallel.astFunctionDef = Z0Z_lameFindReplace(ingredientsParallel.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name) # type: ignore
|
|
166
|
+
"""
|
|
167
|
+
Transform standard Python algorithm code into optimized Numba implementations.
|
|
353
168
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
169
|
+
This function implements the complete transformation pipeline that converts
|
|
170
|
+
a conventional Python implementation into a high-performance Numba-accelerated
|
|
171
|
+
version. The process includes:
|
|
172
|
+
|
|
173
|
+
1. Extracting core algorithm functions from the source module
|
|
174
|
+
2. Inlining function calls to create self-contained implementations
|
|
175
|
+
3. Transforming dataclass access patterns for Numba compatibility
|
|
176
|
+
4. Applying appropriate Numba decorators with optimization settings
|
|
177
|
+
5. Generating a unified module with sequential and parallel implementations
|
|
178
|
+
6. Writing the transformed code to the filesystem with properly managed imports
|
|
357
179
|
|
|
358
|
-
|
|
359
|
-
|
|
180
|
+
The transformation preserves the logical structure and semantics of the original
|
|
181
|
+
implementation while making it compatible with Numba's constraints and
|
|
182
|
+
optimization capabilities. This creates a bridge between the general-purpose
|
|
183
|
+
implementation and the highly-optimized version needed for production use.
|
|
184
|
+
|
|
185
|
+
Parameters:
|
|
186
|
+
numbaFlow: Configuration object that specifies all aspects of the
|
|
187
|
+
transformation process, including source and target locations,
|
|
188
|
+
function and variable names, and output paths.
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
ingredientsModuleNumbaUnified = makeNewFlow(numbaFlow)
|
|
192
|
+
|
|
193
|
+
# numba decorators =========================================
|
|
194
|
+
ingredientsModuleNumbaUnified.listIngredientsFunctions[1] = decorateCallableWithNumba(ingredientsModuleNumbaUnified.listIngredientsFunctions[1])
|
|
195
|
+
ingredientsModuleNumbaUnified.listIngredientsFunctions[2] = decorateCallableWithNumba(ingredientsModuleNumbaUnified.listIngredientsFunctions[2])
|
|
360
196
|
|
|
361
197
|
write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
|
|
362
198
|
|
|
199
|
+
def getIt(astCallConcurrencyResult: list[ast.Call]) -> Callable[[ast.AST], ast.AST]:
|
|
200
|
+
def workhorse(node: ast.AST) -> ast.AST:
|
|
201
|
+
NodeTourist(be.Call, Then.appendTo(astCallConcurrencyResult)).visit(node)
|
|
202
|
+
return node
|
|
203
|
+
return workhorse
|
|
204
|
+
|
|
363
205
|
if __name__ == '__main__':
|
|
364
206
|
makeNumbaFlow(theNumbaFlow)
|