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.
Files changed (34) hide show
  1. mapFolding/__init__.py +60 -13
  2. mapFolding/basecamp.py +32 -17
  3. mapFolding/beDRY.py +4 -5
  4. mapFolding/oeis.py +94 -7
  5. mapFolding/someAssemblyRequired/RecipeJob.py +103 -0
  6. mapFolding/someAssemblyRequired/__init__.py +71 -50
  7. mapFolding/someAssemblyRequired/_theTypes.py +11 -15
  8. mapFolding/someAssemblyRequired/_tool_Make.py +36 -9
  9. mapFolding/someAssemblyRequired/_tool_Then.py +59 -25
  10. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +159 -272
  11. mapFolding/someAssemblyRequired/_toolboxContainers.py +155 -70
  12. mapFolding/someAssemblyRequired/_toolboxPython.py +168 -44
  13. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +154 -39
  14. mapFolding/someAssemblyRequired/toolboxNumba.py +72 -230
  15. mapFolding/someAssemblyRequired/transformationTools.py +370 -141
  16. mapFolding/syntheticModules/{numbaCount_doTheNeedful.py → numbaCount.py} +7 -4
  17. mapFolding/theDao.py +19 -16
  18. mapFolding/theSSOT.py +165 -62
  19. mapFolding/toolboxFilesystem.py +1 -1
  20. mapfolding-0.9.1.dist-info/METADATA +177 -0
  21. mapfolding-0.9.1.dist-info/RECORD +47 -0
  22. tests/__init__.py +44 -0
  23. tests/conftest.py +75 -7
  24. tests/test_computations.py +92 -10
  25. tests/test_filesystem.py +32 -33
  26. tests/test_other.py +0 -1
  27. tests/test_tasks.py +1 -1
  28. mapFolding/someAssemblyRequired/newInliner.py +0 -22
  29. mapfolding-0.8.6.dist-info/METADATA +0 -190
  30. mapfolding-0.8.6.dist-info/RECORD +0 -47
  31. {mapfolding-0.8.6.dist-info → mapfolding-0.9.1.dist-info}/WHEEL +0 -0
  32. {mapfolding-0.8.6.dist-info → mapfolding-0.9.1.dist-info}/entry_points.txt +0 -0
  33. {mapfolding-0.8.6.dist-info → mapfolding-0.9.1.dist-info}/licenses/LICENSE +0 -0
  34. {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 ingredients for optimized code generation.
2
+ Numba-specific Tools for Generating Optimized Code
3
3
 
4
- This module provides specialized tools, constants, and types specifically designed
5
- for transforming Python code into Numba-accelerated implementations. It implements:
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. A range of Numba jit decorator configurations for different optimization scenarios
8
- 2. Functions to identify and manipulate Numba decorators in abstract syntax trees
9
- 3. Utilities for applying appropriate Numba typing to transformed code
10
- 4. Parameter management for Numba compilation options
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 configurations range from conservative options that prioritize compatibility and
13
- error detection to aggressive optimizations that maximize performance at the cost of
14
- flexibility. While this module specifically targets Numba, its design follows the pattern
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.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, 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 pathlib import Path, PurePosixPath
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: # type: ignore
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 = parametersNumbaDefault
154
+ parametersNumba: ParametersNumba = dataclasses.field(default_factory=ParametersNumba) # type: ignore
160
155
 
161
- @dataclasses.dataclass
162
- class RecipeJob:
163
- state: ComputationState
164
- # TODO create function to calculate `foldsTotalEstimated`
165
- foldsTotalEstimated: int = 0
166
- shatteredDataclass: ShatteredDataclass = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
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
- # TODO a tool to automatically remove unused variables from the ArgumentsSpecification (return, and returns) _might_ be nice.
258
- # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
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
- # numba decorators =========================================
355
- ingredientsParallel = decorateCallableWithNumba(ingredientsParallel)
356
- ingredientsSequential = decorateCallableWithNumba(ingredientsSequential)
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
- # Module-level transformations ===========================================================
359
- ingredientsModuleNumbaUnified = IngredientsModule(ingredientsFunction=listAllIngredientsFunctions, imports=LedgerOfImports(numbaFlow.source_astModule))
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)