mapFolding 0.8.5__py3-none-any.whl → 0.9.0__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 +66 -18
- mapFolding/basecamp.py +32 -17
- mapFolding/beDRY.py +3 -3
- mapFolding/oeis.py +121 -25
- mapFolding/someAssemblyRequired/__init__.py +48 -27
- mapFolding/someAssemblyRequired/_theTypes.py +11 -15
- mapFolding/someAssemblyRequired/_tool_Make.py +40 -12
- mapFolding/someAssemblyRequired/_tool_Then.py +59 -25
- mapFolding/someAssemblyRequired/_toolboxAntecedents.py +151 -276
- mapFolding/someAssemblyRequired/_toolboxContainers.py +185 -51
- mapFolding/someAssemblyRequired/_toolboxPython.py +165 -44
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +141 -20
- mapFolding/someAssemblyRequired/toolboxNumba.py +93 -52
- mapFolding/someAssemblyRequired/transformationTools.py +228 -138
- mapFolding/syntheticModules/numbaCount_doTheNeedful.py +0 -1
- mapFolding/theSSOT.py +147 -55
- mapFolding/toolboxFilesystem.py +1 -1
- mapfolding-0.9.0.dist-info/METADATA +177 -0
- mapfolding-0.9.0.dist-info/RECORD +46 -0
- tests/__init__.py +44 -0
- tests/conftest.py +75 -7
- tests/test_computations.py +90 -9
- tests/test_filesystem.py +32 -33
- tests/test_other.py +0 -1
- tests/test_tasks.py +2 -2
- mapFolding/noHomeYet.py +0 -32
- mapFolding/someAssemblyRequired/newInliner.py +0 -22
- mapfolding-0.8.5.dist-info/METADATA +0 -190
- mapfolding-0.8.5.dist-info/RECORD +0 -48
- {mapfolding-0.8.5.dist-info → mapfolding-0.9.0.dist-info}/WHEEL +0 -0
- {mapfolding-0.8.5.dist-info → mapfolding-0.9.0.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.5.dist-info → mapfolding-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.8.5.dist-info → mapfolding-0.9.0.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,35 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Job-specific Numba Code Generation for Map Folding Calculations
|
|
3
|
+
|
|
4
|
+
This module specializes in generating highly-optimized, single-purpose Numba modules
|
|
5
|
+
for specific map folding calculation jobs. Unlike the general-purpose transformation
|
|
6
|
+
in toolboxNumba.py, this module creates standalone Python modules optimized for a
|
|
7
|
+
single map shape with statically-encoded parameters.
|
|
8
|
+
|
|
9
|
+
The code generation pipeline focuses on:
|
|
10
|
+
|
|
11
|
+
1. Converting function parameters to initialized variables with concrete values.
|
|
12
|
+
2. Replacing dynamic computations with statically-known values.
|
|
13
|
+
3. Eliminating unused code paths and variables.
|
|
14
|
+
4. Adding progress tracking for long-running calculations.
|
|
15
|
+
5. Applying appropriate Numba optimizations for the specific calculation.
|
|
16
|
+
|
|
17
|
+
This creates extremely fast, specialized implementations that can be run directly
|
|
18
|
+
as Python scripts or further compiled into standalone executables.
|
|
19
|
+
"""
|
|
20
|
+
|
|
2
21
|
from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal
|
|
3
|
-
from mapFolding.someAssemblyRequired import ast_Identifier,
|
|
22
|
+
from mapFolding.someAssemblyRequired import ast_Identifier, ifThis, Make, NodeChanger, Then, IngredientsFunction, IngredientsModule, LedgerOfImports
|
|
4
23
|
from mapFolding.someAssemblyRequired.toolboxNumba import RecipeJob, SpicesJobNumba, decorateCallableWithNumba
|
|
5
|
-
from mapFolding.someAssemblyRequired.transformationTools import
|
|
24
|
+
from mapFolding.someAssemblyRequired.transformationTools import extractFunctionDef, write_astModule
|
|
6
25
|
from mapFolding.someAssemblyRequired.transformationTools import makeInitializedComputationState
|
|
7
|
-
from mapFolding.theSSOT import The
|
|
26
|
+
from mapFolding.theSSOT import The, raiseIfNoneGitHubIssueNumber3
|
|
27
|
+
from mapFolding.oeis import getFoldsTotalKnown
|
|
8
28
|
from typing import cast
|
|
9
29
|
from Z0Z_tools import autoDecodingRLE
|
|
10
30
|
from pathlib import PurePosixPath
|
|
11
31
|
import ast
|
|
32
|
+
"""Synthesize one file to compute `foldsTotal` of `mapShape`."""
|
|
12
33
|
|
|
13
34
|
list_IdentifiersNotUsedAllHARDCODED = ['concurrencyLimit', 'foldsTotal', 'mapShape',]
|
|
14
35
|
list_IdentifiersNotUsedParallelSequentialHARDCODED = ['indexLeaf']
|
|
@@ -21,13 +42,36 @@ list_IdentifiersStaticValuesHARDCODED = ['dimensionsTotal', 'leavesTotal',]
|
|
|
21
42
|
list_IdentifiersNotUsedHARDCODED = list_IdentifiersStaticValuesHARDCODED + list_IdentifiersReplacedHARDCODED + list_IdentifiersNotUsedAllHARDCODED + list_IdentifiersNotUsedParallelSequentialHARDCODED + list_IdentifiersNotUsedSequentialHARDCODED
|
|
22
43
|
|
|
23
44
|
def addLauncherNumbaProgress(ingredientsModule: IngredientsModule, ingredientsFunction: IngredientsFunction, job: RecipeJob, spices: SpicesJobNumba) -> tuple[IngredientsModule, IngredientsFunction]:
|
|
45
|
+
"""
|
|
46
|
+
Add progress tracking capabilities to a Numba-optimized function.
|
|
47
|
+
|
|
48
|
+
This function modifies both the module and the function to integrate Numba-compatible
|
|
49
|
+
progress tracking for long-running calculations. It performs several key transformations:
|
|
50
|
+
|
|
51
|
+
1. Adds a progress bar parameter to the function signature
|
|
52
|
+
2. Replaces counting increments with progress bar updates
|
|
53
|
+
3. Creates a launcher section that displays and updates progress
|
|
54
|
+
4. Configures file output to save results upon completion
|
|
24
55
|
|
|
56
|
+
The progress tracking is particularly important for map folding calculations
|
|
57
|
+
which can take hours or days to complete, providing visual feedback and
|
|
58
|
+
estimated completion times.
|
|
59
|
+
|
|
60
|
+
Parameters:
|
|
61
|
+
ingredientsModule: The module where the function is defined.
|
|
62
|
+
ingredientsFunction: The function to modify with progress tracking.
|
|
63
|
+
job: Configuration specifying shape details and output paths.
|
|
64
|
+
spices: Configuration specifying progress bar details.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
A tuple containing the modified module and function with progress tracking.
|
|
68
|
+
"""
|
|
25
69
|
linesLaunch: str = f"""
|
|
26
70
|
if __name__ == '__main__':
|
|
27
71
|
with ProgressBar(total={job.foldsTotalEstimated}, update_interval=2) as statusUpdate:
|
|
28
72
|
{job.countCallable}(statusUpdate)
|
|
29
73
|
foldsTotal = statusUpdate.n * {job.state.leavesTotal}
|
|
30
|
-
print('
|
|
74
|
+
print('\\nmap {job.state.mapShape} =', foldsTotal)
|
|
31
75
|
writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
|
|
32
76
|
writeStream.write(str(foldsTotal))
|
|
33
77
|
writeStream.close()
|
|
@@ -50,12 +94,35 @@ if __name__ == '__main__':
|
|
|
50
94
|
return ingredientsModule, ingredientsFunction
|
|
51
95
|
|
|
52
96
|
def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job: RecipeJob) -> IngredientsFunction:
|
|
97
|
+
"""
|
|
98
|
+
Convert function parameters into initialized variables with concrete values.
|
|
99
|
+
|
|
100
|
+
This function implements a critical transformation that converts function parameters
|
|
101
|
+
into statically initialized variables in the function body. This enables several
|
|
102
|
+
optimizations:
|
|
103
|
+
|
|
104
|
+
1. Eliminating parameter passing overhead.
|
|
105
|
+
2. Embedding concrete values directly in the code.
|
|
106
|
+
3. Allowing Numba to optimize based on known value characteristics.
|
|
107
|
+
4. Simplifying function signatures for specialized use cases.
|
|
108
|
+
|
|
109
|
+
The function handles different data types (scalars, arrays, custom types) appropriately,
|
|
110
|
+
replacing abstract parameter references with concrete values from the computation state.
|
|
111
|
+
It also removes unused parameters and variables to eliminate dead code.
|
|
112
|
+
|
|
113
|
+
Parameters:
|
|
114
|
+
ingredientsFunction: The function to transform.
|
|
115
|
+
job: Recipe containing concrete values for parameters and field metadata.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
The modified function with parameters converted to initialized variables.
|
|
119
|
+
"""
|
|
53
120
|
ingredientsFunction.imports.update(job.shatteredDataclass.ledger)
|
|
54
121
|
|
|
55
122
|
list_IdentifiersNotUsed = list_IdentifiersNotUsedHARDCODED
|
|
56
123
|
|
|
57
|
-
|
|
58
|
-
for ast_arg in
|
|
124
|
+
list_argCuzMyBrainRefusesToThink = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
|
|
125
|
+
for ast_arg in list_argCuzMyBrainRefusesToThink:
|
|
59
126
|
if ast_arg.arg in job.shatteredDataclass.field2AnnAssign:
|
|
60
127
|
if ast_arg.arg in list_IdentifiersNotUsed:
|
|
61
128
|
pass
|
|
@@ -63,12 +130,11 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
|
|
|
63
130
|
ImaAnnAssign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
|
|
64
131
|
match elementConstructor:
|
|
65
132
|
case 'scalar':
|
|
66
|
-
ImaAnnAssign.value.args[0].value = int(job.state.__dict__[ast_arg.arg])
|
|
133
|
+
ImaAnnAssign.value.args[0].value = int(job.state.__dict__[ast_arg.arg]) # type: ignore
|
|
67
134
|
case 'array':
|
|
68
|
-
# print(ast.dump(ImaAnnAssign))
|
|
69
135
|
dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], addSpaces=True)
|
|
70
136
|
dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
|
|
71
|
-
ImaAnnAssign.value.args = [dataAs_astExpr]
|
|
137
|
+
ImaAnnAssign.value.args = [dataAs_astExpr] # type: ignore
|
|
72
138
|
case _:
|
|
73
139
|
list_exprDOTannotation: list[ast.expr] = []
|
|
74
140
|
list_exprDOTvalue: list[ast.expr] = []
|
|
@@ -87,12 +153,36 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
|
|
|
87
153
|
ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
|
|
88
154
|
return ingredientsFunction
|
|
89
155
|
|
|
90
|
-
def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba):
|
|
91
|
-
|
|
92
|
-
|
|
156
|
+
def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
|
|
157
|
+
"""
|
|
158
|
+
Generate a highly-optimized, single-purpose Numba module for a specific map shape.
|
|
159
|
+
|
|
160
|
+
This function implements the complete transformation pipeline for creating a
|
|
161
|
+
standalone, specialized implementation for calculating map folding solutions for
|
|
162
|
+
a specific shape. The process includes:
|
|
163
|
+
|
|
164
|
+
1. Extracting the counting function from the source module
|
|
165
|
+
2. Removing unused code paths based on static analysis
|
|
166
|
+
3. Replacing dynamic variables with concrete values
|
|
167
|
+
4. Converting parameters to initialized variables
|
|
168
|
+
5. Adding progress tracking if requested
|
|
169
|
+
6. Applying Numba optimizations and type specifications
|
|
170
|
+
7. Writing the final module to the filesystem
|
|
171
|
+
|
|
172
|
+
The resulting Python module is both human-readable and extraordinarily efficient,
|
|
173
|
+
with all shape-specific optimizations statically encoded. This creates specialized
|
|
174
|
+
implementations that can be orders of magnitude faster than general-purpose code.
|
|
175
|
+
|
|
176
|
+
Parameters:
|
|
177
|
+
job: Configuration specifying the target shape, paths, and computation state.
|
|
178
|
+
spices: Configuration specifying Numba and progress tracking options.
|
|
179
|
+
"""
|
|
180
|
+
astFunctionDef = extractFunctionDef(job.source_astModule, job.countCallable)
|
|
181
|
+
if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
|
|
182
|
+
ingredientsCount: IngredientsFunction = IngredientsFunction(astFunctionDef, LedgerOfImports())
|
|
93
183
|
|
|
94
184
|
# Change the return so you can dynamically determine which variables are not used
|
|
95
|
-
removeReturnStatement = NodeChanger(
|
|
185
|
+
removeReturnStatement = NodeChanger(lambda node: isinstance(node, ast.Return), Then.removeIt) # type: ignore
|
|
96
186
|
removeReturnStatement.visit(ingredientsCount.astFunctionDef)
|
|
97
187
|
ingredientsCount.astFunctionDef.returns = Make.Constant(value=None)
|
|
98
188
|
|
|
@@ -110,21 +200,51 @@ def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba):
|
|
|
110
200
|
NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
|
|
111
201
|
|
|
112
202
|
# This launcher eliminates the use of one identifier, so run it now and you can dynamically determine which variables are not used
|
|
203
|
+
ingredientsModule = IngredientsModule()
|
|
113
204
|
if spices.useNumbaProgressBar:
|
|
114
|
-
ingredientsModule = IngredientsModule()
|
|
115
205
|
ingredientsModule, ingredientsCount = addLauncherNumbaProgress(ingredientsModule, ingredientsCount, job, spices)
|
|
116
206
|
spices.parametersNumba['nogil'] = True
|
|
117
207
|
|
|
118
208
|
ingredientsCount = move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsCount, job)
|
|
119
209
|
|
|
210
|
+
Z0Z_Identifier = 'DatatypeLeavesTotal'
|
|
211
|
+
Z0Z_type = 'uint8'
|
|
212
|
+
ingredientsModule.imports.addImportFrom_asStr('numba', Z0Z_type)
|
|
213
|
+
Z0Z_module = 'typing'
|
|
214
|
+
Z0Z_annotation = 'TypeAlias'
|
|
215
|
+
ingredientsModule.imports.addImportFrom_asStr(Z0Z_module, Z0Z_annotation)
|
|
216
|
+
Z0Z_statement = Make.AnnAssign(Make.Name(Z0Z_Identifier, ast.Store()), Make.Name(Z0Z_annotation), Make.Name(Z0Z_type))
|
|
217
|
+
ingredientsModule.appendPrologue(statement=Z0Z_statement)
|
|
218
|
+
|
|
219
|
+
Z0Z_Identifier = 'DatatypeElephino'
|
|
220
|
+
Z0Z_type = 'int16'
|
|
221
|
+
ingredientsModule.imports.addImportFrom_asStr('numba', Z0Z_type)
|
|
222
|
+
Z0Z_module = 'typing'
|
|
223
|
+
Z0Z_annotation = 'TypeAlias'
|
|
224
|
+
ingredientsModule.imports.addImportFrom_asStr(Z0Z_module, Z0Z_annotation)
|
|
225
|
+
Z0Z_statement = Make.AnnAssign(Make.Name(Z0Z_Identifier, ast.Store()), Make.Name(Z0Z_annotation), Make.Name(Z0Z_type))
|
|
226
|
+
ingredientsModule.appendPrologue(statement=Z0Z_statement)
|
|
227
|
+
|
|
228
|
+
ingredientsCount.imports.removeImportFromModule('mapFolding.theSSOT')
|
|
229
|
+
Z0Z_module = 'numpy'
|
|
230
|
+
Z0Z_asname = 'Array1DLeavesTotal'
|
|
231
|
+
ingredientsCount.imports.removeImportFrom(Z0Z_module, None, Z0Z_asname)
|
|
232
|
+
Z0Z_type_name = 'uint8'
|
|
233
|
+
ingredientsCount.imports.addImportFrom_asStr(Z0Z_module, Z0Z_type_name, Z0Z_asname)
|
|
234
|
+
Z0Z_asname = 'Array1DElephino'
|
|
235
|
+
ingredientsCount.imports.removeImportFrom(Z0Z_module, None, Z0Z_asname)
|
|
236
|
+
Z0Z_type_name = 'int16'
|
|
237
|
+
ingredientsCount.imports.addImportFrom_asStr(Z0Z_module, Z0Z_type_name, Z0Z_asname)
|
|
238
|
+
Z0Z_asname = 'Array3D'
|
|
239
|
+
ingredientsCount.imports.removeImportFrom(Z0Z_module, None, Z0Z_asname)
|
|
240
|
+
Z0Z_type_name = 'uint8'
|
|
241
|
+
ingredientsCount.imports.addImportFrom_asStr(Z0Z_module, Z0Z_type_name, Z0Z_asname)
|
|
242
|
+
|
|
120
243
|
ingredientsCount.astFunctionDef.decorator_list = [] # TODO low-priority, handle this more elegantly
|
|
121
244
|
# TODO when I add the function signature in numba style back to the decorator, the logic needs to handle `ProgressBarType:`
|
|
122
245
|
ingredientsCount = decorateCallableWithNumba(ingredientsCount, spices.parametersNumba)
|
|
123
246
|
|
|
124
247
|
ingredientsModule.appendIngredientsFunction(ingredientsCount)
|
|
125
|
-
|
|
126
|
-
# add imports, make str, remove unused imports
|
|
127
|
-
# put on disk
|
|
128
248
|
write_astModule(ingredientsModule, job.pathFilenameModule, job.packageIdentifier)
|
|
129
249
|
|
|
130
250
|
"""
|
|
@@ -149,10 +269,11 @@ def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba):
|
|
|
149
269
|
"""
|
|
150
270
|
|
|
151
271
|
if __name__ == '__main__':
|
|
152
|
-
mapShape = (
|
|
272
|
+
mapShape = (2,4)
|
|
153
273
|
state = makeInitializedComputationState(mapShape)
|
|
274
|
+
foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
|
|
154
275
|
pathModule = PurePosixPath(The.pathPackage, 'jobs')
|
|
155
276
|
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
|
|
156
|
-
aJob = RecipeJob(state, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
|
|
277
|
+
aJob = RecipeJob(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
|
|
157
278
|
spices = SpicesJobNumba()
|
|
158
279
|
makeJobNumba(aJob, spices)
|
|
@@ -1,45 +1,42 @@
|
|
|
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
|
|
19
|
+
from mapFolding.someAssemblyRequired import grab, IngredientsModule, LedgerOfImports, Make, NodeChanger, NodeTourist, RecipeSynthesizeFlow, Then, ast_Identifier, ifThis, parsePathFilename2astModule, str_nameDOTname, IngredientsFunction, ShatteredDataclass
|
|
20
|
+
from mapFolding.someAssemblyRequired.transformationTools import inlineFunctionDef, Z0Z_lameFindReplace, astModuleToIngredientsFunction, shatter_dataclassesDOTdataclass, write_astModule
|
|
21
|
+
from mapFolding.theSSOT import ComputationState, DatatypeFoldsTotal as TheDatatypeFoldsTotal, DatatypeElephino as TheDatatypeElephino, DatatypeLeavesTotal as TheDatatypeLeavesTotal
|
|
23
22
|
from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal, getPathRootJobDEFAULT
|
|
24
|
-
from mapFolding.someAssemblyRequired import IngredientsModule, LedgerOfImports, Make, NodeChanger, NodeTourist, RecipeSynthesizeFlow, Then, ast_Identifier, be, ifThis, parsePathFilename2astModule, str_nameDOTname, IngredientsFunction, ShatteredDataclass
|
|
25
|
-
from mapFolding.someAssemblyRequired.transformationTools import Z0Z_inlineThisFunctionWithTheseValues, Z0Z_lameFindReplace, Z0Z_makeDictionaryReplacementStatements, astModuleToIngredientsFunction, shatter_dataclassesDOTdataclass, write_astModule
|
|
26
|
-
from mapFolding.theSSOT import ComputationState
|
|
27
23
|
from numba.core.compiler import CompilerBase as numbaCompilerBase
|
|
28
24
|
from pathlib import Path, PurePosixPath
|
|
29
|
-
from typing import Any, cast, Final, TYPE_CHECKING
|
|
25
|
+
from typing import Any, cast, Final, TYPE_CHECKING, TypeAlias, TypeGuard
|
|
30
26
|
import ast
|
|
31
27
|
import dataclasses
|
|
32
28
|
|
|
33
29
|
try:
|
|
34
30
|
from typing import NotRequired
|
|
35
31
|
except Exception:
|
|
36
|
-
from typing_extensions import NotRequired
|
|
32
|
+
from typing_extensions import NotRequired # pyright: ignore[reportShadowedImports]
|
|
37
33
|
|
|
38
34
|
if TYPE_CHECKING:
|
|
39
35
|
from typing import TypedDict
|
|
40
36
|
else:
|
|
41
37
|
TypedDict = dict[str,Any]
|
|
42
38
|
|
|
39
|
+
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
43
40
|
theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
|
|
44
41
|
|
|
45
42
|
class ParametersNumba(TypedDict):
|
|
@@ -78,8 +75,8 @@ parametersNumbaSuperJitParallel: Final[ParametersNumba] = { **parametersNumbaSup
|
|
|
78
75
|
"""Speed, no helmet, concurrency, no talking to non-jitted functions."""
|
|
79
76
|
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, }
|
|
80
77
|
|
|
81
|
-
Z0Z_numbaDataTypeModule = 'numba'
|
|
82
|
-
Z0Z_decoratorCallable = 'jit'
|
|
78
|
+
Z0Z_numbaDataTypeModule: str_nameDOTname = 'numba'
|
|
79
|
+
Z0Z_decoratorCallable: ast_Identifier = 'jit'
|
|
83
80
|
|
|
84
81
|
def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, parametersNumba: ParametersNumba | None = None) -> IngredientsFunction:
|
|
85
82
|
def Z0Z_UnhandledDecorators(astCallable: ast.FunctionDef) -> ast.FunctionDef:
|
|
@@ -90,7 +87,7 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
90
87
|
warnings.warn(f"Removed decorator {ast.unparse(decoratorItem)} from {astCallable.name}")
|
|
91
88
|
return astCallable
|
|
92
89
|
|
|
93
|
-
def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None: #
|
|
90
|
+
def makeSpecialSignatureForNumba(signatureElement: ast.arg) -> ast.Subscript | ast.Name | None: # pyright: ignore[reportUnusedFunction]
|
|
94
91
|
if isinstance(signatureElement.annotation, ast.Subscript) and isinstance(signatureElement.annotation.slice, ast.Tuple):
|
|
95
92
|
annotationShape: ast.expr = signatureElement.annotation.slice.elts[0]
|
|
96
93
|
if isinstance(annotationShape, ast.Subscript) and isinstance(annotationShape.slice, ast.Tuple):
|
|
@@ -123,7 +120,6 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
123
120
|
|
|
124
121
|
list_arg4signature_or_function: list[ast.expr] = []
|
|
125
122
|
for parameter in ingredientsFunction.astFunctionDef.args.args:
|
|
126
|
-
# Efficient translation of Python scalar types to Numba types https://github.com/hunterhogan/mapFolding/issues/8
|
|
127
123
|
# For now, let Numba infer them.
|
|
128
124
|
continue
|
|
129
125
|
# signatureElement: ast.Subscript | ast.Name | None = makeSpecialSignatureForNumba(parameter)
|
|
@@ -142,8 +138,8 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
142
138
|
parametersNumba = parametersNumbaDefault
|
|
143
139
|
listDecoratorKeywords: list[ast.keyword] = [Make.keyword(parameterName, Make.Constant(parameterValue)) for parameterName, parameterValue in parametersNumba.items()]
|
|
144
140
|
|
|
145
|
-
decoratorModule
|
|
146
|
-
decoratorCallable
|
|
141
|
+
decoratorModule = Z0Z_numbaDataTypeModule
|
|
142
|
+
decoratorCallable = Z0Z_decoratorCallable
|
|
147
143
|
ingredientsFunction.imports.addImportFrom_asStr(decoratorModule, decoratorCallable)
|
|
148
144
|
# Leave this line in so that global edits will change it.
|
|
149
145
|
astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_argsDecorator, listDecoratorKeywords)
|
|
@@ -152,18 +148,20 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
152
148
|
ingredientsFunction.astFunctionDef.decorator_list = [astDecorator]
|
|
153
149
|
return ingredientsFunction
|
|
154
150
|
|
|
151
|
+
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
155
152
|
@dataclasses.dataclass
|
|
156
153
|
class SpicesJobNumba:
|
|
157
154
|
useNumbaProgressBar: bool = True
|
|
158
155
|
numbaProgressBarIdentifier: ast_Identifier = 'ProgressBarGroupsOfFolds'
|
|
159
156
|
parametersNumba = parametersNumbaDefault
|
|
160
157
|
|
|
158
|
+
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
161
159
|
@dataclasses.dataclass
|
|
162
160
|
class RecipeJob:
|
|
163
161
|
state: ComputationState
|
|
164
162
|
# TODO create function to calculate `foldsTotalEstimated`
|
|
165
163
|
foldsTotalEstimated: int = 0
|
|
166
|
-
shatteredDataclass: ShatteredDataclass = dataclasses.field(default=None, init=True) #
|
|
164
|
+
shatteredDataclass: ShatteredDataclass = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
|
|
167
165
|
|
|
168
166
|
# ========================================
|
|
169
167
|
# Source
|
|
@@ -183,20 +181,25 @@ class RecipeJob:
|
|
|
183
181
|
pathModule: PurePosixPath | None = PurePosixPath(getPathRootJobDEFAULT())
|
|
184
182
|
""" `pathModule` will override `pathPackage` and `logicalPathRoot`."""
|
|
185
183
|
fileExtension: str = theNumbaFlow.fileExtension
|
|
186
|
-
pathFilenameFoldsTotal: PurePosixPath = dataclasses.field(default=None, init=True) #
|
|
184
|
+
pathFilenameFoldsTotal: PurePosixPath = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
|
|
187
185
|
|
|
188
186
|
# ========================================
|
|
189
187
|
# Logical identifiers (as opposed to physical identifiers)
|
|
190
|
-
# ========================================
|
|
191
188
|
packageIdentifier: ast_Identifier | None = None
|
|
192
189
|
logicalPathRoot: str_nameDOTname | None = None
|
|
193
190
|
""" `logicalPathRoot` likely corresponds to a physical filesystem directory."""
|
|
194
|
-
moduleIdentifier: ast_Identifier = dataclasses.field(default=None, init=True) #
|
|
191
|
+
moduleIdentifier: ast_Identifier = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
|
|
195
192
|
countCallable: ast_Identifier = sourceCountCallable
|
|
196
193
|
dataclassIdentifier: ast_Identifier | None = sourceDataclassIdentifier
|
|
197
194
|
dataclassInstance: ast_Identifier | None = sourceDataclassInstance
|
|
198
195
|
logicalPathModuleDataclass: str_nameDOTname | None = sourceLogicalPathModuleDataclass
|
|
199
196
|
|
|
197
|
+
# ========================================
|
|
198
|
+
# Datatypes
|
|
199
|
+
DatatypeFoldsTotal: TypeAlias = TheDatatypeFoldsTotal
|
|
200
|
+
DatatypeElephino: TypeAlias = TheDatatypeElephino
|
|
201
|
+
DatatypeLeavesTotal: TypeAlias = TheDatatypeLeavesTotal
|
|
202
|
+
|
|
200
203
|
def _makePathFilename(self,
|
|
201
204
|
pathRoot: PurePosixPath | None = None,
|
|
202
205
|
logicalPathINFIX: str_nameDOTname | None = None,
|
|
@@ -225,13 +228,13 @@ class RecipeJob:
|
|
|
225
228
|
def __post_init__(self):
|
|
226
229
|
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(self.state.mapShape))
|
|
227
230
|
|
|
228
|
-
if self.moduleIdentifier is None:
|
|
231
|
+
if self.moduleIdentifier is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
229
232
|
self.moduleIdentifier = pathFilenameFoldsTotal.stem
|
|
230
233
|
|
|
231
|
-
if self.pathFilenameFoldsTotal is None:
|
|
234
|
+
if self.pathFilenameFoldsTotal is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
232
235
|
self.pathFilenameFoldsTotal = pathFilenameFoldsTotal
|
|
233
236
|
|
|
234
|
-
if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.dataclassIdentifier and self.dataclassInstance:
|
|
237
|
+
if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.dataclassIdentifier and self.dataclassInstance: # pyright: ignore[reportUnnecessaryComparison]
|
|
235
238
|
self.shatteredDataclass = shatter_dataclassesDOTdataclass(self.logicalPathModuleDataclass, self.dataclassIdentifier, self.dataclassInstance)
|
|
236
239
|
|
|
237
240
|
# ========================================
|
|
@@ -247,7 +250,39 @@ class RecipeJob:
|
|
|
247
250
|
concurrencyManagerNamespace: ast_Identifier = sourceConcurrencyManagerNamespace
|
|
248
251
|
concurrencyManagerIdentifier: ast_Identifier = sourceConcurrencyManagerIdentifier
|
|
249
252
|
|
|
253
|
+
class be:
|
|
254
|
+
@staticmethod
|
|
255
|
+
def Call(node: ast.AST) -> TypeGuard[ast.Call]:
|
|
256
|
+
return isinstance(node, ast.Call)
|
|
257
|
+
@staticmethod
|
|
258
|
+
def Return(node: ast.AST) -> TypeGuard[ast.Return]:
|
|
259
|
+
return isinstance(node, ast.Return)
|
|
260
|
+
|
|
250
261
|
def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
262
|
+
"""
|
|
263
|
+
Transform standard Python algorithm code into optimized Numba implementations.
|
|
264
|
+
|
|
265
|
+
This function implements the complete transformation pipeline that converts
|
|
266
|
+
a conventional Python implementation into a high-performance Numba-accelerated
|
|
267
|
+
version. The process includes:
|
|
268
|
+
|
|
269
|
+
1. Extracting core algorithm functions from the source module
|
|
270
|
+
2. Inlining function calls to create self-contained implementations
|
|
271
|
+
3. Transforming dataclass access patterns for Numba compatibility
|
|
272
|
+
4. Applying appropriate Numba decorators with optimization settings
|
|
273
|
+
5. Generating a unified module with sequential and parallel implementations
|
|
274
|
+
6. Writing the transformed code to the filesystem with properly managed imports
|
|
275
|
+
|
|
276
|
+
The transformation preserves the logical structure and semantics of the original
|
|
277
|
+
implementation while making it compatible with Numba's constraints and
|
|
278
|
+
optimization capabilities. This creates a bridge between the general-purpose
|
|
279
|
+
implementation and the highly-optimized version needed for production use.
|
|
280
|
+
|
|
281
|
+
Parameters:
|
|
282
|
+
numbaFlow: Configuration object that specifies all aspects of the
|
|
283
|
+
transformation process, including source and target locations,
|
|
284
|
+
function and variable names, and output paths.
|
|
285
|
+
"""
|
|
251
286
|
# TODO a tool to automatically remove unused variables from the ArgumentsSpecification (return, and returns) _might_ be nice.
|
|
252
287
|
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
253
288
|
|
|
@@ -259,14 +294,14 @@ def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
|
259
294
|
]
|
|
260
295
|
|
|
261
296
|
# Inline functions ========================================================
|
|
262
|
-
dictionaryReplacementStatements = Z0Z_makeDictionaryReplacementStatements(numbaFlow.source_astModule)
|
|
263
297
|
# NOTE Replacements statements are based on the identifiers in the _source_, so operate on the source identifiers.
|
|
264
|
-
ingredientsInitialize.astFunctionDef =
|
|
265
|
-
ingredientsParallel.astFunctionDef =
|
|
266
|
-
ingredientsSequential.astFunctionDef =
|
|
298
|
+
ingredientsInitialize.astFunctionDef = inlineFunctionDef(numbaFlow.sourceCallableInitialize, numbaFlow.source_astModule)
|
|
299
|
+
ingredientsParallel.astFunctionDef = inlineFunctionDef(numbaFlow.sourceCallableParallel, numbaFlow.source_astModule)
|
|
300
|
+
ingredientsSequential.astFunctionDef = inlineFunctionDef(numbaFlow.sourceCallableSequential, numbaFlow.source_astModule)
|
|
267
301
|
|
|
268
302
|
# assignRecipeIdentifiersToCallable. =============================
|
|
269
|
-
#
|
|
303
|
+
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
304
|
+
# How can I use dataclass settings as the SSOT for specific actions? https://github.com/hunterhogan/mapFolding/issues/16
|
|
270
305
|
# NOTE reminder: you are updating these `ast.Name` here (and not in a more general search) because this is a
|
|
271
306
|
# narrow search for `ast.Call` so you won't accidentally replace unrelated `ast.Name`.
|
|
272
307
|
listFindReplace = [(numbaFlow.sourceCallableDispatcher, numbaFlow.callableDispatcher),
|
|
@@ -275,7 +310,7 @@ def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
|
275
310
|
(numbaFlow.sourceCallableSequential, numbaFlow.callableSequential),]
|
|
276
311
|
for ingredients in listAllIngredientsFunctions:
|
|
277
312
|
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
278
|
-
updateCallName = NodeChanger(ifThis.isCall_Identifier(source_Identifier),
|
|
313
|
+
updateCallName = NodeChanger(ifThis.isCall_Identifier(source_Identifier), grab.funcAttribute(Then.replaceWith(Make.Name(recipe_Identifier))))
|
|
279
314
|
updateCallName.visit(ingredients.astFunctionDef)
|
|
280
315
|
|
|
281
316
|
ingredientsDispatcher.astFunctionDef.name = numbaFlow.callableDispatcher
|
|
@@ -289,13 +324,13 @@ def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
|
289
324
|
(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.concurrencyManagerNamespace),]
|
|
290
325
|
for ingredients in listAllIngredientsFunctions:
|
|
291
326
|
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
292
|
-
updateName = NodeChanger(ifThis.isName_Identifier(source_Identifier),
|
|
293
|
-
update_arg = NodeChanger(ifThis.isArgument_Identifier(source_Identifier),
|
|
327
|
+
updateName = NodeChanger(ifThis.isName_Identifier(source_Identifier) , grab.idAttribute(Then.replaceWith(recipe_Identifier)))
|
|
328
|
+
update_arg = NodeChanger(ifThis.isArgument_Identifier(source_Identifier), grab.argAttribute(Then.replaceWith(recipe_Identifier)))
|
|
294
329
|
updateName.visit(ingredients.astFunctionDef)
|
|
295
330
|
update_arg.visit(ingredients.astFunctionDef)
|
|
296
331
|
|
|
297
332
|
updateConcurrencyManager = NodeChanger(ifThis.isCallAttributeNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
|
|
298
|
-
,
|
|
333
|
+
, grab.funcAttribute(Then.replaceWith(Make.Attribute(Make.Name(numbaFlow.concurrencyManagerNamespace), numbaFlow.concurrencyManagerIdentifier))))
|
|
299
334
|
updateConcurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
300
335
|
|
|
301
336
|
# shatter Dataclass =======================================================
|
|
@@ -304,25 +339,24 @@ def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
|
304
339
|
shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, instance_Identifier)
|
|
305
340
|
ingredientsDispatcher.imports.update(shatteredDataclass.ledger)
|
|
306
341
|
|
|
342
|
+
# How can I use dataclass settings as the SSOT for specific actions? https://github.com/hunterhogan/mapFolding/issues/16
|
|
307
343
|
# Change callable parameters and Call to the callable at the same time ====
|
|
308
|
-
# 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?
|
|
309
|
-
# Asked differently, how do I integrate separate statements into a "subroutine", and that subroutine is "atomic/indivisible"?
|
|
310
344
|
# sequentialCallable =========================================================
|
|
311
345
|
ingredientsSequential.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
312
346
|
astCallSequentialCallable = Make.Call(Make.Name(numbaFlow.callableSequential), shatteredDataclass.listName4Parameters)
|
|
313
347
|
changeReturnSequentialCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.fragments4AssignmentOrParameters)))
|
|
314
348
|
ingredientsSequential.astFunctionDef.returns = shatteredDataclass.signatureReturnAnnotation
|
|
315
|
-
replaceAssignSequentialCallable = NodeChanger(ifThis.
|
|
349
|
+
replaceAssignSequentialCallable = NodeChanger(ifThis.isAssignAndValueIs(ifThis.isCall_Identifier(numbaFlow.callableSequential)), Then.replaceWith(Make.Assign(listTargets=[shatteredDataclass.fragments4AssignmentOrParameters], value=astCallSequentialCallable)))
|
|
316
350
|
|
|
317
|
-
unpack4sequentialCallable = NodeChanger(ifThis.
|
|
318
|
-
repack4sequentialCallable = NodeChanger(ifThis.
|
|
351
|
+
unpack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIs(ifThis.isCall_Identifier(numbaFlow.callableSequential)), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
352
|
+
repack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIs(ifThis.isCall_Identifier(numbaFlow.callableSequential)), Then.insertThisBelow([shatteredDataclass.repack]))
|
|
319
353
|
|
|
320
354
|
changeReturnSequentialCallable.visit(ingredientsSequential.astFunctionDef)
|
|
321
355
|
replaceAssignSequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
322
356
|
unpack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
323
357
|
repack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
324
358
|
|
|
325
|
-
ingredientsSequential.astFunctionDef = Z0Z_lameFindReplace(ingredientsSequential.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
|
|
359
|
+
ingredientsSequential.astFunctionDef = Z0Z_lameFindReplace(ingredientsSequential.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
|
|
326
360
|
|
|
327
361
|
# parallelCallable =========================================================
|
|
328
362
|
ingredientsParallel.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
@@ -330,20 +364,20 @@ def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
|
330
364
|
|
|
331
365
|
# NOTE I am dissatisfied with this logic for many reasons, including that it requires separate NodeCollector and NodeReplacer instances.
|
|
332
366
|
astCallConcurrencyResult: list[ast.Call] = []
|
|
333
|
-
get_astCallConcurrencyResult
|
|
367
|
+
get_astCallConcurrencyResult = NodeTourist(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)), getIt(astCallConcurrencyResult))
|
|
334
368
|
get_astCallConcurrencyResult.visit(ingredientsDispatcher.astFunctionDef)
|
|
335
|
-
replaceAssignParallelCallable = NodeChanger(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)),
|
|
369
|
+
replaceAssignParallelCallable = NodeChanger(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)), grab.valueAttribute(Then.replaceWith(astCallConcurrencyResult[0])))
|
|
336
370
|
replaceAssignParallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
337
371
|
changeReturnParallelCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.countingVariableName)))
|
|
338
372
|
ingredientsParallel.astFunctionDef.returns = shatteredDataclass.countingVariableAnnotation
|
|
339
373
|
|
|
340
|
-
unpack4parallelCallable = NodeChanger(ifThis.
|
|
374
|
+
unpack4parallelCallable = NodeChanger(ifThis.isAssignAndValueIs(ifThis.isCallAttributeNamespace_Identifier(numbaFlow.concurrencyManagerNamespace, numbaFlow.concurrencyManagerIdentifier)), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
341
375
|
|
|
342
376
|
unpack4parallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
343
377
|
replaceCall2concurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
344
378
|
changeReturnParallelCallable.visit(ingredientsParallel.astFunctionDef)
|
|
345
379
|
|
|
346
|
-
ingredientsParallel.astFunctionDef = Z0Z_lameFindReplace(ingredientsParallel.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
|
|
380
|
+
ingredientsParallel.astFunctionDef = Z0Z_lameFindReplace(ingredientsParallel.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
|
|
347
381
|
|
|
348
382
|
# numba decorators =========================================
|
|
349
383
|
ingredientsParallel = decorateCallableWithNumba(ingredientsParallel)
|
|
@@ -351,8 +385,15 @@ def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
|
351
385
|
|
|
352
386
|
# Module-level transformations ===========================================================
|
|
353
387
|
ingredientsModuleNumbaUnified = IngredientsModule(ingredientsFunction=listAllIngredientsFunctions, imports=LedgerOfImports(numbaFlow.source_astModule))
|
|
388
|
+
ingredientsModuleNumbaUnified.removeImportFromModule('numpy')
|
|
354
389
|
|
|
355
390
|
write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
|
|
356
391
|
|
|
392
|
+
def getIt(astCallConcurrencyResult: list[ast.Call]) -> Callable[[ast.AST], ast.AST]:
|
|
393
|
+
def workhorse(node: ast.AST) -> ast.AST:
|
|
394
|
+
NodeTourist(be.Call, Then.appendTo(astCallConcurrencyResult)).visit(node)
|
|
395
|
+
return node
|
|
396
|
+
return workhorse
|
|
397
|
+
|
|
357
398
|
if __name__ == '__main__':
|
|
358
399
|
makeNumbaFlow(theNumbaFlow)
|