mapFolding 0.12.1__py3-none-any.whl → 0.12.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. mapFolding/__init__.py +42 -18
  2. mapFolding/_theSSOT.py +137 -0
  3. mapFolding/basecamp.py +28 -18
  4. mapFolding/beDRY.py +21 -19
  5. mapFolding/dataBaskets.py +170 -18
  6. mapFolding/datatypes.py +109 -1
  7. mapFolding/filesystemToolkit.py +38 -33
  8. mapFolding/oeis.py +209 -93
  9. mapFolding/someAssemblyRequired/RecipeJob.py +120 -9
  10. mapFolding/someAssemblyRequired/__init__.py +35 -38
  11. mapFolding/someAssemblyRequired/_toolIfThis.py +78 -16
  12. mapFolding/someAssemblyRequired/_toolkitContainers.py +121 -43
  13. mapFolding/someAssemblyRequired/infoBooth.py +37 -2
  14. mapFolding/someAssemblyRequired/makeAllModules.py +712 -0
  15. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +102 -39
  16. mapFolding/someAssemblyRequired/toolkitNumba.py +171 -19
  17. mapFolding/someAssemblyRequired/transformationTools.py +84 -40
  18. mapfolding-0.12.2.dist-info/METADATA +167 -0
  19. mapfolding-0.12.2.dist-info/RECORD +53 -0
  20. {mapfolding-0.12.1.dist-info → mapfolding-0.12.2.dist-info}/WHEEL +1 -1
  21. tests/__init__.py +28 -44
  22. tests/conftest.py +66 -61
  23. tests/test_computations.py +39 -82
  24. tests/test_filesystem.py +25 -1
  25. tests/test_oeis.py +30 -1
  26. tests/test_other.py +27 -0
  27. tests/test_tasks.py +31 -1
  28. mapFolding/someAssemblyRequired/Z0Z_makeAllModules.py +0 -433
  29. mapFolding/theSSOT.py +0 -34
  30. mapfolding-0.12.1.dist-info/METADATA +0 -184
  31. mapfolding-0.12.1.dist-info/RECORD +0 -53
  32. {mapfolding-0.12.1.dist-info → mapfolding-0.12.2.dist-info}/entry_points.txt +0 -0
  33. {mapfolding-0.12.1.dist-info → mapfolding-0.12.2.dist-info}/licenses/LICENSE +0 -0
  34. {mapfolding-0.12.1.dist-info → mapfolding-0.12.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,712 @@
1
+ """
2
+ Map folding AST transformation system: Comprehensive transformation orchestration and module generation.
3
+
4
+ This module provides the orchestration layer of the map folding AST transformation system,
5
+ implementing comprehensive tools that coordinate all transformation stages to generate optimized
6
+ implementations with diverse computational strategies and performance characteristics. Building
7
+ upon the foundational pattern recognition, structural decomposition, core transformation tools,
8
+ Numba integration, and configuration management established in previous layers, this module
9
+ executes complete transformation processes that convert high-level dataclass-based algorithms
10
+ into specialized variants optimized for specific execution contexts.
11
+
12
+ The transformation orchestration addresses the full spectrum of optimization requirements for
13
+ map folding computational research through systematic application of the complete transformation
14
+ toolkit. The comprehensive approach decomposes dataclass parameters into primitive values for
15
+ Numba compatibility while removing object-oriented overhead and preserving computational logic,
16
+ generates concurrent execution variants using ProcessPoolExecutor with task division and result
17
+ aggregation, creates dedicated modules for counting variable setup with transformed loop conditions,
18
+ and provides theorem-specific transformations with configurable optimization levels including
19
+ trimmed variants and Numba-accelerated implementations.
20
+
21
+ The orchestration process operates through systematic AST manipulation that analyzes source
22
+ algorithms to extract dataclass dependencies, transforms data access patterns, applies performance
23
+ optimizations, and generates specialized modules with consistent naming conventions and filesystem
24
+ organization. The comprehensive transformation process coordinates pattern recognition for structural
25
+ analysis, dataclass decomposition for parameter optimization, function transformation for signature
26
+ adaptation, Numba integration for compilation optimization, and configuration management for
27
+ systematic generation control.
28
+
29
+ Generated modules maintain algorithmic correctness while providing significant performance
30
+ improvements through just-in-time compilation, parallel execution, and optimized data structures
31
+ tailored for specific computational requirements essential to large-scale map folding research.
32
+ """
33
+
34
+ from astToolkit import (
35
+ astModuleToIngredientsFunction, Be, ClassIsAndAttribute, DOT, extractClassDef, extractFunctionDef,
36
+ Grab, identifierDotAttribute, IngredientsFunction, IngredientsModule, LedgerOfImports, Make,
37
+ NodeChanger, NodeTourist, parseLogicalPath2astModule, parsePathFilename2astModule, Then,
38
+ )
39
+ from astToolkit.transformationTools import (
40
+ inlineFunctionDef, removeUnusedParameters, write_astModule,
41
+ )
42
+ from collections.abc import Sequence
43
+ from mapFolding import packageSettings
44
+ from mapFolding.someAssemblyRequired import (
45
+ DeReConstructField2ast, IfThis, ShatteredDataclass, sourceCallableDispatcherDEFAULT,
46
+ )
47
+ from mapFolding.someAssemblyRequired.infoBooth import (
48
+ algorithmSourceModuleDEFAULT, dataPackingModuleIdentifierDEFAULT, logicalPathInfixDEFAULT,
49
+ sourceCallableIdentifierDEFAULT, theCountingIdentifierDEFAULT,
50
+ )
51
+ from mapFolding.someAssemblyRequired.toolkitNumba import (
52
+ decorateCallableWithNumba, parametersNumbaLight,
53
+ )
54
+ from mapFolding.someAssemblyRequired.transformationTools import (
55
+ removeDataclassFromFunction, shatter_dataclassesDOTdataclass,
56
+ unpackDataclassCallFunctionRepackDataclass,
57
+ )
58
+ from os import PathLike
59
+ from pathlib import PurePath
60
+ from typing import Any, cast
61
+ from Z0Z_tools import importLogicalPath2Callable, raiseIfNone
62
+ import ast
63
+ import dataclasses
64
+
65
+ def findDataclass(ingredientsFunction: IngredientsFunction) -> tuple[str, str, str]:
66
+ """
67
+ Extract dataclass information from a function's AST for transformation operations.
68
+
69
+ Analyzes the first parameter of a function to identify the dataclass type annotation
70
+ and instance identifier, then locates the module where the dataclass is defined by
71
+ examining the function's import statements. This information is essential for
72
+ dataclass decomposition and transformation operations.
73
+
74
+ Parameters:
75
+ ingredientsFunction: Function container with AST and import information
76
+
77
+ Returns:
78
+ dataclassLogicalPathModule: Module logical path where the dataclass is defined
79
+ dataclassIdentifier: Class name of the dataclass
80
+ dataclassInstanceIdentifier: Parameter name for the dataclass instance
81
+
82
+ Raises:
83
+ ValueError: If dataclass information cannot be extracted from the function
84
+ """
85
+
86
+ dataclassName: ast.expr = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.annotation)).captureLastMatch(ingredientsFunction.astFunctionDef))
87
+ dataclassIdentifier: str = raiseIfNone(NodeTourist(Be.Name, Then.extractIt(DOT.id)).captureLastMatch(dataclassName))
88
+ dataclassLogicalPathModule = None
89
+ for moduleWithLogicalPath, listNameTuples in ingredientsFunction.imports._dictionaryImportFrom.items():
90
+ for nameTuple in listNameTuples:
91
+ if nameTuple[0] == dataclassIdentifier:
92
+ dataclassLogicalPathModule = moduleWithLogicalPath
93
+ break
94
+ if dataclassLogicalPathModule:
95
+ break
96
+ dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
97
+ return raiseIfNone(dataclassLogicalPathModule), dataclassIdentifier, dataclassInstanceIdentifier
98
+
99
+ def _getLogicalPath(packageName: str | None = None, logicalPathInfix: str | None = None, moduleIdentifier: str | None = None, *modules: str) -> identifierDotAttribute:
100
+ """
101
+ Construct logical module path by joining package and module components.
102
+
103
+ Builds a dot-separated logical path string from optional package name, infix path
104
+ components, and module identifiers. This standardizes module path construction
105
+ across the code generation system and ensures consistent naming conventions.
106
+
107
+ Parameters:
108
+ packageName: Root package name for the logical path
109
+ logicalPathInfix: Middle path component (typically 'syntheticModules')
110
+ moduleIdentifier: Primary module identifier
111
+ *modules: Additional module path components to append
112
+
113
+ Returns:
114
+ logicalPath: Dot-separated logical path string suitable for module import operations
115
+ """
116
+
117
+ listLogicalPathParts: list[str] = []
118
+ if packageName:
119
+ listLogicalPathParts.append(packageName)
120
+ if logicalPathInfix:
121
+ listLogicalPathParts.append(logicalPathInfix)
122
+ if moduleIdentifier:
123
+ listLogicalPathParts.append(moduleIdentifier)
124
+ if modules:
125
+ listLogicalPathParts.extend(modules)
126
+ logicalPath = '.'.join(listLogicalPathParts)
127
+ return logicalPath
128
+
129
+ def getModule(packageName: str | None = packageSettings.packageName, logicalPathInfix: str | None = logicalPathInfixDEFAULT, moduleIdentifier: str | None = algorithmSourceModuleDEFAULT) -> ast.Module:
130
+ """
131
+ Load source algorithm module as AST for transformation operations.
132
+
133
+ Retrieves the specified module and parses it into an AST representation that can
134
+ be manipulated by the transformation tools. This provides the foundation for all
135
+ code generation operations by making the source algorithms available for analysis
136
+ and modification.
137
+
138
+ Parameters:
139
+ packageName: Package containing the source module
140
+ logicalPathInfix: Path component within the package structure
141
+ moduleIdentifier: Specific module containing the algorithms
142
+
143
+ Returns:
144
+ astModule: AST module representation ready for transformation operations
145
+ """
146
+
147
+ logicalPathSourceModule: identifierDotAttribute = _getLogicalPath(packageName, logicalPathInfix, moduleIdentifier)
148
+ astModule: ast.Module = parseLogicalPath2astModule(logicalPathSourceModule)
149
+ return astModule
150
+
151
+ def _getPathFilename(pathRoot: PathLike[str] | PurePath | None = packageSettings.pathPackage, logicalPathInfix: PathLike[str] | PurePath | str | None = None, moduleIdentifier: str = '', fileExtension: str = packageSettings.fileExtension) -> PurePath:
152
+ """
153
+ Construct filesystem path for generated module files.
154
+
155
+ Builds the complete filesystem path where generated modules will be written,
156
+ combining root path, optional infix directory, module name, and file extension.
157
+ This ensures consistent file organization across all generated code.
158
+
159
+ Parameters:
160
+ pathRoot: Base directory for the package structure
161
+ logicalPathInfix: Subdirectory for organizing generated modules
162
+ moduleIdentifier: Name of the specific module file
163
+ fileExtension: File extension for Python modules
164
+
165
+ Returns:
166
+ pathFilename: Complete filesystem path for the generated module file
167
+ """
168
+
169
+ pathFilename = PurePath(moduleIdentifier + fileExtension)
170
+ if logicalPathInfix:
171
+ pathFilename = PurePath(logicalPathInfix, pathFilename)
172
+ if pathRoot:
173
+ pathFilename = PurePath(pathRoot, pathFilename)
174
+ return pathFilename
175
+
176
+ def makeInitializeGroupsOfFolds(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
177
+ """
178
+ Generate initialization module for counting variable setup.
179
+
180
+ Creates a specialized module containing initialization logic for the counting variables
181
+ used in map folding computations. The generated function transforms the original
182
+ algorithm's loop conditions to use equality comparisons instead of greater-than
183
+ comparisons, optimizing the initialization phase.
184
+
185
+ This transformation is particularly important for ensuring that counting variables
186
+ are properly initialized before the main computational loops begin executing.
187
+
188
+ Parameters:
189
+ astModule: Source module containing the base algorithm
190
+ moduleIdentifier: Name for the generated initialization module
191
+ callableIdentifier: Name for the initialization function
192
+ logicalPathInfix: Directory path for organizing the generated module
193
+ sourceCallableDispatcher: Optional dispatcher function identifier
194
+
195
+ Returns:
196
+ pathFilename: Filesystem path where the initialization module was written
197
+ """
198
+
199
+ sourceCallableIdentifier: identifierDotAttribute = sourceCallableIdentifierDEFAULT
200
+ if callableIdentifier is None:
201
+ callableIdentifier = sourceCallableIdentifier
202
+ ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
203
+ ingredientsFunction.astFunctionDef.name = callableIdentifier
204
+
205
+ dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
206
+ theCountingIdentifier: identifierDotAttribute = theCountingIdentifierDEFAULT
207
+
208
+ findThis = IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
209
+ doThat = Grab.testAttribute(Grab.andDoAllOf([Grab.opsAttribute(Then.replaceWith([ast.Eq()])), Grab.leftAttribute(Grab.attrAttribute(Then.replaceWith(theCountingIdentifier)))])) # pyright: ignore[reportArgumentType]
210
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef.body[0])
211
+
212
+ ingredientsModule = IngredientsModule(ingredientsFunction)
213
+ pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
214
+ write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
215
+
216
+ return pathFilename
217
+
218
+ def makeDaoOfMapFolding(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
219
+ """
220
+ Generate Numba-optimized sequential implementation of map folding algorithm.
221
+
222
+ Creates a high-performance sequential version of the map folding algorithm by:
223
+ 1. Decomposing dataclass parameters into individual primitive values
224
+ 2. Removing dataclass dependencies that are incompatible with Numba
225
+ 3. Applying Numba decorators for just-in-time compilation
226
+ 4. Optionally including a dispatcher function for dataclass integration
227
+
228
+ The generated module provides significant performance improvements over the
229
+ original dataclass-based implementation while maintaining algorithmic correctness.
230
+ The transformation preserves all computational logic while restructuring data
231
+ access patterns for optimal Numba compilation.
232
+
233
+ Parameters:
234
+ astModule: Source module containing the base algorithm
235
+ moduleIdentifier: Name for the generated optimized module
236
+ callableIdentifier: Name for the main computational function
237
+ logicalPathInfix: Directory path for organizing the generated module
238
+ sourceCallableDispatcher: Optional dispatcher function for dataclass integration
239
+
240
+ Returns:
241
+ pathFilename: Filesystem path where the optimized module was written
242
+ """
243
+
244
+ sourceCallableIdentifier: identifierDotAttribute = sourceCallableIdentifierDEFAULT
245
+ ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
246
+
247
+ if callableIdentifier is None:
248
+ callableIdentifier = sourceCallableIdentifier
249
+ ingredientsFunction.astFunctionDef.name = callableIdentifier
250
+
251
+ shatteredDataclass: ShatteredDataclass = shatter_dataclassesDOTdataclass(*findDataclass(ingredientsFunction))
252
+
253
+ ingredientsFunction.imports.update(shatteredDataclass.imports)
254
+ ingredientsFunction: IngredientsFunction = removeDataclassFromFunction(ingredientsFunction, shatteredDataclass)
255
+ ingredientsFunction = removeUnusedParameters(ingredientsFunction)
256
+ ingredientsFunction = decorateCallableWithNumba(ingredientsFunction, parametersNumbaLight)
257
+
258
+ ingredientsModule = IngredientsModule(ingredientsFunction)
259
+
260
+ if sourceCallableDispatcher is not None:
261
+
262
+ ingredientsFunctionDispatcher: IngredientsFunction = astModuleToIngredientsFunction(astModule, sourceCallableDispatcher)
263
+ ingredientsFunctionDispatcher.imports.update(shatteredDataclass.imports)
264
+ targetCallableIdentifier = ingredientsFunction.astFunctionDef.name
265
+ ingredientsFunctionDispatcher = unpackDataclassCallFunctionRepackDataclass(ingredientsFunctionDispatcher, targetCallableIdentifier, shatteredDataclass)
266
+ astTuple: ast.expr = raiseIfNone(NodeTourist(Be.Return, Then.extractIt(DOT.value)).captureLastMatch(ingredientsFunction.astFunctionDef))
267
+ cast(ast.Tuple, astTuple).ctx = ast.Store()
268
+
269
+ findThis = ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCallIdentifier(targetCallableIdentifier))
270
+ doThat = Then.replaceWith(Make.Assign([astTuple], value=Make.Call(Make.Name(targetCallableIdentifier), cast(ast.Tuple, astTuple).elts)))
271
+ changeAssignCallToTarget = NodeChanger(findThis, doThat)
272
+ changeAssignCallToTarget.visit(ingredientsFunctionDispatcher.astFunctionDef)
273
+
274
+ ingredientsModule.appendIngredientsFunction(ingredientsFunctionDispatcher)
275
+
276
+ ingredientsModule.removeImportFromModule('numpy')
277
+
278
+ pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
279
+
280
+ write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
281
+
282
+ return pathFilename
283
+
284
+ def makeDaoOfMapFoldingParallel(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
285
+ """
286
+ Generate parallel implementation with concurrent execution and task division.
287
+
288
+ Creates a parallel processing version of the map folding algorithm that distributes
289
+ computational work across multiple processes using ProcessPoolExecutor. The
290
+ implementation includes:
291
+
292
+ 1. Dataclass decomposition for both base and parallel state fields
293
+ 2. Task division logic that partitions work based on leaf indices
294
+ 3. Concurrent execution management with future objects
295
+ 4. Result aggregation from multiple parallel computations
296
+ 5. Numba optimization for the core computational kernels
297
+
298
+ The generated module contains multiple functions:
299
+ - Core counting function with parallel-aware task filtering
300
+ - Dataclass unpacking/repacking function for process communication
301
+ - Main dispatcher function that manages the parallel execution pipeline
302
+
303
+ Parameters:
304
+ astModule: Source module containing the base algorithm
305
+ moduleIdentifier: Name for the generated parallel module
306
+ callableIdentifier: Name for the core parallel counting function
307
+ logicalPathInfix: Directory path for organizing the generated module
308
+ sourceCallableDispatcher: Optional dispatcher function identifier
309
+
310
+ Returns:
311
+ pathFilename: Filesystem path where the parallel module was written
312
+ """
313
+
314
+ sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
315
+ if callableIdentifier is None:
316
+ callableIdentifier = sourceCallableIdentifier
317
+ ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
318
+ ingredientsFunction.astFunctionDef.name = callableIdentifier
319
+
320
+ dataclassName: ast.expr = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.annotation)).captureLastMatch(ingredientsFunction.astFunctionDef))
321
+ dataclassIdentifier: str = raiseIfNone(NodeTourist(Be.Name, Then.extractIt(DOT.id)).captureLastMatch(dataclassName))
322
+
323
+ dataclassLogicalPathModule = None
324
+ for moduleWithLogicalPath, listNameTuples in ingredientsFunction.imports._dictionaryImportFrom.items():
325
+ for nameTuple in listNameTuples:
326
+ if nameTuple[0] == dataclassIdentifier:
327
+ dataclassLogicalPathModule = moduleWithLogicalPath
328
+ break
329
+ if dataclassLogicalPathModule:
330
+ break
331
+ if dataclassLogicalPathModule is None:
332
+ raise Exception
333
+ dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
334
+ shatteredDataclass: ShatteredDataclass = shatter_dataclassesDOTdataclass(dataclassLogicalPathModule, dataclassIdentifier, dataclassInstanceIdentifier)
335
+
336
+ # Start add the parallel state fields to the count function ================================================
337
+ dataclassBaseFields: tuple[dataclasses.Field[Any], ...] = dataclasses.fields(importLogicalPath2Callable(dataclassLogicalPathModule, dataclassIdentifier)) # pyright: ignore [reportArgumentType]
338
+ dataclassIdentifierParallel: identifierDotAttribute = 'Parallel' + dataclassIdentifier
339
+ dataclassFieldsParallel: tuple[dataclasses.Field[Any], ...] = dataclasses.fields(importLogicalPath2Callable(dataclassLogicalPathModule, dataclassIdentifierParallel)) # pyright: ignore [reportArgumentType]
340
+ onlyParallelFields: list[dataclasses.Field[Any]] = [field for field in dataclassFieldsParallel if field.name not in [fieldBase.name for fieldBase in dataclassBaseFields]]
341
+
342
+ Official_fieldOrder: list[str] = []
343
+ dictionaryDeReConstruction: dict[str, DeReConstructField2ast] = {}
344
+
345
+ dataclassClassDef: ast.ClassDef | None = extractClassDef(parseLogicalPath2astModule(dataclassLogicalPathModule), dataclassIdentifierParallel)
346
+ if not isinstance(dataclassClassDef, ast.ClassDef):
347
+ raise ValueError(f"I could not find `{dataclassIdentifierParallel = }` in `{dataclassLogicalPathModule = }`.")
348
+
349
+ for aField in onlyParallelFields:
350
+ Official_fieldOrder.append(aField.name)
351
+ dictionaryDeReConstruction[aField.name] = DeReConstructField2ast(dataclassLogicalPathModule, dataclassClassDef, dataclassInstanceIdentifier, aField)
352
+
353
+ shatteredDataclassParallel = ShatteredDataclass(
354
+ countingVariableAnnotation=shatteredDataclass.countingVariableAnnotation,
355
+ countingVariableName=shatteredDataclass.countingVariableName,
356
+ field2AnnAssign={**shatteredDataclass.field2AnnAssign, **{dictionaryDeReConstruction[field].name: dictionaryDeReConstruction[field].astAnnAssignConstructor for field in Official_fieldOrder}},
357
+ Z0Z_field2AnnAssign={**shatteredDataclass.Z0Z_field2AnnAssign, **{dictionaryDeReConstruction[field].name: dictionaryDeReConstruction[field].Z0Z_hack for field in Official_fieldOrder}},
358
+ list_argAnnotated4ArgumentsSpecification=shatteredDataclass.list_argAnnotated4ArgumentsSpecification + [dictionaryDeReConstruction[field].ast_argAnnotated for field in Official_fieldOrder],
359
+ list_keyword_field__field4init=shatteredDataclass.list_keyword_field__field4init + [dictionaryDeReConstruction[field].ast_keyword_field__field for field in Official_fieldOrder if dictionaryDeReConstruction[field].init],
360
+ listAnnotations=shatteredDataclass.listAnnotations + [dictionaryDeReConstruction[field].astAnnotation for field in Official_fieldOrder],
361
+ listName4Parameters=shatteredDataclass.listName4Parameters + [dictionaryDeReConstruction[field].astName for field in Official_fieldOrder],
362
+ listUnpack=shatteredDataclass.listUnpack + [Make.AnnAssign(dictionaryDeReConstruction[field].astName, dictionaryDeReConstruction[field].astAnnotation, dictionaryDeReConstruction[field].ast_nameDOTname) for field in Official_fieldOrder],
363
+ map_stateDOTfield2Name={**shatteredDataclass.map_stateDOTfield2Name, **{dictionaryDeReConstruction[field].ast_nameDOTname: dictionaryDeReConstruction[field].astName for field in Official_fieldOrder}},
364
+ )
365
+ shatteredDataclassParallel.fragments4AssignmentOrParameters = Make.Tuple(shatteredDataclassParallel.listName4Parameters, ast.Store())
366
+ shatteredDataclassParallel.repack = Make.Assign([Make.Name(dataclassInstanceIdentifier)], value=Make.Call(Make.Name(dataclassIdentifierParallel), list_keyword=shatteredDataclassParallel.list_keyword_field__field4init))
367
+ shatteredDataclassParallel.signatureReturnAnnotation = Make.Subscript(Make.Name('tuple'), Make.Tuple(shatteredDataclassParallel.listAnnotations))
368
+
369
+ shatteredDataclassParallel.imports.update(*(dictionaryDeReConstruction[field].ledger for field in Official_fieldOrder))
370
+ shatteredDataclassParallel.imports.addImportFrom_asStr(dataclassLogicalPathModule, dataclassIdentifierParallel)
371
+ shatteredDataclassParallel.imports.update(shatteredDataclass.imports)
372
+ shatteredDataclassParallel.imports.removeImportFrom(dataclassLogicalPathModule, dataclassIdentifier)
373
+
374
+ # End add the parallel state fields to the count function ================================================
375
+
376
+ ingredientsFunction.imports.update(shatteredDataclassParallel.imports)
377
+ ingredientsFunction: IngredientsFunction = removeDataclassFromFunction(ingredientsFunction, shatteredDataclassParallel)
378
+
379
+ # Start add the parallel logic to the count function ================================================
380
+
381
+ findThis = ClassIsAndAttribute.testIs(ast.While, ClassIsAndAttribute.leftIs(ast.Compare, IfThis.isNameIdentifier('leafConnectee')))
382
+ doThat = Then.extractIt(DOT.body)
383
+ captureCountGapsCodeBlock: NodeTourist[ast.While, Sequence[ast.stmt]] = NodeTourist(findThis, doThat)
384
+ countGapsCodeBlock: Sequence[ast.stmt] = raiseIfNone(captureCountGapsCodeBlock.captureLastMatch(ingredientsFunction.astFunctionDef))
385
+
386
+ thisIsMyTaskIndexCodeBlock = ast.If(ast.BoolOp(ast.Or()
387
+ , values=[ast.Compare(ast.Name('leaf1ndex'), ops=[ast.NotEq()], comparators=[ast.Name('taskDivisions')])
388
+ , ast.Compare(Make.Mod.join([ast.Name('leafConnectee'), ast.Name('taskDivisions')]), ops=[ast.Eq()], comparators=[ast.Name('taskIndex')])])
389
+ , body=list(countGapsCodeBlock[0:-1]))
390
+
391
+ countGapsCodeBlockNew: list[ast.stmt] = [thisIsMyTaskIndexCodeBlock, countGapsCodeBlock[-1]]
392
+
393
+ doThat = Grab.bodyAttribute(Then.replaceWith(countGapsCodeBlockNew))
394
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
395
+
396
+ # End add the parallel logic to the count function ================================================
397
+
398
+ ingredientsFunction = removeUnusedParameters(ingredientsFunction)
399
+
400
+ ingredientsFunction = decorateCallableWithNumba(ingredientsFunction, parametersNumbaLight)
401
+
402
+ # Start unpack/repack the dataclass function ================================================
403
+ sourceCallableIdentifier = sourceCallableDispatcherDEFAULT
404
+
405
+ unRepackDataclass: IngredientsFunction = astModuleToIngredientsFunction(astModule, sourceCallableIdentifier)
406
+ unRepackDataclass.astFunctionDef.name = 'unRepack' + dataclassIdentifierParallel
407
+ unRepackDataclass.imports.update(shatteredDataclassParallel.imports)
408
+ findThis = ClassIsAndAttribute.annotationIs(ast.arg, IfThis.isNameIdentifier(dataclassIdentifier))
409
+ doThat = Grab.annotationAttribute(Grab.idAttribute(Then.replaceWith(dataclassIdentifierParallel))) # pyright: ignore[reportArgumentType]
410
+ NodeChanger(findThis, doThat).visit(unRepackDataclass.astFunctionDef)
411
+ unRepackDataclass.astFunctionDef.returns = Make.Name(dataclassIdentifierParallel)
412
+ targetCallableIdentifier: identifierDotAttribute = ingredientsFunction.astFunctionDef.name
413
+ unRepackDataclass = unpackDataclassCallFunctionRepackDataclass(unRepackDataclass, targetCallableIdentifier, shatteredDataclassParallel)
414
+
415
+ astTuple: ast.expr = raiseIfNone(NodeTourist(Be.Return, Then.extractIt(DOT.value)).captureLastMatch(ingredientsFunction.astFunctionDef))
416
+ cast(ast.Tuple, astTuple).ctx = ast.Store()
417
+ findThis = ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCallIdentifier(targetCallableIdentifier))
418
+ doThat = Then.replaceWith(Make.Assign([astTuple], value=Make.Call(Make.Name(targetCallableIdentifier), cast(ast.Tuple, astTuple).elts)))
419
+ changeAssignCallToTarget = NodeChanger(findThis, doThat)
420
+ changeAssignCallToTarget.visit(unRepackDataclass.astFunctionDef)
421
+
422
+ ingredientsDoTheNeedful: IngredientsFunction = IngredientsFunction(
423
+ astFunctionDef = Make.FunctionDef('doTheNeedful'
424
+ , argumentSpecification=Make.arguments(list_arg=[Make.arg('state', annotation=Make.Name(dataclassIdentifierParallel)), Make.arg('concurrencyLimit', annotation=Make.Name('int'))])
425
+ , body=[Make.Assign([Make.Name('stateParallel', ast.Store())], value=Make.Call(Make.Name('deepcopy'), listParameters=[Make.Name('state')]))
426
+ , Make.AnnAssign(Make.Name('listStatesParallel', ast.Store()), annotation=Make.Subscript(value=Make.Name('list'), slice=Make.Name(dataclassIdentifierParallel))
427
+ , value=Make.Mult.join([Make.List([Make.Name('stateParallel')]), Make.Attribute(Make.Name('stateParallel'), 'taskDivisions')]))
428
+ , Make.AnnAssign(Make.Name('groupsOfFoldsTotal', ast.Store()), annotation=Make.Name('int'), value=Make.Constant(value=0))
429
+
430
+ , Make.AnnAssign(Make.Name('dictionaryConcurrency', ast.Store()), annotation=Make.Subscript(value=Make.Name('dict'), slice=Make.Tuple([Make.Name('int'), Make.Subscript(value=Make.Name('ConcurrentFuture'), slice=Make.Name(dataclassIdentifierParallel))])), value=Make.Dict())
431
+ , Make.With(items=[Make.withitem(context_expr=Make.Call(Make.Name('ProcessPoolExecutor'), listParameters=[Make.Name('concurrencyLimit')]), optional_vars=Make.Name('concurrencyManager', ast.Store()))]
432
+ , body=[Make.For(Make.Name('indexSherpa', ast.Store()), iter=Make.Call(Make.Name('range'), listParameters=[Make.Attribute(Make.Name('stateParallel'), 'taskDivisions')])
433
+ , body=[Make.Assign([Make.Name('state', ast.Store())], value=Make.Call(Make.Name('deepcopy'), listParameters=[Make.Name('stateParallel')]))
434
+ , Make.Assign([Make.Attribute(Make.Name('state'), 'taskIndex', context=ast.Store())], value=Make.Name('indexSherpa'))
435
+ , Make.Assign([Make.Subscript(Make.Name('dictionaryConcurrency'), slice=Make.Name('indexSherpa'), context=ast.Store())], value=Make.Call(Make.Attribute(Make.Name('concurrencyManager'), 'submit'), listParameters=[Make.Name(unRepackDataclass.astFunctionDef.name), Make.Name('state')]))])
436
+ , Make.For(Make.Name('indexSherpa', ast.Store()), iter=Make.Call(Make.Name('range'), listParameters=[Make.Attribute(Make.Name('stateParallel'), 'taskDivisions')])
437
+ , body=[Make.Assign([Make.Subscript(Make.Name('listStatesParallel'), slice=Make.Name('indexSherpa'), context=ast.Store())], value=Make.Call(Make.Attribute(Make.Subscript(Make.Name('dictionaryConcurrency'), slice=Make.Name('indexSherpa')), 'result')))
438
+ , Make.AugAssign(Make.Name('groupsOfFoldsTotal', ast.Store()), op=ast.Add(), value=Make.Attribute(Make.Subscript(Make.Name('listStatesParallel'), slice=Make.Name('indexSherpa')), 'groupsOfFolds'))])])
439
+
440
+ , Make.AnnAssign(Make.Name('foldsTotal', ast.Store()), annotation=Make.Name('int'), value=Make.Mult.join([Make.Name('groupsOfFoldsTotal'), Make.Attribute(Make.Name('stateParallel'), 'leavesTotal')]))
441
+ , Make.Return(Make.Tuple([Make.Name('foldsTotal'), Make.Name('listStatesParallel')]))]
442
+ , returns=Make.Subscript(Make.Name('tuple'), slice=Make.Tuple([Make.Name('int'), Make.Subscript(Make.Name('list'), slice=Make.Name(dataclassIdentifierParallel))])))
443
+ , imports = LedgerOfImports(Make.Module([Make.ImportFrom('concurrent.futures', list_alias=[Make.alias('Future', asName='ConcurrentFuture'), Make.alias('ProcessPoolExecutor')]),
444
+ Make.ImportFrom('copy', list_alias=[Make.alias('deepcopy')]),
445
+ Make.ImportFrom('multiprocessing', list_alias=[Make.alias('set_start_method', asName='multiprocessing_set_start_method')]),])
446
+ )
447
+ )
448
+
449
+ ingredientsModule = IngredientsModule([ingredientsFunction, unRepackDataclass, ingredientsDoTheNeedful]
450
+ , prologue = Make.Module([Make.If(test=Make.Compare(left=Make.Name('__name__'), ops=[Make.Eq()], comparators=[Make.Constant('__main__')]), body=[Make.Expr(Make.Call(Make.Name('multiprocessing_set_start_method'), listParameters=[Make.Constant('spawn')]))])])
451
+ )
452
+ ingredientsModule.removeImportFromModule('numpy')
453
+
454
+ pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
455
+
456
+ write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
457
+
458
+ return pathFilename
459
+
460
+ def makeTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
461
+ """
462
+ Generate optimized implementation applying Theorem 2 mathematical optimizations.
463
+
464
+ Creates a specialized version of the map folding algorithm that applies Theorem 2
465
+ optimizations for improved computational efficiency. The transformation includes:
466
+
467
+ 1. Modifying loop termination conditions from general cases to Theorem 2 specifics
468
+ 2. Restructuring conditional logic to eliminate unnecessary branch evaluations
469
+ 3. Adding count doubling operations to leverage mathematical properties
470
+ 4. Removing redundant computations that are not needed under Theorem 2 constraints
471
+
472
+ Theorem 2 provides mathematical guarantees that allow certain computational
473
+ shortcuts and optimizations that would not be valid in the general case. This
474
+ implementation capitalizes on those properties to achieve significant performance
475
+ improvements for maps that satisfy Theorem 2 conditions.
476
+
477
+ Parameters:
478
+ astModule: Source module containing the base algorithm
479
+ moduleIdentifier: Name for the generated theorem-optimized module
480
+ callableIdentifier: Name for the optimized computational function
481
+ logicalPathInfix: Directory path for organizing the generated module
482
+ sourceCallableDispatcher: Currently not implemented for this transformation
483
+
484
+ Returns:
485
+ pathFilename: Filesystem path where the theorem-optimized module was written
486
+
487
+ Raises:
488
+ NotImplementedError: If sourceCallableDispatcher is provided
489
+ """
490
+
491
+ sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
492
+ if callableIdentifier is None:
493
+ callableIdentifier = sourceCallableIdentifier
494
+ ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
495
+ ingredientsFunction.astFunctionDef.name = callableIdentifier
496
+
497
+ dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
498
+
499
+ findThis = IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
500
+ doThat = Grab.testAttribute(Grab.comparatorsAttribute(Then.replaceWith([Make.Constant(4)]))) # pyright: ignore[reportArgumentType]
501
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
502
+
503
+ findThis = IfThis.isIfAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
504
+ doThat = Then.extractIt(DOT.body)
505
+ insertLeaf: Sequence[ast.stmt] | None = NodeTourist(findThis, doThat).captureLastMatch(ingredientsFunction.astFunctionDef)
506
+ findThis = IfThis.isIfAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
507
+ doThat = Then.replaceWith(insertLeaf)
508
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
509
+
510
+ findThis = IfThis.isAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
511
+ doThat = Then.removeIt
512
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
513
+
514
+ findThis = IfThis.isAttributeNamespaceIdentifierLessThanOrEqual0(dataclassInstanceIdentifier, 'leaf1ndex')
515
+ doThat = Then.removeIt
516
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
517
+
518
+ theCountingIdentifier: identifierDotAttribute = theCountingIdentifierDEFAULT
519
+ doubleTheCount: ast.AugAssign = Make.AugAssign(Make.Attribute(ast.Name(dataclassInstanceIdentifier), theCountingIdentifier), ast.Mult(), Make.Constant(2))
520
+ findThis = Be.Return
521
+ doThat = Then.insertThisAbove([doubleTheCount])
522
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
523
+
524
+ ingredientsModule = IngredientsModule(ingredientsFunction)
525
+
526
+ if sourceCallableDispatcher is not None:
527
+ raise NotImplementedError('sourceCallableDispatcher is not implemented yet')
528
+
529
+ pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
530
+
531
+ write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
532
+
533
+ return pathFilename
534
+
535
+ def trimTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
536
+ """
537
+ Generate constrained Theorem 2 implementation by removing unnecessary logic.
538
+
539
+ Creates a trimmed version of the Theorem 2 implementation by eliminating
540
+ conditional logic that is not needed under specific constraint assumptions.
541
+ This transformation removes checks for unconstrained dimensions, simplifying
542
+ the algorithm for cases where dimensional constraints are guaranteed to be
543
+ satisfied by external conditions.
544
+
545
+ The trimming operation is particularly valuable for generating lean implementations
546
+ where the calling context ensures that certain conditions will always be met,
547
+ allowing the removal of defensive programming constructs that add computational
548
+ overhead without providing benefits in the constrained environment.
549
+
550
+ Parameters:
551
+ astModule: Source module containing the Theorem 2 implementation
552
+ moduleIdentifier: Name for the generated trimmed module
553
+ callableIdentifier: Name for the trimmed computational function
554
+ logicalPathInfix: Directory path for organizing the generated module
555
+ sourceCallableDispatcher: Optional dispatcher function identifier (unused)
556
+
557
+ Returns:
558
+ pathFilename: Filesystem path where the trimmed module was written
559
+ """
560
+
561
+ sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
562
+ if callableIdentifier is None:
563
+ callableIdentifier = sourceCallableIdentifier
564
+ ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
565
+ ingredientsFunction.astFunctionDef.name = callableIdentifier
566
+
567
+ dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
568
+
569
+ findThis = IfThis.isIfUnaryNotAttributeNamespaceIdentifier(dataclassInstanceIdentifier, 'dimensionsUnconstrained')
570
+ doThat = Then.removeIt
571
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
572
+
573
+ ingredientsModule = IngredientsModule(ingredientsFunction)
574
+ ingredientsModule.removeImportFromModule('numpy')
575
+
576
+ pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
577
+
578
+ write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
579
+
580
+ return pathFilename
581
+
582
+ def numbaOnTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
583
+ """
584
+ Generate Numba-accelerated Theorem 2 implementation with dataclass decomposition.
585
+
586
+ Creates a highly optimized version of the Theorem 2 algorithm by combining the
587
+ mathematical optimizations of Theorem 2 with Numba just-in-time compilation.
588
+ The transformation includes:
589
+
590
+ 1. Dataclass decomposition to convert structured parameters into primitives
591
+ 2. Removal of Python object dependencies incompatible with Numba
592
+ 3. Application of Numba decorators for maximum performance
593
+ 4. Type annotation optimization for efficient compilation
594
+
595
+ This represents the highest level of optimization available for Theorem 2
596
+ implementations, providing both mathematical efficiency through theorem
597
+ application and computational efficiency through Numba acceleration.
598
+ The result is suitable for production use in high-performance computing
599
+ environments where maximum speed is required.
600
+
601
+ Parameters:
602
+ astModule: Source module containing the Theorem 2 implementation
603
+ moduleIdentifier: Name for the generated Numba-accelerated module
604
+ callableIdentifier: Name for the accelerated computational function
605
+ logicalPathInfix: Directory path for organizing the generated module
606
+ sourceCallableDispatcher: Optional dispatcher function identifier (unused)
607
+
608
+ Returns:
609
+ Filesystem path where the accelerated module was written
610
+ """
611
+
612
+ sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
613
+ if callableIdentifier is None:
614
+ callableIdentifier = sourceCallableIdentifier
615
+ ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
616
+ ingredientsFunction.astFunctionDef.name = callableIdentifier
617
+
618
+ shatteredDataclass: ShatteredDataclass = shatter_dataclassesDOTdataclass(*findDataclass(ingredientsFunction))
619
+
620
+ ingredientsFunction.imports.update(shatteredDataclass.imports)
621
+ ingredientsFunction: IngredientsFunction = removeDataclassFromFunction(ingredientsFunction, shatteredDataclass)
622
+ ingredientsFunction = removeUnusedParameters(ingredientsFunction)
623
+ ingredientsFunction = decorateCallableWithNumba(ingredientsFunction, parametersNumbaLight)
624
+
625
+ ingredientsModule = IngredientsModule(ingredientsFunction)
626
+ ingredientsModule.removeImportFromModule('numpy')
627
+
628
+ pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
629
+
630
+ write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
631
+
632
+ return pathFilename
633
+
634
+ def makeUnRePackDataclass(astImportFrom: ast.ImportFrom) -> None:
635
+ """
636
+ Generate interface module for dataclass unpacking and repacking operations.
637
+
638
+ Creates a specialized module that serves as an interface between dataclass-based
639
+ calling code and optimized implementations that operate on decomposed primitive
640
+ values. The generated module includes:
641
+
642
+ 1. A function that unpacks dataclass instances into individual primitive values
643
+ 2. Calls to the specified optimized target function with decomposed parameters
644
+ 3. Repacking of results back into appropriate dataclass instances
645
+ 4. Import management for all required dependencies
646
+
647
+ This bridge module enables seamless integration between high-level dataclass-based
648
+ APIs and low-level optimized implementations, maintaining type safety and usability
649
+ while leveraging performance optimizations that require primitive value operations.
650
+
651
+ Parameters:
652
+ astImportFrom: Import statement specifying the target optimized function to call
653
+
654
+ Returns:
655
+ None: The generated module is written directly to the filesystem
656
+ """
657
+
658
+ callableIdentifierHARDCODED: str = 'sequential'
659
+
660
+ algorithmSourceModule: identifierDotAttribute = algorithmSourceModuleDEFAULT
661
+ sourceCallableIdentifier: identifierDotAttribute = sourceCallableDispatcherDEFAULT
662
+ logicalPathSourceModule: identifierDotAttribute = '.'.join([packageSettings.packageName, algorithmSourceModule])
663
+
664
+ logicalPathInfix: identifierDotAttribute = logicalPathInfixDEFAULT
665
+ moduleIdentifier: identifierDotAttribute = dataPackingModuleIdentifierDEFAULT
666
+ callableIdentifier: identifierDotAttribute = callableIdentifierHARDCODED
667
+
668
+ ingredientsFunction: IngredientsFunction = astModuleToIngredientsFunction(parseLogicalPath2astModule(logicalPathSourceModule), sourceCallableIdentifier)
669
+ ingredientsFunction.astFunctionDef.name = callableIdentifier
670
+
671
+ shatteredDataclass: ShatteredDataclass = shatter_dataclassesDOTdataclass(*findDataclass(ingredientsFunction))
672
+
673
+ ingredientsFunction.imports.update(shatteredDataclass.imports)
674
+ ingredientsFunction.imports.addAst(astImportFrom)
675
+ targetCallableIdentifier = astImportFrom.names[0].name
676
+ ingredientsFunction = raiseIfNone(unpackDataclassCallFunctionRepackDataclass(ingredientsFunction, targetCallableIdentifier, shatteredDataclass))
677
+ targetFunctionDef: ast.FunctionDef = raiseIfNone(extractFunctionDef(parseLogicalPath2astModule(raiseIfNone(astImportFrom.module)), targetCallableIdentifier))
678
+ astTuple: ast.expr = raiseIfNone(NodeTourist(Be.Return, Then.extractIt(DOT.value)).captureLastMatch(targetFunctionDef))
679
+ cast(ast.Tuple, astTuple).ctx = ast.Store()
680
+
681
+ findThis = ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCallIdentifier(targetCallableIdentifier))
682
+ doThat = Then.replaceWith(Make.Assign([astTuple], value=Make.Call(Make.Name(targetCallableIdentifier), cast(ast.Tuple, astTuple).elts)))
683
+ NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
684
+
685
+ ingredientsModule = IngredientsModule(ingredientsFunction)
686
+ ingredientsModule.removeImportFromModule('numpy')
687
+
688
+ pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
689
+
690
+ write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
691
+
692
+ if __name__ == '__main__':
693
+ astModule: ast.Module = getModule(logicalPathInfix=None)
694
+ makeInitializeGroupsOfFolds(astModule, 'initializeCount', 'initializeGroupsOfFolds', logicalPathInfixDEFAULT)
695
+
696
+ astModule = getModule(logicalPathInfix=None)
697
+ pathFilename: PurePath = makeDaoOfMapFolding(astModule, 'daoOfMapFolding', None, logicalPathInfixDEFAULT, sourceCallableDispatcherDEFAULT)
698
+
699
+ astModule = getModule(logicalPathInfix=None)
700
+ pathFilename = makeDaoOfMapFoldingParallel(astModule, 'countParallel', None, logicalPathInfixDEFAULT, sourceCallableDispatcherDEFAULT)
701
+
702
+ astModule = getModule(logicalPathInfix=None)
703
+ pathFilename = makeTheorem2(astModule, 'theorem2', None, logicalPathInfixDEFAULT, None)
704
+
705
+ astModule = parsePathFilename2astModule(pathFilename)
706
+ pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', None, logicalPathInfixDEFAULT, None)
707
+
708
+ astModule = parsePathFilename2astModule(pathFilename)
709
+ pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', None, logicalPathInfixDEFAULT, None)
710
+
711
+ astImportFrom: ast.ImportFrom = Make.ImportFrom(_getLogicalPath(packageSettings.packageName, logicalPathInfixDEFAULT, 'theorem2Numba'), list_alias=[Make.alias(sourceCallableIdentifierDEFAULT)])
712
+ makeUnRePackDataclass(astImportFrom)