mapFolding 0.12.0__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 +80 -18
  12. mapFolding/someAssemblyRequired/_toolkitContainers.py +123 -45
  13. mapFolding/someAssemblyRequired/infoBooth.py +37 -2
  14. mapFolding/someAssemblyRequired/makeAllModules.py +712 -0
  15. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +111 -48
  16. mapFolding/someAssemblyRequired/toolkitNumba.py +171 -19
  17. mapFolding/someAssemblyRequired/transformationTools.py +93 -49
  18. mapfolding-0.12.2.dist-info/METADATA +167 -0
  19. mapfolding-0.12.2.dist-info/RECORD +53 -0
  20. {mapfolding-0.12.0.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.0.dist-info/METADATA +0 -184
  31. mapfolding-0.12.0.dist-info/RECORD +0 -53
  32. {mapfolding-0.12.0.dist-info → mapfolding-0.12.2.dist-info}/entry_points.txt +0 -0
  33. {mapfolding-0.12.0.dist-info → mapfolding-0.12.2.dist-info}/licenses/LICENSE +0 -0
  34. {mapfolding-0.12.0.dist-info → mapfolding-0.12.2.dist-info}/top_level.txt +0 -0
@@ -1,433 +0,0 @@
1
- from astToolkit import (
2
- astModuleToIngredientsFunction,
3
- Be,
4
- ClassIsAndAttribute,
5
- DOT,
6
- extractClassDef,
7
- extractFunctionDef,
8
- Grab,
9
- IngredientsFunction,
10
- IngredientsModule,
11
- LedgerOfImports,
12
- Make,
13
- NodeChanger,
14
- NodeTourist,
15
- parseLogicalPath2astModule,
16
- parsePathFilename2astModule,
17
- str_nameDOTname,
18
- Then,
19
- )
20
- from astToolkit.transformationTools import inlineFunctionDef, removeUnusedParameters, write_astModule
21
- from collections.abc import Sequence
22
- from mapFolding import packageSettings
23
- from mapFolding.someAssemblyRequired import (
24
- DeReConstructField2ast,
25
- IfThis,
26
- raiseIfNone,
27
- ShatteredDataclass,
28
- sourceCallableDispatcherDEFAULT,
29
- )
30
- from mapFolding.someAssemblyRequired.infoBooth import algorithmSourceModuleDEFAULT, dataPackingModuleIdentifierDEFAULT, logicalPathInfixDEFAULT, sourceCallableIdentifierDEFAULT, theCountingIdentifierDEFAULT
31
- from mapFolding.someAssemblyRequired.toolkitNumba import decorateCallableWithNumba, parametersNumbaLight
32
- from mapFolding.someAssemblyRequired.transformationTools import (
33
- removeDataclassFromFunction,
34
- shatter_dataclassesDOTdataclass,
35
- unpackDataclassCallFunctionRepackDataclass,
36
- )
37
- from os import PathLike
38
- from pathlib import PurePath
39
- from typing import cast
40
- from Z0Z_tools import importLogicalPath2Callable
41
- import ast
42
- import dataclasses
43
-
44
- def findDataclass(ingredientsFunction: IngredientsFunction) -> tuple[str, str, str]:
45
- dataclassName: ast.expr = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.annotation)).captureLastMatch(ingredientsFunction.astFunctionDef))
46
- dataclass_Identifier: str = raiseIfNone(NodeTourist(Be.Name, Then.extractIt(DOT.id)).captureLastMatch(dataclassName))
47
- dataclassLogicalPathModule = None
48
- for moduleWithLogicalPath, listNameTuples in ingredientsFunction.imports.dictionaryImportFrom.items():
49
- for nameTuple in listNameTuples:
50
- if nameTuple[0] == dataclass_Identifier:
51
- dataclassLogicalPathModule = moduleWithLogicalPath
52
- break
53
- if dataclassLogicalPathModule:
54
- break
55
- dataclassInstanceIdentifier = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
56
- return raiseIfNone(dataclassLogicalPathModule), dataclass_Identifier, dataclassInstanceIdentifier
57
-
58
- def _getLogicalPath(packageName: str | None = None, logicalPathInfix: str | None = None, moduleIdentifier: str | None = None, *modules: str) -> str_nameDOTname:
59
- listLogicalPathParts: list[str] = []
60
- if packageName:
61
- listLogicalPathParts.append(packageName)
62
- if logicalPathInfix:
63
- listLogicalPathParts.append(logicalPathInfix)
64
- if moduleIdentifier:
65
- listLogicalPathParts.append(moduleIdentifier)
66
- if modules:
67
- listLogicalPathParts.extend(modules)
68
- logicalPath = '.'.join(listLogicalPathParts)
69
- return logicalPath
70
-
71
- def getModule(packageName: str | None = packageSettings.packageName, logicalPathInfix: str | None = logicalPathInfixDEFAULT, moduleIdentifier: str | None = algorithmSourceModuleDEFAULT) -> ast.Module:
72
- logicalPathSourceModule = _getLogicalPath(packageName, logicalPathInfix, moduleIdentifier)
73
- astModule = parseLogicalPath2astModule(logicalPathSourceModule)
74
- return astModule
75
-
76
- def _getPathFilename(pathRoot: PathLike[str] | PurePath | None = packageSettings.pathPackage, logicalPathInfix: PathLike[str] | PurePath | str | None = None, moduleIdentifier: str = '', fileExtension: str = packageSettings.fileExtension) -> PurePath:
77
- pathFilename = PurePath(moduleIdentifier + fileExtension)
78
- if logicalPathInfix:
79
- pathFilename = PurePath(logicalPathInfix, pathFilename)
80
- if pathRoot:
81
- pathFilename = PurePath(pathRoot, pathFilename)
82
- return pathFilename
83
-
84
- def makeInitializeGroupsOfFolds(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
85
- sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
86
- if callableIdentifier is None:
87
- callableIdentifier = sourceCallableIdentifier
88
- ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
89
- ingredientsFunction.astFunctionDef.name = callableIdentifier
90
-
91
- dataclassInstanceIdentifier = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
92
- theCountingIdentifier = theCountingIdentifierDEFAULT
93
-
94
- findThis = IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
95
- doThat = Grab.testAttribute(Grab.andDoAllOf([Grab.opsAttribute(Then.replaceWith([ast.Eq()])), Grab.leftAttribute(Grab.attrAttribute(Then.replaceWith(theCountingIdentifier)))])) # pyright: ignore[reportArgumentType]
96
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef.body[0])
97
-
98
- ingredientsModule = IngredientsModule(ingredientsFunction)
99
- pathFilename = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
100
- write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
101
-
102
- return pathFilename
103
-
104
- def makeDaoOfMapFolding(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
105
- sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
106
- ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
107
-
108
- if callableIdentifier is None:
109
- callableIdentifier = sourceCallableIdentifier
110
- ingredientsFunction.astFunctionDef.name = callableIdentifier
111
-
112
- shatteredDataclass = shatter_dataclassesDOTdataclass(*findDataclass(ingredientsFunction))
113
-
114
- ingredientsFunction.imports.update(shatteredDataclass.imports)
115
- ingredientsFunction = removeDataclassFromFunction(ingredientsFunction, shatteredDataclass)
116
- ingredientsFunction = removeUnusedParameters(ingredientsFunction)
117
- ingredientsFunction = decorateCallableWithNumba(ingredientsFunction, parametersNumbaLight)
118
-
119
- ingredientsModule = IngredientsModule(ingredientsFunction)
120
-
121
- if sourceCallableDispatcher is not None:
122
-
123
- ingredientsFunctionDispatcher: IngredientsFunction = astModuleToIngredientsFunction(astModule, sourceCallableDispatcher)
124
- ingredientsFunctionDispatcher.imports.update(shatteredDataclass.imports)
125
- targetCallableIdentifier = ingredientsFunction.astFunctionDef.name
126
- ingredientsFunctionDispatcher = unpackDataclassCallFunctionRepackDataclass(ingredientsFunctionDispatcher, targetCallableIdentifier, shatteredDataclass)
127
- astTuple = raiseIfNone(NodeTourist(Be.Return, Then.extractIt(DOT.value)).captureLastMatch(ingredientsFunction.astFunctionDef))
128
- cast(ast.Tuple, astTuple).ctx = ast.Store()
129
-
130
- findThis = ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCall_Identifier(targetCallableIdentifier))
131
- doThat = Then.replaceWith(Make.Assign([astTuple], value=Make.Call(Make.Name(targetCallableIdentifier), cast(ast.Tuple, astTuple).elts)))
132
- changeAssignCallToTarget = NodeChanger(findThis, doThat)
133
- changeAssignCallToTarget.visit(ingredientsFunctionDispatcher.astFunctionDef)
134
-
135
- ingredientsModule.appendIngredientsFunction(ingredientsFunctionDispatcher)
136
-
137
- ingredientsModule.removeImportFromModule('numpy')
138
-
139
- pathFilename = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
140
-
141
- write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
142
-
143
- return pathFilename
144
-
145
- def makeDaoOfMapFoldingParallel(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
146
- sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
147
- if callableIdentifier is None:
148
- callableIdentifier = sourceCallableIdentifier
149
- ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
150
- ingredientsFunction.astFunctionDef.name = callableIdentifier
151
-
152
- dataclassName: ast.expr = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.annotation)).captureLastMatch(ingredientsFunction.astFunctionDef))
153
- dataclass_Identifier: str = raiseIfNone(NodeTourist(Be.Name, Then.extractIt(DOT.id)).captureLastMatch(dataclassName))
154
-
155
- dataclassLogicalPathModule = None
156
- for moduleWithLogicalPath, listNameTuples in ingredientsFunction.imports.dictionaryImportFrom.items():
157
- for nameTuple in listNameTuples:
158
- if nameTuple[0] == dataclass_Identifier:
159
- dataclassLogicalPathModule = moduleWithLogicalPath
160
- break
161
- if dataclassLogicalPathModule:
162
- break
163
- if dataclassLogicalPathModule is None: raise Exception
164
- dataclassInstanceIdentifier = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
165
- shatteredDataclass = shatter_dataclassesDOTdataclass(dataclassLogicalPathModule, dataclass_Identifier, dataclassInstanceIdentifier)
166
-
167
- # Start add the parallel state fields to the count function ================================================
168
- dataclassBaseFields = dataclasses.fields(importLogicalPath2Callable(dataclassLogicalPathModule, dataclass_Identifier)) # pyright: ignore [reportArgumentType]
169
- dataclass_IdentifierParallel = 'Parallel' + dataclass_Identifier
170
- dataclassFieldsParallel = dataclasses.fields(importLogicalPath2Callable(dataclassLogicalPathModule, dataclass_IdentifierParallel)) # pyright: ignore [reportArgumentType]
171
- onlyParallelFields = [field for field in dataclassFieldsParallel if field.name not in [fieldBase.name for fieldBase in dataclassBaseFields]]
172
-
173
- Official_fieldOrder: list[str] = []
174
- dictionaryDeReConstruction: dict[str, DeReConstructField2ast] = {}
175
-
176
- dataclassClassDef = extractClassDef(parseLogicalPath2astModule(dataclassLogicalPathModule), dataclass_IdentifierParallel)
177
- if not isinstance(dataclassClassDef, ast.ClassDef): raise ValueError(f"I could not find `{dataclass_IdentifierParallel = }` in `{dataclassLogicalPathModule = }`.")
178
-
179
- for aField in onlyParallelFields:
180
- Official_fieldOrder.append(aField.name)
181
- dictionaryDeReConstruction[aField.name] = DeReConstructField2ast(dataclassLogicalPathModule, dataclassClassDef, dataclassInstanceIdentifier, aField)
182
-
183
- shatteredDataclassParallel = ShatteredDataclass(
184
- countingVariableAnnotation=shatteredDataclass.countingVariableAnnotation,
185
- countingVariableName=shatteredDataclass.countingVariableName,
186
- field2AnnAssign={**shatteredDataclass.field2AnnAssign, **{dictionaryDeReConstruction[field].name: dictionaryDeReConstruction[field].astAnnAssignConstructor for field in Official_fieldOrder}},
187
- Z0Z_field2AnnAssign={**shatteredDataclass.Z0Z_field2AnnAssign, **{dictionaryDeReConstruction[field].name: dictionaryDeReConstruction[field].Z0Z_hack for field in Official_fieldOrder}},
188
- list_argAnnotated4ArgumentsSpecification=shatteredDataclass.list_argAnnotated4ArgumentsSpecification + [dictionaryDeReConstruction[field].ast_argAnnotated for field in Official_fieldOrder],
189
- list_keyword_field__field4init=shatteredDataclass.list_keyword_field__field4init + [dictionaryDeReConstruction[field].ast_keyword_field__field for field in Official_fieldOrder if dictionaryDeReConstruction[field].init],
190
- listAnnotations=shatteredDataclass.listAnnotations + [dictionaryDeReConstruction[field].astAnnotation for field in Official_fieldOrder],
191
- listName4Parameters=shatteredDataclass.listName4Parameters + [dictionaryDeReConstruction[field].astName for field in Official_fieldOrder],
192
- listUnpack=shatteredDataclass.listUnpack + [Make.AnnAssign(dictionaryDeReConstruction[field].astName, dictionaryDeReConstruction[field].astAnnotation, dictionaryDeReConstruction[field].ast_nameDOTname) for field in Official_fieldOrder],
193
- map_stateDOTfield2Name={**shatteredDataclass.map_stateDOTfield2Name, **{dictionaryDeReConstruction[field].ast_nameDOTname: dictionaryDeReConstruction[field].astName for field in Official_fieldOrder}},
194
- )
195
- shatteredDataclassParallel.fragments4AssignmentOrParameters = Make.Tuple(shatteredDataclassParallel.listName4Parameters, ast.Store())
196
- shatteredDataclassParallel.repack = Make.Assign([Make.Name(dataclassInstanceIdentifier)], value=Make.Call(Make.Name(dataclass_IdentifierParallel), list_keyword=shatteredDataclassParallel.list_keyword_field__field4init))
197
- shatteredDataclassParallel.signatureReturnAnnotation = Make.Subscript(Make.Name('tuple'), Make.Tuple(shatteredDataclassParallel.listAnnotations))
198
-
199
- shatteredDataclassParallel.imports.update(*(dictionaryDeReConstruction[field].ledger for field in Official_fieldOrder))
200
- shatteredDataclassParallel.imports.addImportFrom_asStr(dataclassLogicalPathModule, dataclass_IdentifierParallel)
201
- shatteredDataclassParallel.imports.update(shatteredDataclass.imports)
202
- shatteredDataclassParallel.imports.removeImportFrom(dataclassLogicalPathModule, dataclass_Identifier)
203
-
204
- # End add the parallel state fields to the count function ================================================
205
-
206
- ingredientsFunction.imports.update(shatteredDataclassParallel.imports)
207
- ingredientsFunction = removeDataclassFromFunction(ingredientsFunction, shatteredDataclassParallel)
208
-
209
- # Start add the parallel logic to the count function ================================================
210
-
211
- findThis = ClassIsAndAttribute.testIs(ast.While, ClassIsAndAttribute.leftIs(ast.Compare, IfThis.isName_Identifier('leafConnectee')))
212
- doThat = Then.extractIt(DOT.body)
213
- captureCountGapsCodeBlock: NodeTourist[ast.While, Sequence[ast.stmt]] = NodeTourist(findThis, doThat)
214
- countGapsCodeBlock = raiseIfNone(captureCountGapsCodeBlock.captureLastMatch(ingredientsFunction.astFunctionDef))
215
-
216
- thisIsMyTaskIndexCodeBlock = ast.If(ast.BoolOp(ast.Or()
217
- , values=[ast.Compare(ast.Name('leaf1ndex'), ops=[ast.NotEq()], comparators=[ast.Name('taskDivisions')])
218
- , ast.Compare(ast.BinOp(ast.Name('leafConnectee'), op=ast.Mod(), right=ast.Name('taskDivisions')), ops=[ast.Eq()], comparators=[ast.Name('taskIndex')])])
219
- , body=list(countGapsCodeBlock[0:-1]))
220
-
221
- countGapsCodeBlockNew: list[ast.stmt] = [thisIsMyTaskIndexCodeBlock, countGapsCodeBlock[-1]]
222
-
223
- doThat = Grab.bodyAttribute(Then.replaceWith(countGapsCodeBlockNew))
224
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
225
-
226
- # End add the parallel logic to the count function ================================================
227
-
228
- ingredientsFunction = removeUnusedParameters(ingredientsFunction)
229
-
230
- ingredientsFunction = decorateCallableWithNumba(ingredientsFunction, parametersNumbaLight)
231
-
232
- # Start unpack/repack the dataclass function ================================================
233
- sourceCallableIdentifier = sourceCallableDispatcherDEFAULT
234
-
235
- unRepackDataclass: IngredientsFunction = astModuleToIngredientsFunction(astModule, sourceCallableIdentifier)
236
- unRepackDataclass.astFunctionDef.name = 'unRepack' + dataclass_IdentifierParallel
237
- unRepackDataclass.imports.update(shatteredDataclassParallel.imports)
238
- findThis = ClassIsAndAttribute.annotationIs(ast.arg, IfThis.isName_Identifier(dataclass_Identifier)) # pyright: ignore[reportArgumentType, reportUnknownVariableType, reportCallIssue]
239
- doThat = Grab.annotationAttribute(Grab.idAttribute(Then.replaceWith(dataclass_IdentifierParallel))) # pyright: ignore[reportArgumentType]
240
- NodeChanger(findThis, doThat).visit(unRepackDataclass.astFunctionDef) # pyright: ignore[reportUnknownArgumentType]
241
- unRepackDataclass.astFunctionDef.returns = Make.Name(dataclass_IdentifierParallel)
242
- targetCallableIdentifier = ingredientsFunction.astFunctionDef.name
243
- unRepackDataclass = unpackDataclassCallFunctionRepackDataclass(unRepackDataclass, targetCallableIdentifier, shatteredDataclassParallel)
244
-
245
- astTuple = raiseIfNone(NodeTourist(Be.Return, Then.extractIt(DOT.value)).captureLastMatch(ingredientsFunction.astFunctionDef))
246
- cast(ast.Tuple, astTuple).ctx = ast.Store()
247
- findThis = ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCall_Identifier(targetCallableIdentifier))
248
- doThat = Then.replaceWith(Make.Assign([astTuple], value=Make.Call(Make.Name(targetCallableIdentifier), cast(ast.Tuple, astTuple).elts)))
249
- changeAssignCallToTarget = NodeChanger(findThis, doThat)
250
- changeAssignCallToTarget.visit(unRepackDataclass.astFunctionDef)
251
-
252
- ingredientsDoTheNeedful: IngredientsFunction = IngredientsFunction(
253
- astFunctionDef = ast.FunctionDef(name='doTheNeedful'
254
- , args=ast.arguments(args=[ast.arg('state', annotation=ast.Name(dataclass_IdentifierParallel)), ast.arg('concurrencyLimit', annotation=ast.Name('int'))])
255
- , body=[ast.Assign(targets=[ast.Name('stateParallel', ctx=ast.Store())], value=ast.Call(func=ast.Name('deepcopy'), args=[ast.Name('state')]))
256
- , ast.AnnAssign(target=ast.Name('listStatesParallel', ctx=ast.Store()), annotation=ast.Subscript(value=ast.Name('list'), slice=ast.Name(dataclass_IdentifierParallel)), value=ast.BinOp(left=ast.List(elts=[ast.Name('stateParallel')]), op=ast.Mult(), right=ast.Attribute(value=ast.Name('stateParallel'), attr='taskDivisions')), simple=1)
257
- , ast.AnnAssign(target=ast.Name('groupsOfFoldsTotal', ctx=ast.Store()), annotation=ast.Name('int'), value=ast.Constant(value=0), simple=1)
258
-
259
- , ast.AnnAssign(target=ast.Name('dictionaryConcurrency', ctx=ast.Store()), annotation=ast.Subscript(value=ast.Name('dict'), slice=ast.Tuple(elts=[ast.Name('int'), ast.Subscript(value=ast.Name('ConcurrentFuture'), slice=ast.Name(dataclass_IdentifierParallel))])), value=ast.Dict(), simple=1)
260
- , ast.With(items=[ast.withitem(context_expr=ast.Call(func=ast.Name('ProcessPoolExecutor'), args=[ast.Name('concurrencyLimit')]), optional_vars=ast.Name('concurrencyManager', ctx=ast.Store()))]
261
- , body=[ast.For(target=ast.Name('indexSherpa', ctx=ast.Store()), iter=ast.Call(func=ast.Name('range'), args=[ast.Attribute(value=ast.Name('stateParallel'), attr='taskDivisions')])
262
- , body=[ast.Assign(targets=[ast.Name('state', ctx=ast.Store())], value=ast.Call(func=ast.Name('deepcopy'), args=[ast.Name('stateParallel')]))
263
- , ast.Assign(targets=[ast.Attribute(value=ast.Name('state'), attr='taskIndex', ctx=ast.Store())], value=ast.Name('indexSherpa'))
264
- , ast.Assign(targets=[ast.Subscript(value=ast.Name('dictionaryConcurrency'), slice=ast.Name('indexSherpa'), ctx=ast.Store())], value=ast.Call(func=ast.Attribute(value=ast.Name('concurrencyManager'), attr='submit'), args=[ast.Name(unRepackDataclass.astFunctionDef.name), ast.Name('state')]))])
265
- , ast.For(target=ast.Name('indexSherpa', ctx=ast.Store()), iter=ast.Call(func=ast.Name('range'), args=[ast.Attribute(value=ast.Name('stateParallel'), attr='taskDivisions')])
266
- , body=[ast.Assign(targets=[ast.Subscript(value=ast.Name('listStatesParallel'), slice=ast.Name('indexSherpa'), ctx=ast.Store())], value=ast.Call(func=ast.Attribute(value=ast.Subscript(value=ast.Name('dictionaryConcurrency'), slice=ast.Name('indexSherpa')), attr='result')))
267
- , ast.AugAssign(target=ast.Name('groupsOfFoldsTotal', ctx=ast.Store()), op=ast.Add(), value=ast.Attribute(value=ast.Subscript(value=ast.Name('listStatesParallel'), slice=ast.Name('indexSherpa')), attr='groupsOfFolds'))])])
268
-
269
- , ast.AnnAssign(target=ast.Name('foldsTotal', ctx=ast.Store()), annotation=ast.Name('int'), value=ast.BinOp(left=ast.Name('groupsOfFoldsTotal'), op=ast.Mult(), right=ast.Attribute(value=ast.Name('stateParallel'), attr='leavesTotal')), simple=1)
270
- , ast.Return(value=ast.Tuple(elts=[ast.Name('foldsTotal'), ast.Name('listStatesParallel')]))]
271
- , returns=ast.Subscript(value=ast.Name('tuple'), slice=ast.Tuple(elts=[ast.Name('int'), ast.Subscript(value=ast.Name('list'), slice=ast.Name(dataclass_IdentifierParallel))])))
272
- , imports = LedgerOfImports(Make.Module([ast.ImportFrom(module='concurrent.futures', names=[ast.alias(name='Future', asname='ConcurrentFuture'), ast.alias(name='ProcessPoolExecutor')], level=0),
273
- ast.ImportFrom(module='copy', names=[ast.alias(name='deepcopy')], level=0),
274
- ast.ImportFrom(module='multiprocessing', names=[ast.alias(name='set_start_method', asname='multiprocessing_set_start_method')], level=0),])
275
- )
276
- )
277
-
278
- ingredientsModule = IngredientsModule([ingredientsFunction, unRepackDataclass, ingredientsDoTheNeedful]
279
- , prologue = Make.Module([ast.If(test=ast.Compare(left=ast.Name('__name__'), ops=[ast.Eq()], comparators=[ast.Constant(value='__main__')]), body=[ast.Expr(value=ast.Call(func=ast.Name('multiprocessing_set_start_method'), args=[ast.Constant(value='spawn')]))])])
280
- )
281
- ingredientsModule.removeImportFromModule('numpy')
282
-
283
- pathFilename = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
284
-
285
- write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
286
- return pathFilename
287
-
288
- def makeTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
289
- sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
290
- if callableIdentifier is None:
291
- callableIdentifier = sourceCallableIdentifier
292
- ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
293
- ingredientsFunction.astFunctionDef.name = callableIdentifier
294
-
295
- dataclassInstanceIdentifier = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
296
-
297
- findThis = IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
298
- doThat = Grab.testAttribute(Grab.comparatorsAttribute(Then.replaceWith([Make.Constant(4)]))) # pyright: ignore[reportArgumentType]
299
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
300
-
301
- findThis = IfThis.isIfAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
302
- doThat = Then.extractIt(DOT.body)
303
- insertLeaf = NodeTourist(findThis, doThat).captureLastMatch(ingredientsFunction.astFunctionDef)
304
- findThis = IfThis.isIfAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
305
- doThat = Then.replaceWith(insertLeaf)
306
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
307
-
308
- findThis = IfThis.isAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
309
- doThat = Then.removeIt
310
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
311
-
312
- findThis = IfThis.isAttributeNamespaceIdentifierLessThanOrEqual0(dataclassInstanceIdentifier, 'leaf1ndex')
313
- doThat = Then.removeIt
314
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
315
-
316
- theCountingIdentifier = theCountingIdentifierDEFAULT
317
- doubleTheCount = Make.AugAssign(Make.Attribute(ast.Name(dataclassInstanceIdentifier), theCountingIdentifier), ast.Mult(), Make.Constant(2))
318
- findThis = Be.Return
319
- doThat = Then.insertThisAbove([doubleTheCount])
320
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
321
-
322
- ingredientsModule = IngredientsModule(ingredientsFunction)
323
-
324
- if sourceCallableDispatcher is not None:
325
- raise NotImplementedError('sourceCallableDispatcher is not implemented yet')
326
-
327
- pathFilename = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
328
-
329
- write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
330
-
331
- return pathFilename
332
-
333
- def trimTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
334
- sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
335
- if callableIdentifier is None:
336
- callableIdentifier = sourceCallableIdentifier
337
- ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
338
- ingredientsFunction.astFunctionDef.name = callableIdentifier
339
-
340
- dataclassInstanceIdentifier = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
341
-
342
- findThis = IfThis.isIfUnaryNotAttributeNamespace_Identifier(dataclassInstanceIdentifier, 'dimensionsUnconstrained')
343
- doThat = Then.removeIt
344
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
345
-
346
- ingredientsModule = IngredientsModule(ingredientsFunction)
347
- ingredientsModule.removeImportFromModule('numpy')
348
-
349
- pathFilename = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
350
-
351
- write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
352
-
353
- return pathFilename
354
-
355
- def numbaOnTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
356
- sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
357
- if callableIdentifier is None:
358
- callableIdentifier = sourceCallableIdentifier
359
- ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
360
- ingredientsFunction.astFunctionDef.name = callableIdentifier
361
-
362
- shatteredDataclass = shatter_dataclassesDOTdataclass(*findDataclass(ingredientsFunction))
363
-
364
- ingredientsFunction.imports.update(shatteredDataclass.imports)
365
- ingredientsFunction = removeDataclassFromFunction(ingredientsFunction, shatteredDataclass)
366
- ingredientsFunction = removeUnusedParameters(ingredientsFunction)
367
- ingredientsFunction = decorateCallableWithNumba(ingredientsFunction, parametersNumbaLight)
368
-
369
- ingredientsModule = IngredientsModule(ingredientsFunction)
370
- ingredientsModule.removeImportFromModule('numpy')
371
-
372
- pathFilename = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
373
-
374
- write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
375
-
376
- return pathFilename
377
-
378
- def makeUnRePackDataclass(astImportFrom: ast.ImportFrom) -> None:
379
- callableIdentifierHARDCODED: str = 'sequential'
380
-
381
- algorithmSourceModule = algorithmSourceModuleDEFAULT
382
- sourceCallableIdentifier = sourceCallableDispatcherDEFAULT
383
- logicalPathSourceModule = '.'.join([packageSettings.packageName, algorithmSourceModule])
384
-
385
- logicalPathInfix = logicalPathInfixDEFAULT
386
- moduleIdentifier = dataPackingModuleIdentifierDEFAULT
387
- callableIdentifier = callableIdentifierHARDCODED
388
-
389
- ingredientsFunction: IngredientsFunction = astModuleToIngredientsFunction(parseLogicalPath2astModule(logicalPathSourceModule), sourceCallableIdentifier)
390
- ingredientsFunction.astFunctionDef.name = callableIdentifier
391
-
392
- shatteredDataclass = shatter_dataclassesDOTdataclass(*findDataclass(ingredientsFunction))
393
-
394
- ingredientsFunction.imports.update(shatteredDataclass.imports)
395
- ingredientsFunction.imports.addAst(astImportFrom)
396
- targetCallableIdentifier = astImportFrom.names[0].name
397
- ingredientsFunction = raiseIfNone(unpackDataclassCallFunctionRepackDataclass(ingredientsFunction, targetCallableIdentifier, shatteredDataclass))
398
- targetFunctionDef = raiseIfNone(extractFunctionDef(parseLogicalPath2astModule(raiseIfNone(astImportFrom.module)), targetCallableIdentifier))
399
- astTuple = raiseIfNone(NodeTourist(Be.Return, Then.extractIt(DOT.value)).captureLastMatch(targetFunctionDef))
400
- cast(ast.Tuple, astTuple).ctx = ast.Store()
401
-
402
- findThis = ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCall_Identifier(targetCallableIdentifier))
403
- doThat = Then.replaceWith(Make.Assign([astTuple], value=Make.Call(Make.Name(targetCallableIdentifier), cast(ast.Tuple, astTuple).elts)))
404
- NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
405
-
406
- ingredientsModule = IngredientsModule(ingredientsFunction)
407
- ingredientsModule.removeImportFromModule('numpy')
408
-
409
- pathFilename = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
410
-
411
- write_astModule(ingredientsModule, pathFilename, packageSettings.packageName)
412
-
413
- if __name__ == '__main__':
414
- astModule = getModule(logicalPathInfix=None)
415
- makeInitializeGroupsOfFolds(astModule, 'initializeCount', 'initializeGroupsOfFolds', logicalPathInfixDEFAULT)
416
-
417
- astModule = getModule(logicalPathInfix=None)
418
- pathFilename = makeDaoOfMapFolding(astModule, 'daoOfMapFolding', None, logicalPathInfixDEFAULT, sourceCallableDispatcherDEFAULT)
419
-
420
- astModule = getModule(logicalPathInfix=None)
421
- pathFilename = makeDaoOfMapFoldingParallel(astModule, 'countParallel', None, logicalPathInfixDEFAULT, sourceCallableDispatcherDEFAULT)
422
-
423
- astModule = getModule(logicalPathInfix=None)
424
- pathFilename = makeTheorem2(astModule, 'theorem2', None, logicalPathInfixDEFAULT, None)
425
-
426
- astModule = parsePathFilename2astModule(pathFilename)
427
- pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', None, logicalPathInfixDEFAULT, None)
428
-
429
- astModule = parsePathFilename2astModule(pathFilename)
430
- pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', None, logicalPathInfixDEFAULT, None)
431
-
432
- astImportFrom = Make.ImportFrom(_getLogicalPath(packageSettings.packageName, logicalPathInfixDEFAULT, 'theorem2Numba'), list_alias=[Make.alias(sourceCallableIdentifierDEFAULT)])
433
- makeUnRePackDataclass(astImportFrom)
mapFolding/theSSOT.py DELETED
@@ -1,34 +0,0 @@
1
- from importlib import import_module as importlib_import_module
2
- from inspect import getfile as inspect_getfile
3
- from pathlib import Path
4
- from tomli import load as tomli_load
5
- import dataclasses
6
-
7
- packageNamePACKAGING_HARDCODED = "mapFolding"
8
- concurrencyPackageHARDCODED = 'multiprocessing'
9
-
10
- # Evaluate When Packaging
11
- # https://github.com/hunterhogan/mapFolding/issues/18
12
- try:
13
- packageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
14
- except Exception:
15
- packageNamePACKAGING = packageNamePACKAGING_HARDCODED
16
-
17
- # Evaluate When Installing
18
- # https://github.com/hunterhogan/mapFolding/issues/18
19
- def getPathPackageINSTALLING() -> Path:
20
- pathPackage: Path = Path(inspect_getfile(importlib_import_module(packageNamePACKAGING)))
21
- if pathPackage.is_file():
22
- pathPackage = pathPackage.parent
23
- return pathPackage
24
-
25
- @dataclasses.dataclass
26
- class PackageSettings:
27
- fileExtension: str = dataclasses.field(default='.py', metadata={'evaluateWhen': 'installing'})
28
- packageName: str = dataclasses.field(default = packageNamePACKAGING, metadata={'evaluateWhen': 'packaging'})
29
- pathPackage: Path = dataclasses.field(default_factory=getPathPackageINSTALLING, metadata={'evaluateWhen': 'installing'})
30
- concurrencyPackage: str | None = None
31
- """Package to use for concurrent execution (e.g., 'multiprocessing', 'numba')."""
32
-
33
- concurrencyPackage = concurrencyPackageHARDCODED
34
- packageSettings = PackageSettings(concurrencyPackage=concurrencyPackage)
@@ -1,184 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: mapFolding
3
- Version: 0.12.0
4
- Summary: Map folding algorithm with code transformation framework for optimizing numerical computations
5
- Author-email: Hunter Hogan <HunterHogan@pm.me>
6
- License: CC-BY-NC-4.0
7
- Project-URL: Donate, https://www.patreon.com/integrated
8
- Project-URL: Homepage, https://github.com/hunterhogan/mapFolding
9
- Project-URL: Repository, https://github.com/hunterhogan/mapFolding.git
10
- Project-URL: Issues, https://github.com/hunterhogan/mapFolding/issues
11
- Keywords: A000136,A001415,A001416,A001417,A001418,A195646,algorithmic optimization,AST manipulation,code generation,code transformation,combinatorics,computational geometry,dataclass transformation,folding pattern enumeration,just-in-time compilation,map folding,Numba optimization,OEIS,performance optimization,source code analysis,stamp folding
12
- Classifier: Development Status :: 4 - Beta
13
- Classifier: Environment :: Console
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Intended Audience :: Education
16
- Classifier: Intended Audience :: Science/Research
17
- Classifier: Natural Language :: English
18
- Classifier: Operating System :: OS Independent
19
- Classifier: Programming Language :: Python
20
- Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3.12
22
- Classifier: Programming Language :: Python :: 3.13
23
- Classifier: Topic :: Scientific/Engineering :: Mathematics
24
- Classifier: Topic :: Scientific/Engineering :: Information Analysis
25
- Classifier: Topic :: Software Development :: Code Generators
26
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
- Classifier: Topic :: Software Development :: Compilers
28
- Classifier: Typing :: Typed
29
- Requires-Python: >=3.12
30
- Description-Content-Type: text/markdown
31
- License-File: LICENSE
32
- Requires-Dist: astToolkit
33
- Requires-Dist: autoflake
34
- Requires-Dist: numba_progress
35
- Requires-Dist: numba
36
- Requires-Dist: numpy
37
- Requires-Dist: platformdirs
38
- Requires-Dist: python_minifier
39
- Requires-Dist: sympy
40
- Requires-Dist: tomli
41
- Requires-Dist: Z0Z_tools
42
- Provides-Extra: testing
43
- Requires-Dist: mypy; extra == "testing"
44
- Requires-Dist: pytest; extra == "testing"
45
- Requires-Dist: pytest-cov; extra == "testing"
46
- Requires-Dist: pytest-env; extra == "testing"
47
- Requires-Dist: pytest-xdist; extra == "testing"
48
- Requires-Dist: pyupgrade; extra == "testing"
49
- Requires-Dist: ruff; extra == "testing"
50
- Dynamic: license-file
51
-
52
- # mapFolding: High-Performance Algorithm Playground for Computational Enthusiasts 🗺️
53
-
54
- [![pip install mapFolding](https://img.shields.io/badge/pip%20install-mapFolding-gray.svg?colorB=3b434b)](https://pypi.org/project/mapFolding/)
55
- [![Python Tests](https://github.com/hunterhogan/mapFolding/actions/workflows/pythonTests.yml/badge.svg)](https://github.com/hunterhogan/mapFolding/actions/workflows/pythonTests.yml)
56
- [![License: CC-BY-NC-4.0](https://img.shields.io/badge/License-CC_BY--NC_4.0-3b434b)](https://creativecommons.org/licenses/by-nc/4.0/)
57
-
58
- **This package is for you if:**
59
-
60
- - You're fascinated by computational algorithms and their optimization
61
- - You want to explore AST transformation techniques for Python performance tuning
62
- - You're interested in solving mathematical puzzles through code
63
- - You're learning about Numba and advanced Python optimization
64
-
65
- ## What Does This Package Actually Do?
66
-
67
- `mapFolding` solves a specific mathematical problem: counting the number of distinct ways to fold a rectangular map. While this may sound niche, it's a fascinating computational challenge that demonstrates:
68
-
69
- 1. How to transform readable algorithms into blazingly fast implementations
70
- 2. Advanced techniques for Python optimization using AST manipulation
71
- 3. Numba acceleration with specialized compilation strategies
72
- 4. Algorithms for problems that grow combinatorially
73
-
74
- The package has achieved new computational records, including first-ever calculations for large maps that were previously infeasible.
75
-
76
- ```python
77
- # Compute the number of ways to fold a 5×5 grid:
78
- from mapFolding import oeisIDfor_n
79
- foldsTotal = oeisIDfor_n('A001418', 5)
80
- ```
81
-
82
- ## Key Benefits for Computational Enthusiasts
83
-
84
- ### 1. Algorithm Transformation Laboratory
85
-
86
- See how the same algorithm evolves from readable Python to highly-optimized implementations:
87
-
88
- ```python
89
- # The intuitive, readable version:
90
- def countFolds(mapShape):
91
- # ...implement readable algorithm...
92
-
93
- # The transformed, optimized version (auto-generated):
94
- @numba.jit(nopython=True, parallel=True, fastmath=True)
95
- def countFolds_optimized(shape_param):
96
- # ...blazingly fast implementation...
97
- ```
98
-
99
- ### 2. Code Generation Framework
100
-
101
- Study and extend a complete Python code transformation assembly line:
102
-
103
- - AST analysis and manipulation
104
- - Dataclass decomposition ("shattering")
105
- - Automatic import management
106
- - Type specialization for numerical computing
107
-
108
- ### 3. Exhaustive Test Framework
109
-
110
- Leverage a sophisticated test suite for validating your own optimizations:
111
-
112
- ```python
113
- # Test your own recipe implementation with just a few lines:
114
- @pytest.fixture
115
- def myCustomRecipeFixture(useThisDispatcher, pathTmpTesting):
116
- myRecipe = RecipeSynthesizeFlow(
117
- # Your custom configuration here
118
- )
119
- # ...transformation code...
120
- return customDispatcher
121
-
122
- def test_myCustomImplementation(myCustomRecipeFixture):
123
- # Automatic validation against known values
124
- ```
125
-
126
- ## Installation and Getting Started
127
-
128
- ```sh
129
- pip install mapFolding
130
- ```
131
-
132
- Try a quick calculation:
133
-
134
- ```python
135
- from mapFolding import oeisIDfor_n
136
-
137
- # Calculate ways to fold a 2×4 map
138
- result = oeisIDfor_n('A001415', 4) # Returns 8
139
- print(f"A 2×4 map can be folded {result} different ways")
140
- ```
141
-
142
- ## Mathematical Background (For the Curious)
143
-
144
- The map folding problem was introduced by Lunnon in 1971 and connects to combinatorial geometry, computational complexity, and integer sequence analysis. The calculations provide entries to the Online Encyclopedia of Integer Sequences (OEIS).
145
-
146
- This package implements several OEIS sequences, including:
147
-
148
- - A001415: Number of ways to fold a 2×n strip (now calculated up to n=20!)
149
- - A001418: Number of ways to fold an n×n square grid
150
-
151
- ## Explore the Repository
152
-
153
- The repository structure reveals the package's educational value:
154
-
155
- - `reference/`: Historical implementations and algorithm evolution
156
- - `someAssemblyRequired/`: Code transformation framework
157
- - `tests/`: Comprehensive test suite with fixtures for your own implementations
158
-
159
- ## Who Is This For, Really?
160
-
161
- If you've read this far and are intrigued by computational puzzles, algorithm optimization, or Python performance techniques, this package offers a playground for exploration. It's particularly valuable for:
162
-
163
- - Computer science students studying algorithm optimization
164
- - Python developers exploring Numba and AST manipulation
165
- - Computational mathematicians interested in combinatorial problems
166
- - Anyone fascinated by the intersection of mathematics and computing
167
-
168
- Whether you use it to solve map folding problems or to study its optimization techniques, `mapFolding` offers a unique window into advanced Python programming approaches.
169
-
170
- ## My recovery
171
-
172
- [![Static Badge](https://img.shields.io/badge/2011_August-Homeless_since-blue?style=flat)](https://HunterThinks.com/support)
173
- [![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UC3Gx7kz61009NbhpRtPP7tw)](https://www.youtube.com/@HunterHogan)
174
-
175
- ## How to code
176
-
177
- Coding One Step at a Time:
178
-
179
- 0. WRITE CODE.
180
- 1. Don't write stupid code that's hard to revise.
181
- 2. Write good code.
182
- 3. When revising, write better code.
183
-
184
- [![CC-BY-NC-4.0](https://github.com/hunterhogan/mapFolding/blob/main/CC-BY-NC-4.0.svg)](https://creativecommons.org/licenses/by-nc/4.0/)