mapFolding 0.8.2__py3-none-any.whl → 0.8.4__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 (37) hide show
  1. mapFolding/__init__.py +6 -2
  2. mapFolding/basecamp.py +11 -5
  3. mapFolding/filesystem.py +134 -109
  4. mapFolding/oeis.py +1 -1
  5. mapFolding/reference/__init__.py +7 -0
  6. mapFolding/reference/jobsCompleted/[2x19]/p2x19.py +197 -0
  7. mapFolding/reference/jobsCompleted/__init__.py +50 -0
  8. mapFolding/reference/jobsCompleted/p2x19/p2x19.py +29 -0
  9. mapFolding/someAssemblyRequired/__init__.py +37 -18
  10. mapFolding/someAssemblyRequired/_theTypes.py +35 -0
  11. mapFolding/someAssemblyRequired/_tool_Make.py +92 -0
  12. mapFolding/someAssemblyRequired/_tool_Then.py +65 -0
  13. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +326 -0
  14. mapFolding/someAssemblyRequired/_toolboxContainers.py +306 -0
  15. mapFolding/someAssemblyRequired/_toolboxPython.py +76 -0
  16. mapFolding/someAssemblyRequired/getLLVMforNoReason.py +20 -1
  17. mapFolding/someAssemblyRequired/ingredientsNumba.py +17 -24
  18. mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +112 -149
  19. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +247 -0
  20. mapFolding/someAssemblyRequired/transformDataStructures.py +167 -100
  21. mapFolding/someAssemblyRequired/transformationTools.py +63 -678
  22. mapFolding/syntheticModules/__init__.py +1 -0
  23. mapFolding/syntheticModules/numbaCount_doTheNeedful.py +36 -33
  24. mapFolding/theDao.py +13 -11
  25. mapFolding/theSSOT.py +69 -119
  26. {mapfolding-0.8.2.dist-info → mapfolding-0.8.4.dist-info}/METADATA +4 -2
  27. mapfolding-0.8.4.dist-info/RECORD +49 -0
  28. {mapfolding-0.8.2.dist-info → mapfolding-0.8.4.dist-info}/WHEEL +1 -1
  29. tests/conftest.py +34 -29
  30. tests/test_computations.py +40 -31
  31. tests/test_filesystem.py +3 -3
  32. tests/test_other.py +4 -3
  33. mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +0 -413
  34. mapfolding-0.8.2.dist-info/RECORD +0 -39
  35. {mapfolding-0.8.2.dist-info → mapfolding-0.8.4.dist-info}/entry_points.txt +0 -0
  36. {mapfolding-0.8.2.dist-info → mapfolding-0.8.4.dist-info}/licenses/LICENSE +0 -0
  37. {mapfolding-0.8.2.dist-info → mapfolding-0.8.4.dist-info}/top_level.txt +0 -0
@@ -22,172 +22,135 @@ to generate a fresh optimized implementation.
22
22
  """
23
23
 
24
24
  from mapFolding.someAssemblyRequired import (
25
- extractFunctionDef,
25
+ be,
26
26
  ifThis,
27
- IngredientsFunction,
27
+ Make,
28
+ NodeChanger,
29
+ NodeTourist,
30
+ Then,
31
+ Z0Z_inlineThisFunctionWithTheseValues,
32
+ Z0Z_lameFindReplace,
33
+ Z0Z_makeDictionaryReplacementStatements,
34
+ 又,
35
+ )
36
+ from mapFolding.someAssemblyRequired._toolboxContainers import (
37
+ astModuleToIngredientsFunction,
28
38
  IngredientsModule,
29
39
  LedgerOfImports,
30
- Make,
31
- makeDictionaryReplacementStatements,
32
- NodeCollector,
33
- NodeReplacer,
34
40
  RecipeSynthesizeFlow,
35
- Then,
36
- write_astModule,
37
- Z0Z_replaceMatchingASTnodes,
38
- inlineThisFunctionWithTheseValues,
39
41
  )
40
42
  from mapFolding.someAssemblyRequired.ingredientsNumba import decorateCallableWithNumba
41
43
  from mapFolding.someAssemblyRequired.transformDataStructures import shatter_dataclassesDOTdataclass
42
- from mapFolding.theSSOT import raiseIfNoneGitHubIssueNumber3
44
+ from mapFolding.someAssemblyRequired.transformationTools import write_astModule
43
45
  import ast
44
46
 
45
- def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()) -> None:
46
- """
47
- Think about a better organization of this function.
47
+ def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
48
+ # TODO a tool to automatically remove unused variables from the ArgumentsSpecification (return, and returns) _might_ be nice.
49
+ # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
48
50
 
49
- Currently, transform `Callable` in order:
50
- sourceDispatcherCallable
51
- sourceInitializeCallable
52
- sourceParallelCallable
53
- sourceSequentialCallable
51
+ listAllIngredientsFunctions = [
52
+ (ingredientsInitialize := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableInitialize)),
53
+ (ingredientsParallel := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableParallel)),
54
+ (ingredientsSequential := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableSequential)),
55
+ (ingredientsDispatcher := astModuleToIngredientsFunction(numbaFlow.source_astModule, numbaFlow.sourceCallableDispatcher)),
56
+ ]
57
+
58
+ # Inline functions ========================================================
59
+ dictionaryReplacementStatements = Z0Z_makeDictionaryReplacementStatements(numbaFlow.source_astModule)
60
+ # NOTE Replacements statements are based on the identifiers in the _source_, so operate on the source identifiers.
61
+ ingredientsInitialize.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsInitialize.astFunctionDef, dictionaryReplacementStatements)
62
+ ingredientsParallel.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsParallel.astFunctionDef, dictionaryReplacementStatements)
63
+ ingredientsSequential.astFunctionDef = Z0Z_inlineThisFunctionWithTheseValues(ingredientsSequential.astFunctionDef, dictionaryReplacementStatements)
64
+
65
+ # assignRecipeIdentifiersToCallable. =============================
66
+ # TODO How can I use `RecipeSynthesizeFlow` as the SSOT for the pairs of items that may need to be replaced?
67
+ # NOTE reminder: you are updating these `ast.Name` here (and not in a more general search) because this is a
68
+ # narrow search for `ast.Call` so you won't accidentally replace unrelated `ast.Name`.
69
+ listFindReplace = [(numbaFlow.sourceCallableDispatcher, numbaFlow.callableDispatcher),
70
+ (numbaFlow.sourceCallableInitialize, numbaFlow.callableInitialize),
71
+ (numbaFlow.sourceCallableParallel, numbaFlow.callableParallel),
72
+ (numbaFlow.sourceCallableSequential, numbaFlow.callableSequential),]
73
+ for ingredients in listAllIngredientsFunctions:
74
+ for source_Identifier, recipe_Identifier in listFindReplace:
75
+ updateCallName = NodeChanger(ifThis.isCall_Identifier(source_Identifier), Then.DOTfunc(Then.replaceWith(Make.Name(recipe_Identifier))))
76
+ updateCallName.visit(ingredients.astFunctionDef)
77
+
78
+ ingredientsDispatcher.astFunctionDef.name = numbaFlow.callableDispatcher
79
+ ingredientsInitialize.astFunctionDef.name = numbaFlow.callableInitialize
80
+ ingredientsParallel.astFunctionDef.name = numbaFlow.callableParallel
81
+ ingredientsSequential.astFunctionDef.name = numbaFlow.callableSequential
82
+
83
+ # Assign identifiers per the recipe. ==============================
84
+ listFindReplace = [(numbaFlow.sourceDataclassInstance, numbaFlow.dataclassInstance),
85
+ (numbaFlow.sourceDataclassInstanceTaskDistribution, numbaFlow.dataclassInstanceTaskDistribution),
86
+ (numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.concurrencyManagerNamespace),]
87
+ for ingredients in listAllIngredientsFunctions:
88
+ for source_Identifier, recipe_Identifier in listFindReplace:
89
+ updateName = NodeChanger(ifThis.isName_Identifier(source_Identifier), Then.DOTid(Then.replaceWith(recipe_Identifier)))
90
+ update_arg = NodeChanger(ifThis.isArgument_Identifier(source_Identifier), Then.DOTarg(Then.replaceWith(recipe_Identifier)))
91
+ updateName.visit(ingredients.astFunctionDef)
92
+ update_arg.visit(ingredients.astFunctionDef)
93
+
94
+ updateConcurrencyManager = NodeChanger(ifThis.isCallAttributeNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
95
+ , Then.DOTfunc(Then.replaceWith(Make.Attribute(Make.Name(numbaFlow.concurrencyManagerNamespace), numbaFlow.concurrencyManagerIdentifier))))
96
+ updateConcurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
97
+
98
+ # shatter Dataclass =======================================================
99
+ instance_Identifier = numbaFlow.dataclassInstance
100
+ getTheOtherRecord_damn = numbaFlow.dataclassInstanceTaskDistribution
101
+ shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, instance_Identifier)
102
+ ingredientsDispatcher.imports.update(shatteredDataclass.ledger)
103
+
104
+ # Change callable parameters and Call to the callable at the same time ====
105
+ # 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?
106
+ # Asked differently, how do I integrate separate statements into a "subroutine", and that subroutine is "atomic/indivisible"?
107
+ # sequentialCallable =========================================================
108
+ ingredientsSequential.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
109
+ astCallSequentialCallable = Make.Call(Make.Name(numbaFlow.callableSequential), shatteredDataclass.listName4Parameters)
110
+ changeReturnSequentialCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.fragments4AssignmentOrParameters)))
111
+ ingredientsSequential.astFunctionDef.returns = shatteredDataclass.signatureReturnAnnotation
112
+ replaceAssignSequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.replaceWith(Make.Assign(listTargets=[shatteredDataclass.fragments4AssignmentOrParameters], value=astCallSequentialCallable)))
113
+
114
+ unpack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.insertThisAbove(shatteredDataclass.listUnpack))
115
+ repack4sequentialCallable = NodeChanger(ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.callableSequential), Then.insertThisBelow([shatteredDataclass.repack]))
116
+
117
+ changeReturnSequentialCallable.visit(ingredientsSequential.astFunctionDef)
118
+ replaceAssignSequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
119
+ unpack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
120
+ repack4sequentialCallable.visit(ingredientsDispatcher.astFunctionDef)
121
+
122
+ ingredientsSequential.astFunctionDef = Z0Z_lameFindReplace(ingredientsSequential.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
123
+
124
+ # parallelCallable =========================================================
125
+ ingredientsParallel.astFunctionDef.args = Make.argumentsSpecification(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
126
+ 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)))
127
+
128
+ # NOTE I am dissatisfied with this logic for many reasons, including that it requires separate NodeCollector and NodeReplacer instances.
129
+ astCallConcurrencyResult: list[ast.Call] = []
130
+ 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]
131
+ get_astCallConcurrencyResult.visit(ingredientsDispatcher.astFunctionDef)
132
+ replaceAssignParallelCallable = NodeChanger(ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(getTheOtherRecord_damn)), Then.DOTvalue(Then.replaceWith(astCallConcurrencyResult[0])))
133
+ replaceAssignParallelCallable.visit(ingredientsDispatcher.astFunctionDef)
134
+ changeReturnParallelCallable = NodeChanger(be.Return, Then.replaceWith(Make.Return(shatteredDataclass.countingVariableName)))
135
+ ingredientsParallel.astFunctionDef.returns = shatteredDataclass.countingVariableAnnotation
54
136
 
55
- But, it should be organized around each transformation. So, when the parameters of `sourceSequentialCallable`
56
- are transformed, for example, the statement in `sourceDispatcherCallable` that calls `sourceSequentialCallable` should be
57
- transformed at the same time: literally in the same function-or-NodeReplacer-or-subroutine. That would help
58
- avoid bugs.
137
+ unpack4parallelCallable = NodeChanger(ifThis.isAssignAndValueIsCallAttributeNamespace_Identifier(numbaFlow.concurrencyManagerNamespace, numbaFlow.concurrencyManagerIdentifier), Then.insertThisAbove(shatteredDataclass.listUnpack))
59
138
 
60
- Furthermore, if the above example transformation requires unpacking the dataclass, for example, then the unpacking
61
- would be automatically triggered. I have no idea how that would happen, but the transformations are highly predictable,
62
- so using a programming language to construct if-this-then-that cascades shouldn't be a problem, you know?
139
+ unpack4parallelCallable.visit(ingredientsDispatcher.astFunctionDef)
140
+ replaceCall2concurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
141
+ changeReturnParallelCallable.visit(ingredientsParallel.astFunctionDef)
63
142
 
64
- # TODO a tool to automatically remove unused variables from the ArgumentsSpecification (return, and returns) _might_ be nice.
65
- """
66
- dictionaryReplacementStatements = makeDictionaryReplacementStatements(numbaFlow.source_astModule)
67
- # TODO remember that `sequentialCallable` and `sourceSequentialCallable` are two different values.
68
- # Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
143
+ ingredientsParallel.astFunctionDef = Z0Z_lameFindReplace(ingredientsParallel.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
69
144
 
70
- # ===========================================================
71
- sourcePython = numbaFlow.sourceDispatcherCallable
72
- astFunctionDef = extractFunctionDef(sourcePython, numbaFlow.source_astModule)
73
- if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
74
- ingredientsDispatcher = IngredientsFunction(astFunctionDef, LedgerOfImports(numbaFlow.source_astModule))
75
-
76
- # sourceParallelCallable
77
- shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, numbaFlow.sourceDataclassInstanceTaskDistribution)
78
- ingredientsDispatcher.imports.update(shatteredDataclass.ledgerDataclassANDFragments)
79
-
80
- NodeReplacer(
81
- findThis = ifThis.isAssignAndValueIsCallNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
82
- , doThat = Then.insertThisAbove(shatteredDataclass.listAnnAssign4DataclassUnpack)
83
- ).visit(ingredientsDispatcher.astFunctionDef)
84
- NodeReplacer(
85
- findThis = ifThis.isCallNamespace_Identifier(numbaFlow.sourceConcurrencyManagerNamespace, numbaFlow.sourceConcurrencyManagerIdentifier)
86
- , doThat = Then.replaceWith(Make.astCall(Make.astAttribute(Make.astName(numbaFlow.sourceConcurrencyManagerNamespace), numbaFlow.sourceConcurrencyManagerIdentifier)
87
- , listArguments=[Make.astName(numbaFlow.parallelCallable)] + shatteredDataclass.listNameDataclassFragments4Parameters))
88
- ).visit(ingredientsDispatcher.astFunctionDef)
89
-
90
- CapturedAssign: list[ast.AST] = []
91
- CapturedCall: list[ast.Call] = []
92
- findThis = ifThis.isCall
93
- doThat = [Then.appendTo(CapturedCall)]
94
- capture = NodeCollector(findThis, doThat)
95
-
96
- NodeCollector(
97
- findThis = ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(numbaFlow.sourceDataclassInstance))
98
- , doThat = [Then.appendTo(CapturedAssign)
99
- , lambda node: capture.visit(node)]
100
- ).visit(ingredientsDispatcher.astFunctionDef)
101
-
102
- newAssign = CapturedAssign[0]
103
- NodeReplacer(
104
- findThis = lambda node: ifThis.isSubscript(node) and ifThis.isAttribute(node.value) and ifThis.isCall(node.value.value)
105
- , doThat = Then.replaceWith(CapturedCall[0])
106
- ).visit(newAssign)
107
-
108
- NodeReplacer(
109
- findThis = ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier(numbaFlow.sourceDataclassInstance))
110
- , doThat = Then.replaceWith(newAssign)
111
- ).visit(ingredientsDispatcher.astFunctionDef)
112
-
113
- # sourceSequentialCallable
114
- shatteredDataclass = shatter_dataclassesDOTdataclass(numbaFlow.logicalPathModuleDataclass, numbaFlow.sourceDataclassIdentifier, numbaFlow.sourceDataclassInstance)
115
-
116
- ingredientsDispatcher.imports.update(shatteredDataclass.ledgerDataclassANDFragments)
117
-
118
- NodeReplacer(
119
- findThis = ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.sourceSequentialCallable)
120
- , doThat = Then.insertThisAbove(shatteredDataclass.listAnnAssign4DataclassUnpack)
121
- ).visit(ingredientsDispatcher.astFunctionDef)
122
- NodeReplacer(
123
- findThis = ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.sourceSequentialCallable)
124
- , doThat = Then.insertThisBelow([shatteredDataclass.astAssignDataclassRepack])
125
- ).visit(ingredientsDispatcher.astFunctionDef)
126
- NodeReplacer(
127
- findThis = ifThis.isAssignAndValueIsCall_Identifier(numbaFlow.sourceSequentialCallable)
128
- , doThat = Then.replaceWith(Make.astAssign(listTargets=[shatteredDataclass.astTuple4AssignTargetsToFragments], value=Make.astCall(Make.astName(numbaFlow.sequentialCallable), shatteredDataclass.listNameDataclassFragments4Parameters)))
129
- ).visit(ingredientsDispatcher.astFunctionDef)
130
-
131
- ingredientsDispatcher.astFunctionDef.name = numbaFlow.dispatcherCallable
132
-
133
- # ===========================================================
134
- sourcePython = numbaFlow.sourceInitializeCallable
135
- astFunctionDef = extractFunctionDef(sourcePython, numbaFlow.source_astModule)
136
- if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
137
- astFunctionDef = inlineThisFunctionWithTheseValues(astFunctionDef, dictionaryReplacementStatements)
138
- ingredientsInitialize = IngredientsFunction(astFunctionDef, LedgerOfImports(numbaFlow.source_astModule))
139
-
140
- # ===========================================================
141
- sourcePython = numbaFlow.sourceParallelCallable
142
- astFunctionDef = extractFunctionDef(sourcePython, numbaFlow.source_astModule)
143
- if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
144
- astFunctionDef = inlineThisFunctionWithTheseValues(astFunctionDef, dictionaryReplacementStatements)
145
- ingredientsParallel = IngredientsFunction(astFunctionDef, LedgerOfImports(numbaFlow.source_astModule))
146
- ingredientsParallel.astFunctionDef.name = numbaFlow.parallelCallable
147
- ingredientsParallel.astFunctionDef.args = Make.astArgumentsSpecification(args=shatteredDataclass.list_ast_argAnnotated4ArgumentsSpecification)
148
- NodeReplacer(
149
- findThis = ifThis.isReturn
150
- , doThat = Then.replaceWith(Make.astReturn(shatteredDataclass.astTuple4AssignTargetsToFragments))
151
- ).visit(ingredientsParallel.astFunctionDef)
152
-
153
- NodeReplacer(
154
- findThis = ifThis.isReturn
155
- , doThat = Then.replaceWith(Make.astReturn(shatteredDataclass.countingVariableName))
156
- ).visit(ingredientsParallel.astFunctionDef)
157
- ingredientsParallel.astFunctionDef.returns = shatteredDataclass.countingVariableAnnotation
158
- replacementMap = {statement.value: statement.target for statement in shatteredDataclass.listAnnAssign4DataclassUnpack}
159
- ingredientsParallel.astFunctionDef = Z0Z_replaceMatchingASTnodes(ingredientsParallel.astFunctionDef, replacementMap) # type: ignore
145
+ # numba decorators =========================================
160
146
  ingredientsParallel = decorateCallableWithNumba(ingredientsParallel)
161
-
162
- # ===========================================================
163
- sourcePython = numbaFlow.sourceSequentialCallable
164
- astFunctionDef = extractFunctionDef(sourcePython, numbaFlow.source_astModule)
165
- if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
166
- astFunctionDef = inlineThisFunctionWithTheseValues(astFunctionDef, dictionaryReplacementStatements)
167
- ingredientsSequential = IngredientsFunction(astFunctionDef, LedgerOfImports(numbaFlow.source_astModule))
168
- ingredientsSequential.astFunctionDef.name = numbaFlow.sequentialCallable
169
- ingredientsSequential.astFunctionDef.args = Make.astArgumentsSpecification(args=shatteredDataclass.list_ast_argAnnotated4ArgumentsSpecification)
170
- NodeReplacer(
171
- findThis = ifThis.isReturn
172
- , doThat = Then.replaceWith(Make.astReturn(shatteredDataclass.astTuple4AssignTargetsToFragments))
173
- ).visit(ingredientsSequential.astFunctionDef)
174
- NodeReplacer(
175
- findThis = ifThis.isReturn
176
- , doThat = Then.replaceWith(Make.astReturn(shatteredDataclass.astTuple4AssignTargetsToFragments))
177
- ).visit(ingredientsSequential.astFunctionDef)
178
- ingredientsSequential.astFunctionDef.returns = shatteredDataclass.astSubscriptPrimitiveTupleAnnotations4FunctionDef_returns
179
- replacementMap = {statement.value: statement.target for statement in shatteredDataclass.listAnnAssign4DataclassUnpack}
180
- ingredientsSequential.astFunctionDef = Z0Z_replaceMatchingASTnodes(ingredientsSequential.astFunctionDef, replacementMap) # type: ignore
181
147
  ingredientsSequential = decorateCallableWithNumba(ingredientsSequential)
182
148
 
183
- # ===========================================================
184
- ingredientsModuleNumbaUnified = IngredientsModule(
185
- ingredientsFunction=[ingredientsInitialize,
186
- ingredientsParallel,
187
- ingredientsSequential,
188
- ingredientsDispatcher], imports=LedgerOfImports(numbaFlow.source_astModule))
149
+ # Module-level transformations ===========================================================
150
+ ingredientsModuleNumbaUnified = IngredientsModule(ingredientsFunction=listAllIngredientsFunctions, imports=LedgerOfImports(numbaFlow.source_astModule))
189
151
 
190
- write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageName)
152
+ write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
191
153
 
154
+ theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
192
155
  if __name__ == '__main__':
193
- makeNumbaFlow()
156
+ makeNumbaFlow(theNumbaFlow)
@@ -0,0 +1,247 @@
1
+ """Synthesize one file to compute `foldsTotal` of `mapShape`."""
2
+ from mapFolding.someAssemblyRequired import ast_Identifier, be, ifThis, Make, NodeChanger, NodeTourist, parsePathFilename2astModule, str_nameDOTname, Then, write_astModule, 又
3
+ from mapFolding.someAssemblyRequired.ingredientsNumba import decorateCallableWithNumba, ParametersNumba, parametersNumbaDefault
4
+ from mapFolding.someAssemblyRequired.synthesizeNumbaFlow import theNumbaFlow
5
+ from mapFolding.someAssemblyRequired.transformDataStructures import makeInitializedComputationState, shatter_dataclassesDOTdataclass, ShatteredDataclass
6
+ from mapFolding.someAssemblyRequired._toolboxContainers import astModuleToIngredientsFunction, IngredientsFunction, IngredientsModule, LedgerOfImports
7
+ from mapFolding.filesystem import getFilenameFoldsTotal, getPathFilenameFoldsTotal, getPathRootJobDEFAULT
8
+ from mapFolding.theSSOT import ComputationState, The
9
+ from pathlib import Path, PurePosixPath
10
+ from typing import cast
11
+ from Z0Z_tools import autoDecodingRLE
12
+ import ast
13
+ import dataclasses
14
+
15
+ list_IdentifiersNotUsedAllHARDCODED = ['concurrencyLimit', 'foldsTotal', 'mapShape',]
16
+ list_IdentifiersNotUsedParallelSequentialHARDCODED = ['indexLeaf']
17
+ list_IdentifiersNotUsedSequentialHARDCODED = ['foldGroups', 'taskDivisions', 'taskIndex',]
18
+
19
+ list_IdentifiersReplacedHARDCODED = ['groupsOfFolds',]
20
+
21
+ list_IdentifiersStaticValuesHARDCODED = ['dimensionsTotal', 'leavesTotal',]
22
+
23
+ list_IdentifiersNotUsedHARDCODED = list_IdentifiersStaticValuesHARDCODED + list_IdentifiersReplacedHARDCODED + list_IdentifiersNotUsedAllHARDCODED + list_IdentifiersNotUsedParallelSequentialHARDCODED + list_IdentifiersNotUsedSequentialHARDCODED
24
+
25
+ @dataclasses.dataclass
26
+ class Z0Z_RecipeJob:
27
+ state: ComputationState
28
+ # TODO create function to calculate `foldsTotalEstimated`
29
+ foldsTotalEstimated: int = 0
30
+ useNumbaProgressBar: bool = True
31
+ numbaProgressBarIdentifier: ast_Identifier = 'ProgressBarGroupsOfFolds'
32
+ shatteredDataclass: ShatteredDataclass = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
33
+
34
+ # ========================================
35
+ # Source
36
+ source_astModule = parsePathFilename2astModule(theNumbaFlow.pathFilenameSequential)
37
+ sourceCountCallable: ast_Identifier = theNumbaFlow.callableSequential
38
+
39
+ sourceLogicalPathModuleDataclass: str_nameDOTname = theNumbaFlow.logicalPathModuleDataclass
40
+ sourceDataclassIdentifier: ast_Identifier = theNumbaFlow.dataclassIdentifier
41
+ sourceDataclassInstance: ast_Identifier = theNumbaFlow.dataclassInstance
42
+
43
+ sourcePathPackage: PurePosixPath | None = theNumbaFlow.pathPackage
44
+ sourcePackageIdentifier: ast_Identifier | None = theNumbaFlow.packageIdentifier
45
+
46
+ # ========================================
47
+ # Filesystem (names of physical objects)
48
+ pathPackage: PurePosixPath | None = None
49
+ pathModule: PurePosixPath | None = PurePosixPath(getPathRootJobDEFAULT())
50
+ """ `pathModule` will override `pathPackage` and `logicalPathRoot`."""
51
+ fileExtension: str = theNumbaFlow.fileExtension
52
+ pathFilenameFoldsTotal: PurePosixPath = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
53
+
54
+ # ========================================
55
+ # Logical identifiers (as opposed to physical identifiers)
56
+ # ========================================
57
+ packageIdentifier: ast_Identifier | None = None
58
+ logicalPathRoot: str_nameDOTname | None = None
59
+ """ `logicalPathRoot` likely corresponds to a physical filesystem directory."""
60
+ moduleIdentifier: ast_Identifier = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
61
+ countCallable: ast_Identifier = sourceCountCallable
62
+ dataclassIdentifier: ast_Identifier | None = sourceDataclassIdentifier
63
+ dataclassInstance: ast_Identifier | None = sourceDataclassInstance
64
+ logicalPathModuleDataclass: str_nameDOTname | None = sourceLogicalPathModuleDataclass
65
+
66
+ def _makePathFilename(self,
67
+ pathRoot: PurePosixPath | None = None,
68
+ logicalPathINFIX: str_nameDOTname | None = None,
69
+ filenameStem: str | None = None,
70
+ fileExtension: str | None = None,
71
+ ) -> PurePosixPath:
72
+ if pathRoot is None:
73
+ pathRoot = self.pathPackage or PurePosixPath(Path.cwd())
74
+ if logicalPathINFIX:
75
+ whyIsThisStillAThing: list[str] = logicalPathINFIX.split('.')
76
+ pathRoot = pathRoot.joinpath(*whyIsThisStillAThing)
77
+ if filenameStem is None:
78
+ filenameStem = self.moduleIdentifier
79
+ if fileExtension is None:
80
+ fileExtension = self.fileExtension
81
+ filename: str = filenameStem + fileExtension
82
+ return pathRoot.joinpath(filename)
83
+
84
+ @property
85
+ def pathFilenameModule(self) -> PurePosixPath:
86
+ if self.pathModule is None:
87
+ return self._makePathFilename()
88
+ else:
89
+ return self._makePathFilename(pathRoot=self.pathModule, logicalPathINFIX=None)
90
+
91
+ def __post_init__(self):
92
+ pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(self.state.mapShape))
93
+
94
+ if self.moduleIdentifier is None:
95
+ self.moduleIdentifier = pathFilenameFoldsTotal.stem
96
+
97
+ if self.pathFilenameFoldsTotal is None:
98
+ self.pathFilenameFoldsTotal = pathFilenameFoldsTotal
99
+
100
+ if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.dataclassIdentifier and self.dataclassInstance:
101
+ self.shatteredDataclass = shatter_dataclassesDOTdataclass(self.logicalPathModuleDataclass, self.dataclassIdentifier, self.dataclassInstance)
102
+
103
+ # ========================================
104
+ # Fields you probably don't need =================================
105
+ # Dispatcher =================================
106
+ sourceDispatcherCallable: ast_Identifier = theNumbaFlow.callableDispatcher
107
+ dispatcherCallable: ast_Identifier = sourceDispatcherCallable
108
+ # Parallel counting =================================
109
+ sourceDataclassInstanceTaskDistribution: ast_Identifier = theNumbaFlow.dataclassInstanceTaskDistribution
110
+ sourceConcurrencyManagerNamespace: ast_Identifier = theNumbaFlow.concurrencyManagerNamespace
111
+ sourceConcurrencyManagerIdentifier: ast_Identifier = theNumbaFlow.concurrencyManagerIdentifier
112
+ dataclassInstanceTaskDistribution: ast_Identifier = sourceDataclassInstanceTaskDistribution
113
+ concurrencyManagerNamespace: ast_Identifier = sourceConcurrencyManagerNamespace
114
+ concurrencyManagerIdentifier: ast_Identifier = sourceConcurrencyManagerIdentifier
115
+
116
+ def addLauncherNumbaProgress(ingredientsModule: IngredientsModule, ingredientsFunction: IngredientsFunction, job: Z0Z_RecipeJob) -> IngredientsModule:
117
+
118
+ linesLaunch: str = f"""
119
+ if __name__ == '__main__':
120
+ with ProgressBar(total={job.foldsTotalEstimated}, update_interval=2) as statusUpdate:
121
+ {job.countCallable}(statusUpdate)
122
+ foldsTotal = statusUpdate.n * {job.state.leavesTotal}
123
+ print('map {job.state.mapShape} =', foldsTotal)
124
+ writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
125
+ writeStream.write(str(foldsTotal))
126
+ writeStream.close()
127
+ """
128
+ numba_progressPythonClass: ast_Identifier = 'ProgressBar'
129
+ numba_progressNumbaType: ast_Identifier = 'ProgressBarType'
130
+ ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressPythonClass)
131
+ ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressNumbaType)
132
+
133
+ ast_argNumbaProgress = ast.arg(arg=job.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
134
+ ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
135
+
136
+ findThis = ifThis.isAugAssign_targetIs(ifThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
137
+ doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(job.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
138
+ countWithProgressBar = NodeChanger(findThis, doThat)
139
+ countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
140
+
141
+ ingredientsModule.appendLauncher(ast.parse(linesLaunch))
142
+
143
+ return ingredientsModule
144
+
145
+ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job: Z0Z_RecipeJob) -> IngredientsFunction:
146
+ ingredientsFunction.imports.update(job.shatteredDataclass.ledger)
147
+
148
+ list_IdentifiersNotUsed = list_IdentifiersNotUsedHARDCODED
149
+
150
+ list_argCauseMyBrainRefusesToDoThisTheRightWay = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
151
+ for ast_arg in list_argCauseMyBrainRefusesToDoThisTheRightWay:
152
+ if ast_arg.arg in job.shatteredDataclass.field2AnnAssign:
153
+ if ast_arg.arg in list_IdentifiersNotUsed:
154
+ pass
155
+ else:
156
+ ImaAnnAssign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
157
+ match elementConstructor:
158
+ case 'scalar':
159
+ ImaAnnAssign.value.args[0].value = int(job.state.__dict__[ast_arg.arg]) # type: ignore
160
+ case 'array':
161
+ # print(ast.dump(ImaAnnAssign))
162
+ dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], addSpaces=True)
163
+ dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
164
+ ImaAnnAssign.value.args = [dataAs_astExpr] # type: ignore
165
+ case _:
166
+ list_exprDOTannotation: list[ast.expr] = []
167
+ list_exprDOTvalue: list[ast.expr] = []
168
+ for dimension in job.state.mapShape:
169
+ list_exprDOTannotation.append(Make.Name(elementConstructor))
170
+ list_exprDOTvalue.append(Make.Call(Make.Name(elementConstructor), [Make.Constant(dimension)]))
171
+ ImaAnnAssign.annotation.slice.elts = list_exprDOTannotation # type: ignore
172
+ ImaAnnAssign.value.elts = list_exprDOTvalue # type: ignore
173
+
174
+ ingredientsFunction.astFunctionDef.body.insert(0, ImaAnnAssign)
175
+
176
+ findThis = ifThis.is_arg_Identifier(ast_arg.arg)
177
+ remove_arg = NodeChanger(findThis, Then.removeIt)
178
+ remove_arg.visit(ingredientsFunction.astFunctionDef)
179
+
180
+ ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
181
+ return ingredientsFunction
182
+
183
+ def makeJobNumba(job: Z0Z_RecipeJob, parametersNumba: ParametersNumba = parametersNumbaDefault):
184
+ # get the raw ingredients: data and the algorithm
185
+ ingredientsCount: IngredientsFunction = astModuleToIngredientsFunction(job.source_astModule, job.countCallable)
186
+
187
+ # Change the return so you can dynamically determine which variables are not used
188
+ removeReturnStatement = NodeChanger(be.Return, Then.removeIt)
189
+ removeReturnStatement.visit(ingredientsCount.astFunctionDef)
190
+ ingredientsCount.astFunctionDef.returns = Make.Constant(value=None)
191
+
192
+ # Remove `foldGroups` and any other unused statements, so you can dynamically determine which variables are not used
193
+ findThis = ifThis.isAssignAndTargets0Is(ifThis.isSubscript_Identifier('foldGroups'))
194
+ doThat = Then.removeIt
195
+ remove_foldGroups = NodeChanger(findThis, doThat)
196
+ remove_foldGroups.visit(ingredientsCount.astFunctionDef)
197
+
198
+ # replace identifiers with static values with their values, so you can dynamically determine which variables are not used
199
+ list_IdentifiersStaticValues = list_IdentifiersStaticValuesHARDCODED
200
+ for identifier in list_IdentifiersStaticValues:
201
+ findThis = ifThis.isName_Identifier(identifier)
202
+ doThat = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
203
+ NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
204
+
205
+ # This launcher eliminates the use of one identifier, so run it now and you can dynamically determine which variables are not used
206
+ ingredientsModule = IngredientsModule()
207
+ ingredientsModule = addLauncherNumbaProgress(ingredientsModule, ingredientsCount, job)
208
+ parametersNumba['nogil'] = True
209
+
210
+ ingredientsCount = move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsCount, job)
211
+
212
+ ingredientsCount.astFunctionDef.decorator_list = [] # TODO low-priority, handle this more elegantly
213
+ # TODO when I add the function signature in numba style back to the decorator, the logic needs to handle `ProgressBarType:`
214
+ ingredientsCount = decorateCallableWithNumba(ingredientsCount, parametersNumba)
215
+
216
+ ingredientsModule.appendIngredientsFunction(ingredientsCount)
217
+
218
+ # add imports, make str, remove unused imports
219
+ # put on disk
220
+ write_astModule(ingredientsModule, job.pathFilenameModule, job.packageIdentifier)
221
+
222
+ """
223
+ Overview
224
+ - the code starts life in theDao.py, which has many optimizations;
225
+ - `makeNumbaOptimizedFlow` increase optimization especially by using numba;
226
+ - `makeJobNumba` increases optimization especially by limiting its capabilities to just one set of parameters
227
+ - the synthesized module must run well as a standalone interpreted-Python script
228
+ - the next major optimization step will (probably) be to use the module synthesized by `makeJobNumba` to compile a standalone executable
229
+ - 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
230
+
231
+ Necessary
232
+ - Move the function's parameters to the function body,
233
+ - initialize identifiers with their state types and values,
234
+
235
+ Optimizations
236
+ - replace static-valued identifiers with their values
237
+ - narrowly focused imports
238
+
239
+ Minutia
240
+ - do not use `with` statement inside numba jitted code, except to use numba's obj mode
241
+ """
242
+
243
+ if __name__ == '__main__':
244
+ mapShape = (6,6)
245
+ state = makeInitializedComputationState(mapShape)
246
+ aJob = Z0Z_RecipeJob(state)
247
+ makeJobNumba(aJob)