mapFolding 0.9.4__py3-none-any.whl → 0.10.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.
Files changed (42) hide show
  1. mapFolding/__init__.py +41 -7
  2. mapFolding/basecamp.py +100 -9
  3. mapFolding/beDRY.py +7 -15
  4. mapFolding/dataBaskets.py +12 -0
  5. mapFolding/datatypes.py +4 -4
  6. mapFolding/oeis.py +2 -7
  7. mapFolding/someAssemblyRequired/RecipeJob.py +97 -3
  8. mapFolding/someAssemblyRequired/Z0Z_makeSomeModules.py +143 -42
  9. mapFolding/someAssemblyRequired/__init__.py +38 -49
  10. mapFolding/someAssemblyRequired/_astTypes.py +117 -0
  11. mapFolding/someAssemblyRequired/_theTypes.py +12 -41
  12. mapFolding/someAssemblyRequired/_toolBe.py +524 -0
  13. mapFolding/someAssemblyRequired/_toolDOT.py +493 -0
  14. mapFolding/someAssemblyRequired/_toolGrab.py +653 -0
  15. mapFolding/someAssemblyRequired/_toolIfThis.py +193 -0
  16. mapFolding/someAssemblyRequired/_toolMake.py +339 -0
  17. mapFolding/someAssemblyRequired/_toolThen.py +63 -0
  18. mapFolding/someAssemblyRequired/_toolboxAST.py +3 -3
  19. mapFolding/someAssemblyRequired/_toolboxContainers.py +124 -29
  20. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +274 -0
  21. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +12 -11
  22. mapFolding/someAssemblyRequired/toolboxNumba.py +4 -28
  23. mapFolding/someAssemblyRequired/transformationTools.py +46 -155
  24. mapFolding/syntheticModules/daoOfMapFolding.py +74 -0
  25. mapFolding/syntheticModules/dataPacking.py +1 -1
  26. mapFolding/syntheticModules/theorem2Numba.py +2 -8
  27. mapFolding/syntheticModules/theorem2Trimmed.py +43 -0
  28. mapFolding/toolFactory/astFactory.py +493 -0
  29. mapFolding/toolFactory/astFactory_annex.py +63 -0
  30. mapFolding/toolFactory/astFactory_docstrings.py +63 -0
  31. {mapfolding-0.9.4.dist-info → mapfolding-0.10.0.dist-info}/METADATA +2 -1
  32. mapfolding-0.10.0.dist-info/RECORD +66 -0
  33. {mapfolding-0.9.4.dist-info → mapfolding-0.10.0.dist-info}/WHEEL +1 -1
  34. tests/test_computations.py +1 -1
  35. mapFolding/Z0Z_flowControl.py +0 -117
  36. mapFolding/someAssemblyRequired/_tool_Make.py +0 -134
  37. mapFolding/someAssemblyRequired/_tool_Then.py +0 -157
  38. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +0 -387
  39. mapfolding-0.9.4.dist-info/RECORD +0 -57
  40. {mapfolding-0.9.4.dist-info → mapfolding-0.10.0.dist-info}/entry_points.txt +0 -0
  41. {mapfolding-0.9.4.dist-info → mapfolding-0.10.0.dist-info}/licenses/LICENSE +0 -0
  42. {mapfolding-0.9.4.dist-info → mapfolding-0.10.0.dist-info}/top_level.txt +0 -0
@@ -19,9 +19,11 @@ specific optimizations and transformations.
19
19
  """
20
20
 
21
21
  from collections import defaultdict
22
- from collections.abc import Sequence
23
- from mapFolding.someAssemblyRequired import ast_Identifier, Make, parseLogicalPath2astModule, str_nameDOTname
24
- from mapFolding.theSSOT import The
22
+ from collections.abc import Callable, Sequence
23
+ from copy import deepcopy
24
+ from typing import Any
25
+ from mapFolding.someAssemblyRequired import ast_Identifier, DOT, IfThis, Make, NodeTourist, parseLogicalPath2astModule, str_nameDOTname, Then
26
+ from mapFolding.theSSOT import raiseIfNoneGitHubIssueNumber3, The
25
27
  from pathlib import Path, PurePosixPath
26
28
  from Z0Z_tools import updateExtendPolishDictionaryLists
27
29
  import ast
@@ -171,22 +173,21 @@ class IngredientsModule:
171
173
  """
172
174
  Assemble a complete Python module from its constituent AST components.
173
175
 
174
- IngredientsModule provides a structured container for all elements needed to
175
- generate a complete Python module, including:
176
+ IngredientsModule provides a structured container for all elements needed to generate a complete Python module,
177
+ including:
176
178
 
177
- 1. Import statements aggregated from all module components
178
- 2. Prologue code that runs before function definitions
179
- 3. Function definitions with their dependencies
180
- 4. Epilogue code that runs after function definitions
181
- 5. Entry point code executed when the module runs as a script
182
- 6. Type ignores and other annotations
179
+ 1. Import statements aggregated from all module components.
180
+ 2. Prologue code that runs before function definitions.
181
+ 3. Function definitions with their dependencies.
182
+ 4. Epilogue code that runs after function definitions.
183
+ 5. Entry point code executed when the module runs as a script.
184
+ 6. Type ignores and other annotations.
183
185
 
184
- This class enables programmatic assembly of Python modules with a clear
185
- separation between different structural elements, while maintaining the
186
- proper ordering and relationships between components.
186
+ This class enables programmatic assembly of Python modules with a clear separation between different structural
187
+ elements, while maintaining the proper ordering and relationships between components.
187
188
 
188
- The modular design allows transformations to be applied to specific parts
189
- of a module while preserving the overall structure.
189
+ The modular design allows transformations to be applied to specific parts of a module while preserving the overall
190
+ structure.
190
191
 
191
192
  Parameters:
192
193
  ingredientsFunction (None): One or more `IngredientsFunction` that will appended to `listIngredientsFunctions`.
@@ -311,22 +312,20 @@ class RecipeSynthesizeFlow:
311
312
  """
312
313
  Configure the generation of new modules, including Numba-accelerated code modules.
313
314
 
314
- RecipeSynthesizeFlow defines the complete blueprint for transforming an original
315
- Python algorithm into an optimized, accelerated implementation. It specifies:
315
+ RecipeSynthesizeFlow defines the complete blueprint for transforming an original Python algorithm into an optimized,
316
+ accelerated implementation. It specifies:
316
317
 
317
- 1. Source code locations and identifiers
318
- 2. Target code locations and identifiers
319
- 3. Naming conventions for generated modules and functions
320
- 4. File system paths for output files
321
- 5. Import relationships between components
318
+ 1. Source code locations and identifiers.
319
+ 2. Target code locations and identifiers.
320
+ 3. Naming conventions for generated modules and functions.
321
+ 4. File system paths for output files.
322
+ 5. Import relationships between components.
322
323
 
323
- This configuration class serves as a single source of truth for the code generation
324
- process, ensuring consistency across all generated artifacts while enabling
325
- customization of the transformation assembly line.
324
+ This configuration class serves as a single source of truth for the code generation process, ensuring consistency
325
+ across all generated artifacts while enabling customization of the transformation assembly line.
326
326
 
327
- The transformation process uses this configuration to extract functions from the
328
- source module, transform them according to optimization rules, and output
329
- properly structured optimized modules with all necessary imports.
327
+ The transformation process uses this configuration to extract functions from the source module, transform them
328
+ according to optimization rules, and output properly structured optimized modules with all necessary imports.
330
329
  """
331
330
  # ========================================
332
331
  # Source
@@ -471,3 +470,99 @@ class ShatteredDataclass:
471
470
 
472
471
  signatureReturnAnnotation: ast.Subscript = dummySubscript
473
472
  """tuple-based return type annotation for function definitions."""
473
+
474
+ @dataclasses.dataclass
475
+ class DeReConstructField2ast:
476
+ """
477
+ Transform a dataclass field into AST node representations for code generation.
478
+
479
+ This class extracts and transforms a dataclass Field object into various AST node
480
+ representations needed for code generation. It handles the conversion of field
481
+ attributes, type annotations, and metadata into AST constructs that can be used
482
+ to reconstruct the field in generated code.
483
+
484
+ The class is particularly important for decomposing dataclass fields (like those in
485
+ ComputationState) to enable their use in specialized contexts like Numba-optimized
486
+ functions, where the full dataclass cannot be directly used but its contents need
487
+ to be accessible.
488
+
489
+ Each field is processed according to its type and metadata to create appropriate
490
+ variable declarations, type annotations, and initialization code as AST nodes.
491
+ """
492
+ dataclassesDOTdataclassLogicalPathModule: dataclasses.InitVar[str_nameDOTname]
493
+ dataclassClassDef: dataclasses.InitVar[ast.ClassDef]
494
+ dataclassesDOTdataclassInstance_Identifier: dataclasses.InitVar[ast_Identifier]
495
+ field: dataclasses.InitVar[dataclasses.Field[Any]]
496
+
497
+ ledger: LedgerOfImports = dataclasses.field(default_factory=LedgerOfImports)
498
+
499
+ name: ast_Identifier = dataclasses.field(init=False)
500
+ typeBuffalo: type[Any] | str | Any = dataclasses.field(init=False)
501
+ default: Any | None = dataclasses.field(init=False)
502
+ default_factory: Callable[..., Any] | None = dataclasses.field(init=False)
503
+ repr: bool = dataclasses.field(init=False)
504
+ hash: bool | None = dataclasses.field(init=False)
505
+ init: bool = dataclasses.field(init=False)
506
+ compare: bool = dataclasses.field(init=False)
507
+ metadata: dict[Any, Any] = dataclasses.field(init=False)
508
+ kw_only: bool = dataclasses.field(init=False)
509
+
510
+ astName: ast.Name = dataclasses.field(init=False)
511
+ ast_keyword_field__field: ast.keyword = dataclasses.field(init=False)
512
+ ast_nameDOTname: ast.Attribute = dataclasses.field(init=False)
513
+ astAnnotation: ast.expr = dataclasses.field(init=False)
514
+ ast_argAnnotated: ast.arg = dataclasses.field(init=False)
515
+ astAnnAssignConstructor: ast.AnnAssign|ast.Assign = dataclasses.field(init=False)
516
+ Z0Z_hack: tuple[ast.AnnAssign|ast.Assign, str] = dataclasses.field(init=False)
517
+
518
+ def __post_init__(self, dataclassesDOTdataclassLogicalPathModule: str_nameDOTname, dataclassClassDef: ast.ClassDef, dataclassesDOTdataclassInstance_Identifier: ast_Identifier, field: dataclasses.Field[Any]) -> None:
519
+ self.compare = field.compare
520
+ self.default = field.default if field.default is not dataclasses.MISSING else None
521
+ self.default_factory = field.default_factory if field.default_factory is not dataclasses.MISSING else None
522
+ self.hash = field.hash
523
+ self.init = field.init
524
+ self.kw_only = field.kw_only if field.kw_only is not dataclasses.MISSING else False
525
+ self.metadata = dict(field.metadata)
526
+ self.name = field.name
527
+ self.repr = field.repr
528
+ self.typeBuffalo = field.type
529
+
530
+ self.astName = Make.Name(self.name)
531
+ self.ast_keyword_field__field = Make.keyword(self.name, self.astName)
532
+ self.ast_nameDOTname = Make.Attribute(Make.Name(dataclassesDOTdataclassInstance_Identifier), self.name)
533
+
534
+ sherpa = NodeTourist(IfThis.isAnnAssign_targetIs(IfThis.isName_Identifier(self.name)), Then.extractIt(DOT.annotation)).captureLastMatch(dataclassClassDef)
535
+ if sherpa is None: raise raiseIfNoneGitHubIssueNumber3
536
+ else: self.astAnnotation = sherpa
537
+
538
+ self.ast_argAnnotated = Make.arg(self.name, self.astAnnotation)
539
+
540
+ dtype = self.metadata.get('dtype', None)
541
+ if dtype:
542
+ moduleWithLogicalPath: str_nameDOTname = 'numpy'
543
+ annotationType = 'ndarray'
544
+ self.ledger.addImportFrom_asStr(moduleWithLogicalPath, annotationType)
545
+ self.ledger.addImportFrom_asStr(moduleWithLogicalPath, 'dtype')
546
+ axesSubscript = Make.Subscript(Make.Name('tuple'), Make.Name('uint8'))
547
+ dtype_asnameName: ast.Name = self.astAnnotation # type: ignore
548
+ if dtype_asnameName.id == 'Array3D':
549
+ axesSubscript = Make.Subscript(Make.Name('tuple'), Make.Tuple([Make.Name('uint8'), Make.Name('uint8'), Make.Name('uint8')]))
550
+ ast_expr = Make.Subscript(Make.Name(annotationType), Make.Tuple([axesSubscript, Make.Subscript(Make.Name('dtype'), dtype_asnameName)]))
551
+ constructor = 'array'
552
+ self.ledger.addImportFrom_asStr(moduleWithLogicalPath, constructor)
553
+ dtypeIdentifier: ast_Identifier = dtype.__name__
554
+ self.ledger.addImportFrom_asStr(moduleWithLogicalPath, dtypeIdentifier, dtype_asnameName.id)
555
+ self.astAnnAssignConstructor = Make.AnnAssign(self.astName, ast_expr, Make.Call(Make.Name(constructor), list_keyword=[Make.keyword('dtype', dtype_asnameName)]))
556
+ self.astAnnAssignConstructor = Make.Assign([self.astName], Make.Call(Make.Name(constructor), list_keyword=[Make.keyword('dtype', dtype_asnameName)]))
557
+ self.Z0Z_hack = (self.astAnnAssignConstructor, 'array')
558
+ elif isinstance(self.astAnnotation, ast.Name):
559
+ self.astAnnAssignConstructor = Make.AnnAssign(self.astName, self.astAnnotation, Make.Call(self.astAnnotation, [Make.Constant(-1)]))
560
+ self.Z0Z_hack = (self.astAnnAssignConstructor, 'scalar')
561
+ elif isinstance(self.astAnnotation, ast.Subscript):
562
+ elementConstructor: ast_Identifier = self.metadata['elementConstructor']
563
+ self.ledger.addImportFrom_asStr(dataclassesDOTdataclassLogicalPathModule, elementConstructor)
564
+ takeTheTuple: ast.Tuple = deepcopy(self.astAnnotation.slice) # type: ignore
565
+ self.astAnnAssignConstructor = Make.AnnAssign(self.astName, self.astAnnotation, takeTheTuple)
566
+ self.Z0Z_hack = (self.astAnnAssignConstructor, elementConstructor)
567
+ if isinstance(self.astAnnotation, ast.Name):
568
+ self.ledger.addImportFrom_asStr(dataclassesDOTdataclassLogicalPathModule, self.astAnnotation.id) # pyright: ignore [reportUnknownArgumentType, reportUnknownMemberType, reportIJustCalledATypeGuardMethod_WTF]
@@ -0,0 +1,274 @@
1
+ from mapFolding import getPathFilenameFoldsTotal, raiseIfNoneGitHubIssueNumber3, The
2
+ from mapFolding.someAssemblyRequired import (
3
+ ast_Identifier,
4
+ Be,
5
+ extractFunctionDef,
6
+ IfThis,
7
+ IngredientsFunction,
8
+ IngredientsModule,
9
+ LedgerOfImports,
10
+ Make,
11
+ NodeChanger,
12
+ NodeTourist,
13
+ str_nameDOTname,
14
+ Then,
15
+ )
16
+ from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2Numba
17
+ from mapFolding.someAssemblyRequired.toolboxNumba import parametersNumbaLight, SpicesJobNumba, decorateCallableWithNumba
18
+ from mapFolding.someAssemblyRequired.transformationTools import dictionaryEstimates, write_astModule, makeInitializedComputationState
19
+ from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
20
+ from mapFolding.dataBaskets import MapFoldingState
21
+ from pathlib import PurePosixPath
22
+ from typing import cast, NamedTuple
23
+ from Z0Z_tools import autoDecodingRLE
24
+ import ast
25
+ """Synthesize one file to compute `foldsTotal` of `mapShape`."""
26
+
27
+ list_IdentifiersNotUsedAllHARDCODED = ['concurrencyLimit', 'foldsTotal', 'mapShape',]
28
+ list_IdentifiersNotUsedParallelSequentialHARDCODED = ['indexLeaf']
29
+ list_IdentifiersNotUsedSequentialHARDCODED = ['foldGroups', 'taskDivisions', 'taskIndex',]
30
+
31
+ list_IdentifiersReplacedHARDCODED = ['groupsOfFolds',]
32
+
33
+ list_IdentifiersStaticValuesHARDCODED = ['dimensionsTotal', 'leavesTotal',]
34
+
35
+ list_IdentifiersNotUsedHARDCODED = list_IdentifiersStaticValuesHARDCODED + list_IdentifiersReplacedHARDCODED + list_IdentifiersNotUsedAllHARDCODED + list_IdentifiersNotUsedParallelSequentialHARDCODED + list_IdentifiersNotUsedSequentialHARDCODED
36
+
37
+ def addLauncherNumbaProgress(ingredientsModule: IngredientsModule, ingredientsFunction: IngredientsFunction, job: RecipeJobTheorem2Numba, spices: SpicesJobNumba) -> tuple[IngredientsModule, IngredientsFunction]:
38
+ """
39
+ Add progress tracking capabilities to a Numba-optimized function.
40
+
41
+ This function modifies both the module and the function to integrate Numba-compatible
42
+ progress tracking for long-running calculations. It performs several key transformations:
43
+
44
+ 1. Adds a progress bar parameter to the function signature
45
+ 2. Replaces counting increments with progress bar updates
46
+ 3. Creates a launcher section that displays and updates progress
47
+ 4. Configures file output to save results upon completion
48
+
49
+ The progress tracking is particularly important for map folding calculations
50
+ which can take hours or days to complete, providing visual feedback and
51
+ estimated completion times.
52
+
53
+ Parameters:
54
+ ingredientsModule: The module where the function is defined.
55
+ ingredientsFunction: The function to modify with progress tracking.
56
+ job: Configuration specifying shape details and output paths.
57
+ spices: Configuration specifying progress bar details.
58
+
59
+ Returns:
60
+ A tuple containing the modified module and function with progress tracking.
61
+ """
62
+ linesLaunch: str = f"""
63
+ if __name__ == '__main__':
64
+ with ProgressBar(total={job.foldsTotalEstimated}, update_interval=2) as statusUpdate:
65
+ {job.countCallable}(statusUpdate)
66
+ foldsTotal = statusUpdate.n * {job.state.leavesTotal}
67
+ print('\\nmap {job.state.mapShape} =', foldsTotal)
68
+ writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
69
+ writeStream.write(str(foldsTotal))
70
+ writeStream.close()
71
+ """
72
+ numba_progressPythonClass: ast_Identifier = 'ProgressBar'
73
+ numba_progressNumbaType: ast_Identifier = 'ProgressBarType'
74
+ ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressPythonClass)
75
+ ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressNumbaType)
76
+
77
+ ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
78
+ ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
79
+
80
+ findThis = IfThis.isAugAssign_targetIs(IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
81
+ doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
82
+ countWithProgressBar = NodeChanger(findThis, doThat)
83
+ countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
84
+
85
+ removeReturnStatement = NodeChanger(Be.Return, Then.removeIt)
86
+ removeReturnStatement.visit(ingredientsFunction.astFunctionDef)
87
+ ingredientsFunction.astFunctionDef.returns = Make.Constant(value=None)
88
+
89
+ ingredientsModule.appendLauncher(ast.parse(linesLaunch))
90
+
91
+ return ingredientsModule, ingredientsFunction
92
+
93
+ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job: RecipeJobTheorem2Numba) -> IngredientsFunction:
94
+ """
95
+ Convert function parameters into initialized variables with concrete values.
96
+
97
+ This function implements a critical transformation that converts function parameters
98
+ into statically initialized variables in the function body. This enables several
99
+ optimizations:
100
+
101
+ 1. Eliminating parameter passing overhead.
102
+ 2. Embedding concrete values directly in the code.
103
+ 3. Allowing Numba to optimize based on known value characteristics.
104
+ 4. Simplifying function signatures for specialized use cases.
105
+
106
+ The function handles different data types (scalars, arrays, custom types) appropriately,
107
+ replacing abstract parameter references with concrete values from the computation state.
108
+ It also removes unused parameters and variables to eliminate dead code.
109
+
110
+ Parameters:
111
+ ingredientsFunction: The function to transform.
112
+ job: Recipe containing concrete values for parameters and field metadata.
113
+
114
+ Returns:
115
+ The modified function with parameters converted to initialized variables.
116
+ """
117
+ ingredientsFunction.imports.update(job.shatteredDataclass.imports)
118
+
119
+ list_argCuzMyBrainRefusesToThink = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
120
+ list_arg_arg: list[ast_Identifier] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
121
+ listName: list[ast.Name] = []
122
+ NodeTourist(Be.Name, Then.appendTo(listName)).visit(ingredientsFunction.astFunctionDef)
123
+ list_Identifiers: list[ast_Identifier] = [astName.id for astName in listName]
124
+ list_IdentifiersNotUsed: list[ast_Identifier] = list(set(list_arg_arg) - set(list_Identifiers))
125
+
126
+ for ast_arg in list_argCuzMyBrainRefusesToThink:
127
+ if ast_arg.arg in job.shatteredDataclass.field2AnnAssign:
128
+ if ast_arg.arg in list_IdentifiersNotUsed:
129
+ pass
130
+ else:
131
+ ImaAnnAssign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
132
+ match elementConstructor:
133
+ case 'scalar':
134
+ ImaAnnAssign.value.args[0].value = int(job.state.__dict__[ast_arg.arg]) # type: ignore
135
+ case 'array':
136
+ dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], True)
137
+ dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
138
+ ImaAnnAssign.value.args = [dataAs_astExpr] # type: ignore
139
+ case _:
140
+ list_exprDOTannotation: list[ast.expr] = []
141
+ list_exprDOTvalue: list[ast.expr] = []
142
+ for dimension in job.state.mapShape:
143
+ list_exprDOTannotation.append(Make.Name(elementConstructor))
144
+ list_exprDOTvalue.append(Make.Call(Make.Name(elementConstructor), [Make.Constant(dimension)]))
145
+ ImaAnnAssign.annotation.slice.elts = list_exprDOTannotation # type: ignore
146
+ ImaAnnAssign.value.elts = list_exprDOTvalue # type: ignore
147
+
148
+ ingredientsFunction.astFunctionDef.body.insert(0, ImaAnnAssign)
149
+
150
+ findThis = IfThis.is_arg_Identifier(ast_arg.arg)
151
+ remove_arg = NodeChanger(findThis, Then.removeIt)
152
+ remove_arg.visit(ingredientsFunction.astFunctionDef)
153
+
154
+ ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
155
+ return ingredientsFunction
156
+
157
+ def makeJobNumba(job: RecipeJobTheorem2Numba, spices: SpicesJobNumba) -> None:
158
+
159
+ astFunctionDef = extractFunctionDef(job.source_astModule, job.countCallable)
160
+ if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
161
+ ingredientsCount: IngredientsFunction = IngredientsFunction(astFunctionDef, LedgerOfImports())
162
+
163
+ # Remove `foldGroups` and any other unused statements, so you can dynamically determine which variables are not used
164
+ findThis = IfThis.isAssignAndTargets0Is(IfThis.isSubscript_Identifier('foldGroups'))
165
+ doThat = Then.removeIt
166
+ remove_foldGroups = NodeChanger(findThis, doThat)
167
+ remove_foldGroups.visit(ingredientsCount.astFunctionDef)
168
+
169
+ # replace identifiers with static values with their values, so you can dynamically determine which variables are not used
170
+ list_IdentifiersStaticValues = list_IdentifiersStaticValuesHARDCODED
171
+ for identifier in list_IdentifiersStaticValues:
172
+ findThis = IfThis.isName_Identifier(identifier)
173
+ doThat = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
174
+ NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
175
+
176
+ ingredientsModule = IngredientsModule()
177
+ # This launcher eliminates the use of one identifier, so run it now and you can dynamically determine which variables are not used
178
+ if spices.useNumbaProgressBar:
179
+ ingredientsModule, ingredientsCount = addLauncherNumbaProgress(ingredientsModule, ingredientsCount, job, spices)
180
+ spices.parametersNumba['nogil'] = True
181
+ else:
182
+ linesLaunch: str = f"""
183
+ if __name__ == '__main__':
184
+ import time
185
+ timeStart = time.perf_counter()
186
+ foldsTotal = {job.countCallable}() * {job.state.leavesTotal}
187
+ print(time.perf_counter() - timeStart)
188
+ print('\\nmap {job.state.mapShape} =', foldsTotal)
189
+ writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
190
+ writeStream.write(str(foldsTotal))
191
+ writeStream.close()
192
+ """
193
+ # from mapFolding.oeis import getFoldsTotalKnown
194
+ # print(foldsTotal == getFoldsTotalKnown({job.state.mapShape}))
195
+ ingredientsModule.appendLauncher(ast.parse(linesLaunch))
196
+ changeReturnParallelCallable = NodeChanger(Be.Return, Then.replaceWith(Make.Return(job.shatteredDataclass.countingVariableName)))
197
+ changeReturnParallelCallable.visit(ingredientsCount.astFunctionDef)
198
+ ingredientsCount.astFunctionDef.returns = job.shatteredDataclass.countingVariableAnnotation
199
+
200
+ ingredientsCount = move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsCount, job)
201
+
202
+ class DatatypeConfig(NamedTuple):
203
+ Z0Z_module: str_nameDOTname
204
+ fml: ast_Identifier
205
+ Z0Z_type_name: ast_Identifier
206
+ Z0Z_asname: ast_Identifier | None = None
207
+
208
+ listDatatypeConfigs = [
209
+ DatatypeConfig(fml='DatatypeLeavesTotal', Z0Z_module='numba', Z0Z_type_name='uint8'),
210
+ DatatypeConfig(fml='DatatypeElephino', Z0Z_module='numba', Z0Z_type_name='uint16'),
211
+ DatatypeConfig(fml='DatatypeFoldsTotal', Z0Z_module='numba', Z0Z_type_name='uint64'),
212
+ ]
213
+
214
+ for datatypeConfig in listDatatypeConfigs:
215
+ ingredientsModule.imports.addImportFrom_asStr(datatypeConfig.Z0Z_module, datatypeConfig.Z0Z_type_name)
216
+ statement = Make.Assign(
217
+ [Make.Name(datatypeConfig.fml, ast.Store())],
218
+ Make.Name(datatypeConfig.Z0Z_type_name)
219
+ )
220
+ ingredientsModule.appendPrologue(statement=statement)
221
+
222
+ ingredientsCount.imports.removeImportFromModule('mapFolding.theSSOT')
223
+
224
+ listNumPyTypeConfigs = [
225
+ DatatypeConfig(fml='Array1DLeavesTotal', Z0Z_module='numpy', Z0Z_type_name='uint8', Z0Z_asname='Array1DLeavesTotal'),
226
+ DatatypeConfig(fml='Array1DElephino', Z0Z_module='numpy', Z0Z_type_name='uint16', Z0Z_asname='Array1DElephino'),
227
+ DatatypeConfig(fml='Array3D', Z0Z_module='numpy', Z0Z_type_name='uint8', Z0Z_asname='Array3D'),
228
+ ]
229
+
230
+ for typeConfig in listNumPyTypeConfigs:
231
+ ingredientsCount.imports.removeImportFrom(typeConfig.Z0Z_module, None, typeConfig.fml)
232
+ ingredientsCount.imports.addImportFrom_asStr(typeConfig.Z0Z_module, typeConfig.Z0Z_type_name, typeConfig.Z0Z_asname)
233
+
234
+ ingredientsCount.astFunctionDef.decorator_list = [] # TODO low-priority, handle this more elegantly
235
+ # TODO when I add the function signature in numba style back to the decorator, the logic needs to handle `ProgressBarType:`
236
+ ingredientsCount = decorateCallableWithNumba(ingredientsCount, spices.parametersNumba)
237
+
238
+ ingredientsModule.appendIngredientsFunction(ingredientsCount)
239
+ write_astModule(ingredientsModule, job.pathFilenameModule, job.packageIdentifier)
240
+
241
+ """
242
+ Overview
243
+ - the code starts life in theDao.py, which has many optimizations;
244
+ - `makeNumbaOptimizedFlow` increase optimization especially by using numba;
245
+ - `makeJobNumba` increases optimization especially by limiting its capabilities to just one set of parameters
246
+ - the synthesized module must run well as a standalone interpreted-Python script
247
+ - the next major optimization step will (probably) be to use the module synthesized by `makeJobNumba` to compile a standalone executable
248
+ - Nevertheless, at each major optimization step, the code is constantly being improved and optimized, so everything must be well organized (read: semantic) and able to handle a range of arbitrary upstream and not disrupt downstream transformations
249
+
250
+ Necessary
251
+ - Move the function's parameters to the function body,
252
+ - initialize identifiers with their state types and values,
253
+
254
+ Optimizations
255
+ - replace static-valued identifiers with their values
256
+ - narrowly focused imports
257
+
258
+ Minutia
259
+ - do not use `with` statement inside numba jitted code, except to use numba's obj mode
260
+ """
261
+
262
+ if __name__ == '__main__':
263
+ mapShape = (1,46)
264
+ state = MapFoldingState(mapShape)
265
+ state = initializeGroupsOfFolds(state)
266
+ # foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
267
+ # foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal
268
+ foldsTotalEstimated = 0
269
+ pathModule = PurePosixPath(The.pathPackage, 'jobs')
270
+ pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
271
+ aJob = RecipeJobTheorem2Numba(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
272
+ spices = SpicesJobNumba(useNumbaProgressBar=False, parametersNumba=parametersNumbaLight)
273
+ # spices = SpicesJobNumba()
274
+ makeJobNumba(aJob, spices)
@@ -21,9 +21,9 @@ as Python scripts or further compiled into standalone executables.
21
21
  from mapFolding import getPathFilenameFoldsTotal, raiseIfNoneGitHubIssueNumber3, The
22
22
  from mapFolding.someAssemblyRequired import (
23
23
  ast_Identifier,
24
- be,
24
+ Be,
25
25
  extractFunctionDef,
26
- ifThis,
26
+ IfThis,
27
27
  IngredientsFunction,
28
28
  IngredientsModule,
29
29
  LedgerOfImports,
@@ -95,12 +95,12 @@ if __name__ == '__main__':
95
95
  ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
96
96
  ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
97
97
 
98
- findThis = ifThis.isAugAssign_targetIs(ifThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
98
+ findThis = IfThis.isAugAssign_targetIs(IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
99
99
  doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
100
100
  countWithProgressBar = NodeChanger(findThis, doThat)
101
101
  countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
102
102
 
103
- removeReturnStatement = NodeChanger(be.Return, Then.removeIt)
103
+ removeReturnStatement = NodeChanger(Be.Return, Then.removeIt)
104
104
  removeReturnStatement.visit(ingredientsFunction.astFunctionDef)
105
105
  ingredientsFunction.astFunctionDef.returns = Make.Constant(value=None)
106
106
 
@@ -137,7 +137,7 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
137
137
  list_argCuzMyBrainRefusesToThink = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
138
138
  list_arg_arg: list[ast_Identifier] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
139
139
  listName: list[ast.Name] = []
140
- NodeTourist(be.Name, Then.appendTo(listName)).visit(ingredientsFunction.astFunctionDef)
140
+ NodeTourist(Be.Name, Then.appendTo(listName)).visit(ingredientsFunction.astFunctionDef)
141
141
  list_Identifiers: list[ast_Identifier] = [astName.id for astName in listName]
142
142
  list_IdentifiersNotUsed: list[ast_Identifier] = list(set(list_arg_arg) - set(list_Identifiers))
143
143
 
@@ -165,7 +165,7 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
165
165
 
166
166
  ingredientsFunction.astFunctionDef.body.insert(0, ImaAnnAssign)
167
167
 
168
- findThis = ifThis.is_arg_Identifier(ast_arg.arg)
168
+ findThis = IfThis.is_arg_Identifier(ast_arg.arg)
169
169
  remove_arg = NodeChanger(findThis, Then.removeIt)
170
170
  remove_arg.visit(ingredientsFunction.astFunctionDef)
171
171
 
@@ -201,7 +201,7 @@ def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
201
201
  ingredientsCount: IngredientsFunction = IngredientsFunction(astFunctionDef, LedgerOfImports())
202
202
 
203
203
  # Remove `foldGroups` and any other unused statements, so you can dynamically determine which variables are not used
204
- findThis = ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier('foldGroups'))
204
+ findThis = IfThis.isAssignAndTargets0Is(IfThis.isSubscript_Identifier('foldGroups'))
205
205
  doThat = Then.removeIt
206
206
  remove_foldGroups = NodeChanger(findThis, doThat)
207
207
  remove_foldGroups.visit(ingredientsCount.astFunctionDef)
@@ -209,7 +209,7 @@ def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
209
209
  # replace identifiers with static values with their values, so you can dynamically determine which variables are not used
210
210
  list_IdentifiersStaticValues = list_IdentifiersStaticValuesHARDCODED
211
211
  for identifier in list_IdentifiersStaticValues:
212
- findThis = ifThis.isName_Identifier(identifier)
212
+ findThis = IfThis.isName_Identifier(identifier)
213
213
  doThat = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
214
214
  NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
215
215
 
@@ -233,7 +233,7 @@ if __name__ == '__main__':
233
233
  # from mapFolding.oeis import getFoldsTotalKnown
234
234
  # print(foldsTotal == getFoldsTotalKnown({job.state.mapShape}))
235
235
  ingredientsModule.appendLauncher(ast.parse(linesLaunch))
236
- changeReturnParallelCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(job.shatteredDataclass.countingVariableName)))
236
+ changeReturnParallelCallable = NodeChanger(Be.Return, Then.replaceWith(Make.Return(job.shatteredDataclass.countingVariableName)))
237
237
  changeReturnParallelCallable.visit(ingredientsCount.astFunctionDef)
238
238
  ingredientsCount.astFunctionDef.returns = job.shatteredDataclass.countingVariableAnnotation
239
239
 
@@ -300,10 +300,11 @@ if __name__ == '__main__':
300
300
  """
301
301
 
302
302
  if __name__ == '__main__':
303
- mapShape = (2,21)
303
+ mapShape = (1,46)
304
304
  state = makeInitializedComputationState(mapShape)
305
305
  # foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
306
- foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal
306
+ # foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal
307
+ foldsTotalEstimated = 0
307
308
  pathModule = PurePosixPath(The.pathPackage, 'jobs')
308
309
  pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
309
310
  aJob = RecipeJob(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
@@ -16,23 +16,14 @@ performance improvements while preserving code semantics and correctness.
16
16
  """
17
17
 
18
18
  from collections.abc import Callable, Sequence
19
- from mapFolding.someAssemblyRequired import ast_Identifier, be, IngredientsFunction, Make, NodeTourist, RecipeSynthesizeFlow, str_nameDOTname, Then
19
+ from mapFolding import NotRequired, TypedDict
20
+ from mapFolding.someAssemblyRequired import ast_Identifier, IngredientsFunction, Make, RecipeSynthesizeFlow, str_nameDOTname
20
21
  from mapFolding.someAssemblyRequired.transformationTools import makeNewFlow, write_astModule
21
22
  from numba.core.compiler import CompilerBase as numbaCompilerBase
22
- from typing import Any, cast, Final, TYPE_CHECKING, TypeGuard
23
+ from typing import Any, cast, Final
23
24
  import ast
24
25
  import dataclasses
25
26
 
26
- try:
27
- from typing import NotRequired
28
- except Exception:
29
- from typing_extensions import NotRequired # pyright: ignore[reportShadowedImports]
30
-
31
- if TYPE_CHECKING:
32
- from typing import TypedDict
33
- else:
34
- TypedDict = dict[str,Any]
35
-
36
27
  # Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
37
28
  theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
38
29
 
@@ -60,17 +51,8 @@ class ParametersNumba(TypedDict):
60
51
  signature_or_function: NotRequired[Any | Callable[..., Any] | str | tuple[Any, ...]]
61
52
  target: NotRequired[str]
62
53
 
63
- parametersNumbaFailEarly: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': True, 'cache': True, 'error_model': 'python', 'fastmath': False, 'forceinline': True, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': True, 'parallel': False, }
64
- """For a production function: speed is irrelevant, error discovery is paramount, must be compatible with anything downstream."""
65
54
  parametersNumbaDefault: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': False, 'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': True, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': True, 'parallel': False, }
66
55
  """Middle of the road: fast, lean, but will talk to non-jitted functions."""
67
- parametersNumbaParallelDEFAULT: Final[ParametersNumba] = { **parametersNumbaDefault, '_nrt': True, 'parallel': True, }
68
- """Middle of the road: fast, lean, but will talk to non-jitted functions."""
69
- parametersNumbaSuperJit: Final[ParametersNumba] = { **parametersNumbaDefault, 'no_cfunc_wrapper': True, 'no_cpython_wrapper': True, }
70
- """Speed, no helmet, no talking to non-jitted functions."""
71
- parametersNumbaSuperJitParallel: Final[ParametersNumba] = { **parametersNumbaSuperJit, '_nrt': True, 'parallel': True, }
72
- """Speed, no helmet, concurrency, no talking to non-jitted functions."""
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
56
  parametersNumbaLight: Final[ParametersNumba] = {'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': True}
75
57
 
76
58
  Z0Z_numbaDataTypeModule: str_nameDOTname = 'numba'
@@ -141,7 +123,7 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
141
123
  ingredientsFunction.imports.addImportFrom_asStr(decoratorModule, decoratorCallable)
142
124
  # Leave this line in so that global edits will change it.
143
125
  astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_argsDecorator, listDecoratorKeywords)
144
- astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_astKeywords=listDecoratorKeywords)
126
+ astDecorator: ast.Call = Make.Call(Make.Name(decoratorCallable), list_keyword=listDecoratorKeywords)
145
127
 
146
128
  ingredientsFunction.astFunctionDef.decorator_list = [astDecorator]
147
129
  return ingredientsFunction
@@ -188,11 +170,5 @@ def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
188
170
 
189
171
  write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
190
172
 
191
- def getIt(astCallConcurrencyResult: list[ast.Call]) -> Callable[[ast.AST], ast.AST]:
192
- def workhorse(node: ast.AST) -> ast.AST:
193
- NodeTourist(be.Call, Then.appendTo(astCallConcurrencyResult)).visit(node)
194
- return node
195
- return workhorse
196
-
197
173
  if __name__ == '__main__':
198
174
  makeNumbaFlow(theNumbaFlow)