mapFolding 0.12.2__py3-none-any.whl → 0.12.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.
- mapFolding/__init__.py +4 -2
- mapFolding/_theSSOT.py +32 -88
- mapFolding/{datatypes.py → _theTypes.py} +25 -3
- mapFolding/basecamp.py +39 -34
- mapFolding/beDRY.py +79 -54
- mapFolding/dataBaskets.py +117 -74
- mapFolding/filesystemToolkit.py +140 -91
- mapFolding/oeis.py +242 -144
- mapFolding/reference/flattened.py +1 -1
- mapFolding/someAssemblyRequired/RecipeJob.py +68 -53
- mapFolding/someAssemblyRequired/__init__.py +40 -15
- mapFolding/someAssemblyRequired/_toolIfThis.py +82 -54
- mapFolding/someAssemblyRequired/_toolkitContainers.py +19 -16
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +35 -26
- mapFolding/someAssemblyRequired/makeAllModules.py +348 -275
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +81 -57
- mapFolding/someAssemblyRequired/toolkitNumba.py +80 -50
- mapFolding/someAssemblyRequired/transformationTools.py +63 -40
- {mapfolding-0.12.2.dist-info → mapfolding-0.12.3.dist-info}/METADATA +7 -11
- {mapfolding-0.12.2.dist-info → mapfolding-0.12.3.dist-info}/RECORD +28 -28
- tests/test_computations.py +26 -8
- tests/test_oeis.py +8 -7
- tests/test_other.py +3 -3
- tests/test_tasks.py +2 -4
- {mapfolding-0.12.2.dist-info → mapfolding-0.12.3.dist-info}/WHEEL +0 -0
- {mapfolding-0.12.2.dist-info → mapfolding-0.12.3.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.12.2.dist-info → mapfolding-0.12.3.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.12.2.dist-info → mapfolding-0.12.3.dist-info}/top_level.txt +0 -0
|
@@ -29,36 +29,37 @@ essential progress feedback capabilities for large-scale computational research.
|
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
31
|
from astToolkit import (
|
|
32
|
-
Be,
|
|
33
|
-
|
|
34
|
-
)
|
|
32
|
+
Be, extractFunctionDef, identifierDotAttribute, IngredientsFunction, IngredientsModule, LedgerOfImports, Make,
|
|
33
|
+
NodeChanger, NodeTourist, Then)
|
|
35
34
|
from astToolkit.transformationTools import write_astModule
|
|
35
|
+
from hunterMakesPy import autoDecodingRLE, raiseIfNone
|
|
36
36
|
from mapFolding import getPathFilenameFoldsTotal, MapFoldingState, packageSettings
|
|
37
37
|
from mapFolding.someAssemblyRequired import IfThis
|
|
38
38
|
from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2Numba
|
|
39
|
-
from mapFolding.someAssemblyRequired.toolkitNumba import
|
|
40
|
-
decorateCallableWithNumba, parametersNumbaLight, SpicesJobNumba,
|
|
41
|
-
)
|
|
39
|
+
from mapFolding.someAssemblyRequired.toolkitNumba import decorateCallableWithNumba, parametersNumbaLight, SpicesJobNumba
|
|
42
40
|
from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
|
|
43
41
|
from pathlib import PurePosixPath
|
|
44
|
-
from typing import cast, NamedTuple
|
|
45
|
-
from
|
|
42
|
+
from typing import cast, NamedTuple, TYPE_CHECKING
|
|
43
|
+
from typing_extensions import TypeIs
|
|
46
44
|
import ast
|
|
47
45
|
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from collections.abc import Callable
|
|
48
|
+
|
|
48
49
|
# Configuration lists for code optimization and dead code elimination
|
|
49
|
-
listIdentifiersNotUsedAllHARDCODED: list[str] = ['concurrencyLimit', 'foldsTotal', 'mapShape'
|
|
50
|
+
listIdentifiersNotUsedAllHARDCODED: list[str] = ['concurrencyLimit', 'foldsTotal', 'mapShape']
|
|
50
51
|
"""Identifiers that are universally unused across all optimization contexts."""
|
|
51
52
|
|
|
52
53
|
listIdentifiersNotUsedParallelSequentialHARDCODED: list[str] = ['indexLeaf']
|
|
53
54
|
"""Identifiers unused in both parallel and sequential execution modes."""
|
|
54
55
|
|
|
55
|
-
listIdentifiersNotUsedSequentialHARDCODED: list[str] = ['foldGroups', 'taskDivisions', 'taskIndex'
|
|
56
|
+
listIdentifiersNotUsedSequentialHARDCODED: list[str] = ['foldGroups', 'taskDivisions', 'taskIndex']
|
|
56
57
|
"""Identifiers unused specifically in sequential execution mode."""
|
|
57
58
|
|
|
58
|
-
listIdentifiersReplacedHARDCODED: list[str] = ['groupsOfFolds'
|
|
59
|
+
listIdentifiersReplacedHARDCODED: list[str] = ['groupsOfFolds']
|
|
59
60
|
"""Identifiers that get replaced with optimized equivalents during transformation."""
|
|
60
61
|
|
|
61
|
-
listIdentifiersStaticValuesHARDCODED: list[str] = ['dimensionsTotal', 'leavesTotal'
|
|
62
|
+
listIdentifiersStaticValuesHARDCODED: list[str] = ['dimensionsTotal', 'leavesTotal']
|
|
62
63
|
"""Identifiers with compile-time constant values that can be embedded directly."""
|
|
63
64
|
|
|
64
65
|
listIdentifiersNotUsedHARDCODED: list[str] = listIdentifiersStaticValuesHARDCODED + listIdentifiersReplacedHARDCODED + listIdentifiersNotUsedAllHARDCODED + listIdentifiersNotUsedParallelSequentialHARDCODED + listIdentifiersNotUsedSequentialHARDCODED
|
|
@@ -67,6 +68,8 @@ listIdentifiersNotUsedHARDCODED: list[str] = listIdentifiersStaticValuesHARDCODE
|
|
|
67
68
|
def addLauncherNumbaProgress(ingredientsModule: IngredientsModule, ingredientsFunction: IngredientsFunction, job: RecipeJobTheorem2Numba, spices: SpicesJobNumba) -> tuple[IngredientsModule, IngredientsFunction]:
|
|
68
69
|
"""Add progress tracking capabilities to a Numba-optimized function.
|
|
69
70
|
|
|
71
|
+
(AI generated docstring)
|
|
72
|
+
|
|
70
73
|
This function modifies both the module and the function to integrate Numba-compatible
|
|
71
74
|
progress tracking for long-running calculations. It performs several key transformations:
|
|
72
75
|
|
|
@@ -79,16 +82,23 @@ def addLauncherNumbaProgress(ingredientsModule: IngredientsModule, ingredientsFu
|
|
|
79
82
|
which can take hours or days to complete, providing visual feedback and
|
|
80
83
|
estimated completion times.
|
|
81
84
|
|
|
82
|
-
Parameters
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
ingredientsModule : IngredientsModule
|
|
88
|
+
The module where the function is defined.
|
|
89
|
+
ingredientsFunction : IngredientsFunction
|
|
90
|
+
The function to modify with progress tracking.
|
|
91
|
+
job : RecipeJobTheorem2Numba
|
|
92
|
+
Configuration specifying shape details and output paths.
|
|
93
|
+
spices : SpicesJobNumba
|
|
94
|
+
Configuration specifying progress bar details.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
moduleAndFunction : tuple[IngredientsModule, IngredientsFunction]
|
|
89
99
|
Modified module and function with integrated progress tracking capabilities.
|
|
90
|
-
"""
|
|
91
100
|
|
|
101
|
+
"""
|
|
92
102
|
linesLaunch: str = f"""
|
|
93
103
|
if __name__ == '__main__':
|
|
94
104
|
with ProgressBar(total={job.foldsTotalEstimated}, update_interval=2) as statusUpdate:
|
|
@@ -107,9 +117,9 @@ if __name__ == '__main__':
|
|
|
107
117
|
ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
|
|
108
118
|
ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
|
|
109
119
|
|
|
110
|
-
findThis =
|
|
111
|
-
doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
|
|
112
|
-
countWithProgressBar = NodeChanger(findThis, doThat)
|
|
120
|
+
findThis: Callable[[ast.AST], TypeIs[ast.AugAssign] | bool] = Be.AugAssign.targetIs(IfThis.isNameIdentifier(job.shatteredDataclass.countingVariableName.id))
|
|
121
|
+
doThat: Callable[[ast.AugAssign], ast.Expr] = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
|
|
122
|
+
countWithProgressBar: NodeChanger[ast.AugAssign, ast.Expr] = NodeChanger(findThis, doThat)
|
|
113
123
|
countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
|
|
114
124
|
|
|
115
125
|
removeReturnStatement = NodeChanger(Be.Return, Then.removeIt)
|
|
@@ -123,6 +133,8 @@ if __name__ == '__main__':
|
|
|
123
133
|
def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job: RecipeJobTheorem2Numba) -> IngredientsFunction:
|
|
124
134
|
"""Convert function parameters into initialized variables with concrete values.
|
|
125
135
|
|
|
136
|
+
(AI generated docstring)
|
|
137
|
+
|
|
126
138
|
This function implements a critical transformation that converts function parameters
|
|
127
139
|
into statically initialized variables in the function body. This enables several
|
|
128
140
|
optimizations:
|
|
@@ -136,12 +148,18 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
|
|
|
136
148
|
replacing abstract parameter references with concrete values from the computation state.
|
|
137
149
|
It also removes unused parameters and variables to eliminate dead code.
|
|
138
150
|
|
|
139
|
-
Parameters
|
|
140
|
-
|
|
141
|
-
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
ingredientsFunction : IngredientsFunction
|
|
154
|
+
The function to transform.
|
|
155
|
+
job : RecipeJobTheorem2Numba
|
|
156
|
+
Recipe containing concrete values for parameters and field metadata.
|
|
142
157
|
|
|
143
|
-
Returns
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
modifiedFunction : IngredientsFunction
|
|
144
161
|
The modified function with parameters converted to initialized variables.
|
|
162
|
+
|
|
145
163
|
"""
|
|
146
164
|
ingredientsFunction.imports.update(job.shatteredDataclass.imports)
|
|
147
165
|
|
|
@@ -160,24 +178,24 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
|
|
|
160
178
|
ImaAnnAssign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
|
|
161
179
|
match elementConstructor:
|
|
162
180
|
case 'scalar':
|
|
163
|
-
cast(ast.Constant, cast(ast.Call, ImaAnnAssign.value).args[0]).value = int(job.state.__dict__[ast_arg.arg])
|
|
181
|
+
cast('ast.Constant', cast('ast.Call', ImaAnnAssign.value).args[0]).value = int(job.state.__dict__[ast_arg.arg])
|
|
164
182
|
case 'array':
|
|
165
|
-
dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], True)
|
|
166
|
-
dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
|
|
167
|
-
cast(ast.Call, ImaAnnAssign.value).args = [dataAs_astExpr]
|
|
183
|
+
dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], assumeAddSpaces=True)
|
|
184
|
+
dataAs_astExpr: ast.expr = cast('ast.Expr', ast.parse(dataAsStrRLE).body[0]).value
|
|
185
|
+
cast('ast.Call', ImaAnnAssign.value).args = [dataAs_astExpr]
|
|
168
186
|
case _:
|
|
169
187
|
list_exprDOTannotation: list[ast.expr] = []
|
|
170
188
|
list_exprDOTvalue: list[ast.expr] = []
|
|
171
189
|
for dimension in job.state.mapShape:
|
|
172
190
|
list_exprDOTannotation.append(Make.Name(elementConstructor))
|
|
173
191
|
list_exprDOTvalue.append(Make.Call(Make.Name(elementConstructor), [Make.Constant(dimension)]))
|
|
174
|
-
cast(ast.Tuple, cast(ast.Subscript, cast(ast.AnnAssign, ImaAnnAssign).annotation).slice).elts = list_exprDOTannotation
|
|
175
|
-
cast(ast.Tuple, ImaAnnAssign.value).elts = list_exprDOTvalue
|
|
192
|
+
cast('ast.Tuple', cast('ast.Subscript', cast('ast.AnnAssign', ImaAnnAssign).annotation).slice).elts = list_exprDOTannotation
|
|
193
|
+
cast('ast.Tuple', ImaAnnAssign.value).elts = list_exprDOTvalue
|
|
176
194
|
|
|
177
195
|
ingredientsFunction.astFunctionDef.body.insert(0, ImaAnnAssign)
|
|
178
196
|
|
|
179
|
-
findThis = IfThis.is_argIdentifier(ast_arg.arg)
|
|
180
|
-
remove_arg = NodeChanger(findThis, Then.removeIt)
|
|
197
|
+
findThis: Callable[[ast.AST], TypeIs[ast.arg] | bool] = IfThis.is_argIdentifier(ast_arg.arg)
|
|
198
|
+
remove_arg: NodeChanger[ast.arg, None] = NodeChanger(findThis, Then.removeIt)
|
|
181
199
|
remove_arg.visit(ingredientsFunction.astFunctionDef)
|
|
182
200
|
|
|
183
201
|
ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
|
|
@@ -186,6 +204,8 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
|
|
|
186
204
|
def makeJobNumba(job: RecipeJobTheorem2Numba, spices: SpicesJobNumba) -> None:
|
|
187
205
|
"""Generate an optimized Numba-compiled computation module for map folding calculations.
|
|
188
206
|
|
|
207
|
+
(AI generated docstring)
|
|
208
|
+
|
|
189
209
|
This function orchestrates the complete code transformation pipeline to convert
|
|
190
210
|
a generic map folding algorithm into a highly optimized, specialized computation
|
|
191
211
|
module. The transformation process includes:
|
|
@@ -203,26 +223,25 @@ def makeJobNumba(job: RecipeJobTheorem2Numba, spices: SpicesJobNumba) -> None:
|
|
|
203
223
|
map folding calculations for the specific map dimensions with maximum
|
|
204
224
|
performance through just-in-time compilation.
|
|
205
225
|
|
|
206
|
-
Parameters
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
226
|
+
Parameters
|
|
227
|
+
----------
|
|
228
|
+
job : RecipeJobTheorem2Numba
|
|
229
|
+
Configuration recipe containing source locations, target paths, and state.
|
|
230
|
+
spices : SpicesJobNumba
|
|
231
|
+
Optimization settings including Numba parameters and progress options.
|
|
210
232
|
|
|
233
|
+
"""
|
|
211
234
|
astFunctionDef: ast.FunctionDef = raiseIfNone(extractFunctionDef(job.source_astModule, job.countCallable))
|
|
212
235
|
ingredientsCount: IngredientsFunction = IngredientsFunction(astFunctionDef, LedgerOfImports())
|
|
213
236
|
|
|
214
237
|
# Remove `foldGroups` and any other unused statements, so you can dynamically determine which variables are not used
|
|
215
|
-
|
|
216
|
-
# findThis = IfThis.isAssignAndTargets0Is(IfThis.isSubscriptIdentifier('foldGroups'))
|
|
217
|
-
doThat = Then.removeIt
|
|
218
|
-
remove_foldGroups = NodeChanger(findThis, doThat)
|
|
219
|
-
# remove_foldGroups.visit(ingredientsCount.astFunctionDef)
|
|
238
|
+
# NodeChanger[ast.Name, None](Be.Assign.targetsIs(lambda list_expr: any(IfThis.isSubscriptIdentifier('foldGroups')(node) for node in list_expr)) , Then.removeIt).visit(ingredientsCount.astFunctionDef) # noqa: ERA001
|
|
220
239
|
|
|
221
240
|
# replace identifiers with static values with their values, so you can dynamically determine which variables are not used
|
|
222
241
|
listIdentifiersStaticValues: list[str] = listIdentifiersStaticValuesHARDCODED
|
|
223
242
|
for identifier in listIdentifiersStaticValues:
|
|
224
|
-
findThis = IfThis.isNameIdentifier(identifier)
|
|
225
|
-
doThat = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
|
|
243
|
+
findThis: Callable[[ast.AST], TypeIs[ast.Name] | bool] = IfThis.isNameIdentifier(identifier)
|
|
244
|
+
doThat: Callable[[ast.Name], ast.Constant] = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
|
|
226
245
|
NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
|
|
227
246
|
|
|
228
247
|
ingredientsModule = IngredientsModule()
|
|
@@ -242,8 +261,8 @@ if __name__ == '__main__':
|
|
|
242
261
|
writeStream.write(str(foldsTotal))
|
|
243
262
|
writeStream.close()
|
|
244
263
|
"""
|
|
245
|
-
# from mapFolding.oeis import getFoldsTotalKnown
|
|
246
|
-
# print(foldsTotal == getFoldsTotalKnown({job.state.mapShape}))
|
|
264
|
+
# from mapFolding.oeis import getFoldsTotalKnown # noqa: ERA001
|
|
265
|
+
# print(foldsTotal == getFoldsTotalKnown({job.state.mapShape})) # noqa: ERA001
|
|
247
266
|
ingredientsModule.appendLauncher(ast.parse(linesLaunch))
|
|
248
267
|
changeReturnParallelCallable = NodeChanger(Be.Return, Then.replaceWith(Make.Return(job.shatteredDataclass.countingVariableName)))
|
|
249
268
|
changeReturnParallelCallable.visit(ingredientsCount.astFunctionDef)
|
|
@@ -258,12 +277,18 @@ if __name__ == '__main__':
|
|
|
258
277
|
generation. Each configuration specifies the source module, target type name,
|
|
259
278
|
and optional import alias for the transformation.
|
|
260
279
|
|
|
261
|
-
Attributes
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
280
|
+
Attributes
|
|
281
|
+
----------
|
|
282
|
+
fml : str
|
|
283
|
+
Framework datatype identifier to be replaced.
|
|
284
|
+
Z0Z_module : identifierDotAttribute
|
|
285
|
+
Module containing the target datatype (e.g., 'numba', 'numpy').
|
|
286
|
+
Z0Z_type_name : str
|
|
287
|
+
Concrete type name in the target module.
|
|
288
|
+
Z0Z_asname : str | None = None
|
|
289
|
+
Optional import alias for the type.
|
|
266
290
|
"""
|
|
291
|
+
|
|
267
292
|
fml: str
|
|
268
293
|
Z0Z_module: identifierDotAttribute
|
|
269
294
|
Z0Z_type_name: str
|
|
@@ -296,7 +321,6 @@ if __name__ == '__main__':
|
|
|
296
321
|
ingredientsCount.imports.addImportFrom_asStr(typeConfig.Z0Z_module, typeConfig.Z0Z_type_name, typeConfig.Z0Z_asname)
|
|
297
322
|
|
|
298
323
|
ingredientsCount.astFunctionDef.decorator_list = [] # TODO low-priority, handle this more elegantly
|
|
299
|
-
# TODO when I add the function signature in numba style back to the decorator, the logic needs to handle `ProgressBarType:`
|
|
300
324
|
ingredientsCount = decorateCallableWithNumba(ingredientsCount, spices.parametersNumba)
|
|
301
325
|
ingredientsModule.appendIngredientsFunction(ingredientsCount)
|
|
302
326
|
write_astModule(ingredientsModule, job.pathFilenameModule, job.packageIdentifier)
|
|
@@ -326,12 +350,12 @@ if __name__ == '__main__':
|
|
|
326
350
|
mapShape = (2,4)
|
|
327
351
|
state = MapFoldingState(mapShape)
|
|
328
352
|
state = initializeGroupsOfFolds(state)
|
|
329
|
-
# foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
|
|
330
|
-
# foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal
|
|
353
|
+
# foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal # noqa: ERA001
|
|
354
|
+
# foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal # noqa: ERA001
|
|
331
355
|
foldsTotalEstimated = 0
|
|
332
356
|
pathModule = PurePosixPath(packageSettings.pathPackage, 'jobs')
|
|
333
357
|
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
|
|
334
358
|
aJob = RecipeJobTheorem2Numba(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
|
|
335
359
|
spices = SpicesJobNumba(useNumbaProgressBar=False, parametersNumba=parametersNumbaLight)
|
|
336
|
-
# spices = SpicesJobNumba()
|
|
360
|
+
# spices = SpicesJobNumba() # noqa: ERA001
|
|
337
361
|
makeJobNumba(aJob, spices)
|
|
@@ -26,13 +26,14 @@ system to produce standalone modules optimized for specific map dimensions and c
|
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
28
|
from astToolkit import identifierDotAttribute, IngredientsFunction, Make
|
|
29
|
-
from
|
|
30
|
-
from numba.core.compiler import CompilerBase as numbaCompilerBase
|
|
31
|
-
from typing import Any, cast, Final, NotRequired, TypedDict
|
|
29
|
+
from typing import cast, Final, NotRequired, TYPE_CHECKING, TypedDict
|
|
32
30
|
import ast
|
|
33
31
|
import dataclasses
|
|
34
32
|
import warnings
|
|
35
33
|
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from collections.abc import Sequence
|
|
36
|
+
|
|
36
37
|
class ParametersNumba(TypedDict):
|
|
37
38
|
"""
|
|
38
39
|
Configuration parameters for Numba compilation decorators.
|
|
@@ -56,6 +57,7 @@ class ParametersNumba(TypedDict):
|
|
|
56
57
|
optional via `NotRequired`, allowing flexible configuration while requiring explicit
|
|
57
58
|
decisions on critical performance and correctness parameters.
|
|
58
59
|
"""
|
|
60
|
+
|
|
59
61
|
_dbg_extend_lifetimes: NotRequired[bool]
|
|
60
62
|
_dbg_optnone: NotRequired[bool]
|
|
61
63
|
_nrt: NotRequired[bool]
|
|
@@ -67,7 +69,7 @@ class ParametersNumba(TypedDict):
|
|
|
67
69
|
forceinline: NotRequired[bool]
|
|
68
70
|
forceobj: NotRequired[bool]
|
|
69
71
|
inline: NotRequired[str]
|
|
70
|
-
locals: NotRequired[dict[str, Any]]
|
|
72
|
+
# locals: NotRequired[dict[str, Any]]
|
|
71
73
|
looplift: NotRequired[bool]
|
|
72
74
|
no_cfunc_wrapper: NotRequired[bool]
|
|
73
75
|
no_cpython_wrapper: NotRequired[bool]
|
|
@@ -75,11 +77,11 @@ class ParametersNumba(TypedDict):
|
|
|
75
77
|
nogil: NotRequired[bool]
|
|
76
78
|
nopython: NotRequired[bool]
|
|
77
79
|
parallel: NotRequired[bool]
|
|
78
|
-
pipeline_class: NotRequired[type[numbaCompilerBase]]
|
|
79
|
-
signature_or_function: NotRequired[Any | Callable[..., Any] | str | tuple[Any, ...]]
|
|
80
|
+
# pipeline_class: NotRequired[type[numbaCompilerBase]]
|
|
81
|
+
# signature_or_function: NotRequired[Any | Callable[..., Any] | str | tuple[Any, ...]]
|
|
80
82
|
target: NotRequired[str]
|
|
81
83
|
|
|
82
|
-
parametersNumbaDefault: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': False, 'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': True, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': True, 'parallel': False
|
|
84
|
+
parametersNumbaDefault: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': False, 'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': True, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': True, 'parallel': False }
|
|
83
85
|
"""
|
|
84
86
|
Comprehensive Numba configuration for maximum performance optimization.
|
|
85
87
|
|
|
@@ -132,54 +134,69 @@ While Numba offers multiple decorators (`@jit`, `@njit`, `@vectorize`), this too
|
|
|
132
134
|
on the general-purpose `@jit` decorator with configurable parameters for flexibility.
|
|
133
135
|
"""
|
|
134
136
|
|
|
135
|
-
def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, parametersNumba: ParametersNumba | None = None) -> IngredientsFunction:
|
|
136
|
-
"""
|
|
137
|
-
Transform a Python function into a Numba-accelerated version with appropriate decorators.
|
|
137
|
+
def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, parametersNumba: ParametersNumba | None = None) -> IngredientsFunction: # noqa: C901
|
|
138
|
+
"""Transform a Python function into a Numba-accelerated version with appropriate decorators.
|
|
138
139
|
|
|
139
|
-
|
|
140
|
-
an IngredientsFunction container. It handles the complete transformation pipeline:
|
|
140
|
+
(AI generated docstring)
|
|
141
141
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
This function applies Numba's `@jit` decorator to an existing function definition within
|
|
143
|
+
an `IngredientsFunction` container. It handles the complete transformation pipeline
|
|
144
|
+
including removing any existing decorators that might conflict with Numba, constructing
|
|
145
|
+
type signatures for Numba compilation when possible, applying the `@jit` decorator with
|
|
146
|
+
specified or default parameters, and updating import requirements to include necessary
|
|
147
|
+
Numba modules.
|
|
146
148
|
|
|
147
149
|
The transformation preserves function semantics while enabling significant performance
|
|
148
150
|
improvements through just-in-time compilation. Type inference is attempted for
|
|
149
151
|
function parameters and return values to enable optimized compilation paths.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
|
|
153
|
+
Parameters
|
|
154
|
+
----------
|
|
155
|
+
ingredientsFunction : IngredientsFunction
|
|
156
|
+
Container holding the function definition and associated metadata.
|
|
157
|
+
parametersNumba : ParametersNumba | None = None
|
|
158
|
+
Optional Numba configuration; uses `parametersNumbaDefault` if `None`.
|
|
159
|
+
|
|
160
|
+
Returns
|
|
161
|
+
-------
|
|
162
|
+
ingredientsFunction : IngredientsFunction
|
|
163
|
+
Modified `IngredientsFunction` with Numba decorator applied and imports updated.
|
|
164
|
+
|
|
155
165
|
"""
|
|
156
166
|
def Z0Z_UnhandledDecorators(astCallable: ast.FunctionDef) -> ast.FunctionDef:
|
|
157
|
-
"""
|
|
158
|
-
|
|
167
|
+
"""Remove existing decorators from function definition to prevent conflicts with Numba.
|
|
168
|
+
|
|
169
|
+
(AI generated docstring)
|
|
159
170
|
|
|
160
171
|
Numba compilation can be incompatible with certain Python decorators, so this
|
|
161
172
|
function strips all existing decorators from a function definition before
|
|
162
|
-
applying the Numba
|
|
173
|
+
applying the Numba `@jit` decorator. Removed decorators are logged as warnings
|
|
163
174
|
for debugging purposes.
|
|
164
175
|
|
|
165
176
|
TODO: Implement more sophisticated decorator handling that can preserve
|
|
166
177
|
compatible decorators and intelligently handle decorator composition.
|
|
167
178
|
|
|
168
|
-
Parameters
|
|
169
|
-
|
|
179
|
+
Parameters
|
|
180
|
+
----------
|
|
181
|
+
astCallable : ast.FunctionDef
|
|
182
|
+
Function definition AST node to process.
|
|
183
|
+
|
|
184
|
+
Returns
|
|
185
|
+
-------
|
|
186
|
+
astCallable : ast.FunctionDef
|
|
187
|
+
Function definition with decorator list cleared.
|
|
170
188
|
|
|
171
|
-
Returns:
|
|
172
|
-
astCallable: Function definition with decorator list cleared
|
|
173
189
|
"""
|
|
174
|
-
# TODO
|
|
190
|
+
# TODO more explicit handling of decorators. I'm able to ignore this because I know `algorithmSource` doesn't have any decorators.
|
|
175
191
|
for decoratorItem in astCallable.decorator_list.copy():
|
|
176
192
|
astCallable.decorator_list.remove(decoratorItem)
|
|
177
|
-
warnings.warn(f"Removed decorator {ast.unparse(decoratorItem)} from {astCallable.name}")
|
|
193
|
+
warnings.warn(f"Removed decorator {ast.unparse(decoratorItem)} from {astCallable.name}", stacklevel=2)
|
|
178
194
|
return astCallable
|
|
179
195
|
|
|
180
196
|
def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None: # pyright: ignore[reportUnusedFunction]
|
|
181
|
-
"""
|
|
182
|
-
|
|
197
|
+
"""Generate Numba-compatible type signatures for function parameters.
|
|
198
|
+
|
|
199
|
+
(AI generated docstring)
|
|
183
200
|
|
|
184
201
|
This function analyzes function parameter type annotations and converts them into
|
|
185
202
|
Numba-compatible type signature expressions. It handles various annotation patterns
|
|
@@ -189,20 +206,25 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
189
206
|
The generated signatures enable Numba to perform more efficient compilation by
|
|
190
207
|
providing explicit type information rather than relying solely on type inference.
|
|
191
208
|
|
|
192
|
-
Parameters
|
|
193
|
-
|
|
209
|
+
Parameters
|
|
210
|
+
----------
|
|
211
|
+
signatureElement : ast.arg
|
|
212
|
+
Function parameter with type annotation to convert.
|
|
213
|
+
|
|
214
|
+
Returns
|
|
215
|
+
-------
|
|
216
|
+
ast.Subscript | ast.Name | None
|
|
217
|
+
Numba-compatible type signature AST node, or None if conversion not possible.
|
|
194
218
|
|
|
195
|
-
Returns:
|
|
196
|
-
Numba-compatible type signature AST node, or None if conversion not possible
|
|
197
219
|
"""
|
|
198
220
|
if isinstance(signatureElement.annotation, ast.Subscript) and isinstance(signatureElement.annotation.slice, ast.Tuple):
|
|
199
221
|
annotationShape: ast.expr = signatureElement.annotation.slice.elts[0]
|
|
200
222
|
if isinstance(annotationShape, ast.Subscript) and isinstance(annotationShape.slice, ast.Tuple):
|
|
201
223
|
shapeAsListSlices: list[ast.Slice] = [ast.Slice() for _axis in range(len(annotationShape.slice.elts))]
|
|
202
|
-
shapeAsListSlices[-1] =
|
|
203
|
-
shapeAST: ast.Slice | ast.Tuple =
|
|
224
|
+
shapeAsListSlices[-1] = Make.Slice(step=Make.Constant(1))
|
|
225
|
+
shapeAST: ast.Slice | ast.Tuple = Make.Tuple(list(shapeAsListSlices))
|
|
204
226
|
else:
|
|
205
|
-
shapeAST =
|
|
227
|
+
shapeAST = Make.Slice(step=Make.Constant(1))
|
|
206
228
|
|
|
207
229
|
annotationDtype: ast.expr = signatureElement.annotation.slice.elts[1]
|
|
208
230
|
if (isinstance(annotationDtype, ast.Subscript) and isinstance(annotationDtype.slice, ast.Attribute)):
|
|
@@ -214,9 +236,9 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
214
236
|
Z0Z_hacky_dtype: str = ndarrayName
|
|
215
237
|
datatype_attr = datatypeAST or Z0Z_hacky_dtype
|
|
216
238
|
ingredientsFunction.imports.addImportFrom_asStr(datatypeModuleDecorator, datatype_attr)
|
|
217
|
-
datatypeNumba =
|
|
239
|
+
datatypeNumba = Make.Name(datatype_attr)
|
|
218
240
|
|
|
219
|
-
return
|
|
241
|
+
return Make.Subscript(datatypeNumba, slice=shapeAST)
|
|
220
242
|
|
|
221
243
|
elif isinstance(signatureElement.annotation, ast.Name):
|
|
222
244
|
return signatureElement.annotation
|
|
@@ -235,14 +257,15 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
235
257
|
|
|
236
258
|
if ingredientsFunction.astFunctionDef.returns and isinstance(ingredientsFunction.astFunctionDef.returns, ast.Name):
|
|
237
259
|
theReturn: ast.Name = ingredientsFunction.astFunctionDef.returns
|
|
238
|
-
list_argsDecorator = [cast(ast.expr,
|
|
239
|
-
,
|
|
260
|
+
list_argsDecorator = [cast("ast.expr", Make.Call(Make.Name(theReturn.id)
|
|
261
|
+
, list_arg4signature_or_function if list_arg4signature_or_function else [], [] ) )]
|
|
240
262
|
elif list_arg4signature_or_function:
|
|
241
|
-
list_argsDecorator = [cast(ast.expr,
|
|
263
|
+
list_argsDecorator = [cast("ast.expr", Make.Tuple(list_arg4signature_or_function))]
|
|
242
264
|
|
|
243
265
|
ingredientsFunction.astFunctionDef = Z0Z_UnhandledDecorators(ingredientsFunction.astFunctionDef)
|
|
244
266
|
if parametersNumba is None:
|
|
245
267
|
parametersNumba = parametersNumbaDefault
|
|
268
|
+
|
|
246
269
|
listDecoratorKeywords: list[ast.keyword] = [Make.keyword(parameterName, Make.Constant(parameterValue)) for parameterName, parameterValue in parametersNumba.items()] # pyright: ignore[reportArgumentType]
|
|
247
270
|
|
|
248
271
|
decoratorModule = Z0Z_numbaDataTypeModule
|
|
@@ -257,8 +280,9 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
257
280
|
|
|
258
281
|
@dataclasses.dataclass
|
|
259
282
|
class SpicesJobNumba:
|
|
260
|
-
"""
|
|
261
|
-
|
|
283
|
+
"""Configuration container for Numba-specific job processing options.
|
|
284
|
+
|
|
285
|
+
(AI generated docstring)
|
|
262
286
|
|
|
263
287
|
This dataclass encapsulates configuration settings that control how Numba
|
|
264
288
|
compilation and execution is applied to job processing functions. It provides
|
|
@@ -269,11 +293,17 @@ class SpicesJobNumba:
|
|
|
269
293
|
Numba's specialized requirements, enabling consistent application of
|
|
270
294
|
optimization settings across different computational contexts.
|
|
271
295
|
|
|
272
|
-
Attributes
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
296
|
+
Attributes
|
|
297
|
+
----------
|
|
298
|
+
useNumbaProgressBar : bool
|
|
299
|
+
Enable progress bar display for long-running computations.
|
|
300
|
+
numbaProgressBarIdentifier : str
|
|
301
|
+
Progress bar implementation identifier.
|
|
302
|
+
parametersNumba : ParametersNumba
|
|
303
|
+
Numba compilation parameters with sensible defaults.
|
|
304
|
+
|
|
276
305
|
"""
|
|
306
|
+
|
|
277
307
|
useNumbaProgressBar: bool = True
|
|
278
308
|
"""Enable progress bar display for Numba-compiled functions with long execution times."""
|
|
279
309
|
|