mapFolding 0.8.3__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 (30) hide show
  1. mapFolding/__init__.py +2 -2
  2. mapFolding/basecamp.py +11 -5
  3. mapFolding/filesystem.py +134 -109
  4. mapFolding/oeis.py +1 -1
  5. mapFolding/someAssemblyRequired/__init__.py +37 -18
  6. mapFolding/someAssemblyRequired/_theTypes.py +35 -0
  7. mapFolding/someAssemblyRequired/_tool_Make.py +92 -0
  8. mapFolding/someAssemblyRequired/_tool_Then.py +65 -0
  9. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +326 -0
  10. mapFolding/someAssemblyRequired/_toolboxContainers.py +306 -0
  11. mapFolding/someAssemblyRequired/_toolboxPython.py +76 -0
  12. mapFolding/someAssemblyRequired/ingredientsNumba.py +17 -24
  13. mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +114 -169
  14. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +247 -0
  15. mapFolding/someAssemblyRequired/transformDataStructures.py +167 -100
  16. mapFolding/someAssemblyRequired/transformationTools.py +63 -685
  17. mapFolding/syntheticModules/numbaCount_doTheNeedful.py +36 -33
  18. mapFolding/theDao.py +13 -11
  19. mapFolding/theSSOT.py +69 -112
  20. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/METADATA +2 -1
  21. mapfolding-0.8.4.dist-info/RECORD +49 -0
  22. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/WHEEL +1 -1
  23. tests/conftest.py +34 -29
  24. tests/test_computations.py +40 -31
  25. tests/test_filesystem.py +3 -3
  26. mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +0 -413
  27. mapfolding-0.8.3.dist-info/RECORD +0 -43
  28. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/entry_points.txt +0 -0
  29. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/licenses/LICENSE +0 -0
  30. {mapfolding-0.8.3.dist-info → mapfolding-0.8.4.dist-info}/top_level.txt +0 -0
@@ -1,53 +1,62 @@
1
1
  from mapFolding.basecamp import countFolds
2
2
  from mapFolding.filesystem import getPathFilenameFoldsTotal
3
+ from mapFolding.beDRY import validateListDimensions
3
4
  from mapFolding.noHomeYet import getFoldsTotalKnown
4
5
  from mapFolding.oeis import settingsOEIS, oeisIDfor_n
5
- # from mapFolding.someAssemblyRequired import writeJobNumba
6
- from pathlib import Path
6
+ from mapFolding.someAssemblyRequired.synthesizeNumbaJob import makeJobNumba, Z0Z_RecipeJob
7
+ from mapFolding.someAssemblyRequired.transformDataStructures import makeInitializedComputationState
8
+ from pathlib import Path, PurePosixPath
7
9
  from tests.conftest import standardizedEqualToCallableReturn, registrarRecordsTmpObject
8
10
  from types import ModuleType
9
11
  import importlib.util
10
12
  import multiprocessing
13
+ import threading
14
+ from copy import deepcopy
11
15
  import pytest
12
16
 
13
17
  if __name__ == '__main__':
14
18
  multiprocessing.set_start_method('spawn')
15
19
 
16
20
  def test_algorithmSourceParallel(listDimensionsTestParallelization: list[int], useAlgorithmSourceDispatcher: None) -> None:
17
- standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestParallelization)), countFolds, listDimensionsTestParallelization, None, 'maximum', None)
21
+ standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestParallelization)), countFolds, listDimensionsTestParallelization, None, 'maximum', None)
18
22
 
19
23
  def test_algorithmSourceSequential(listDimensionsTestCountFolds: tuple[int, ...], useAlgorithmSourceDispatcher: None) -> None:
20
- standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestCountFolds)), countFolds, listDimensionsTestCountFolds)
24
+ standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestCountFolds)), countFolds, listDimensionsTestCountFolds)
21
25
 
22
26
  def test_aOFn_calculate_value(oeisID: str) -> None:
23
- for n in settingsOEIS[oeisID]['valuesTestValidation']:
24
- standardizedEqualToCallableReturn(settingsOEIS[oeisID]['valuesKnown'][n], oeisIDfor_n, oeisID, n)
27
+ for n in settingsOEIS[oeisID]['valuesTestValidation']:
28
+ standardizedEqualToCallableReturn(settingsOEIS[oeisID]['valuesKnown'][n], oeisIDfor_n, oeisID, n)
25
29
 
26
30
  def test_syntheticParallel(syntheticDispatcherFixture: None, listDimensionsTestParallelization: list[int]):
27
- standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestParallelization)), countFolds, listDimensionsTestParallelization, None, 'maximum')
31
+ standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestParallelization)), countFolds, listDimensionsTestParallelization, None, 'maximum')
28
32
 
29
33
  def test_syntheticSequential(syntheticDispatcherFixture: None, listDimensionsTestCountFolds: list[int]) -> None:
30
- standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestCountFolds)), countFolds, listDimensionsTestCountFolds)
31
-
32
- # @pytest.mark.parametrize('pathFilenameTmpTesting', ['.py'], indirect=True)
33
- # def test_writeJobNumba(listDimensionsTestCountFolds: list[int], pathFilenameTmpTesting: Path) -> None:
34
- # from mapFolding.syntheticModules import numbaCount
35
- # algorithmSourceHARDCODED: ModuleType = numbaCount
36
- # algorithmSource = algorithmSourceHARDCODED
37
- # callableTargetHARDCODED = 'countSequential'
38
- # callableTarget = callableTargetHARDCODED
39
- # pathFilenameModule = writeJobNumba(listDimensionsTestCountFolds, algorithmSource, callableTarget, pathFilenameWriteJob=pathFilenameTmpTesting.absolute())
40
-
41
- # Don_Lapre_Road_to_Self_Improvement = importlib.util.spec_from_file_location("__main__", pathFilenameModule)
42
- # if Don_Lapre_Road_to_Self_Improvement is None:
43
- # raise ImportError(f"Failed to create module specification from {pathFilenameModule}")
44
- # if Don_Lapre_Road_to_Self_Improvement.loader is None:
45
- # raise ImportError(f"Failed to get loader for module {pathFilenameModule}")
46
- # module = importlib.util.module_from_spec(Don_Lapre_Road_to_Self_Improvement)
47
-
48
- # module.__name__ = "__main__"
49
- # Don_Lapre_Road_to_Self_Improvement.loader.exec_module(module)
50
-
51
- # pathFilenameFoldsTotal = getPathFilenameFoldsTotal(listDimensionsTestCountFolds)
52
- # registrarRecordsTmpObject(pathFilenameFoldsTotal)
53
- # standardizedEqualToCallableReturn(str(getFoldsTotalKnown(tuple(listDimensionsTestCountFolds))), pathFilenameFoldsTotal.read_text().strip)
34
+ standardizedEqualToCallableReturn(getFoldsTotalKnown(tuple(listDimensionsTestCountFolds)), countFolds, listDimensionsTestCountFolds)
35
+
36
+ @pytest.mark.parametrize('pathFilenameTmpTesting', ['.py'], indirect=True)
37
+ def test_writeJobNumba(oneTestCuzTestsOverwritingTests: list[int], pathFilenameTmpTesting: Path) -> None:
38
+ mapShape = validateListDimensions(oneTestCuzTestsOverwritingTests)
39
+ state = makeInitializedComputationState(mapShape)
40
+
41
+ pathFilenameModule = pathFilenameTmpTesting.absolute()
42
+ pathFilenameFoldsTotal = pathFilenameModule.with_suffix('.foldsTotalTesting')
43
+ registrarRecordsTmpObject(pathFilenameFoldsTotal)
44
+
45
+ jobTest = Z0Z_RecipeJob(state
46
+ , pathModule=PurePosixPath(pathFilenameModule.parent)
47
+ , moduleIdentifier=pathFilenameModule.stem
48
+ , pathFilenameFoldsTotal=PurePosixPath(pathFilenameFoldsTotal))
49
+
50
+ makeJobNumba(jobTest)
51
+
52
+ Don_Lapre_Road_to_Self_Improvement = importlib.util.spec_from_file_location("__main__", pathFilenameModule)
53
+ if Don_Lapre_Road_to_Self_Improvement is None:
54
+ raise ImportError(f"Failed to create module specification from {pathFilenameModule}")
55
+ if Don_Lapre_Road_to_Self_Improvement.loader is None:
56
+ raise ImportError(f"Failed to get loader for module {pathFilenameModule}")
57
+ module = importlib.util.module_from_spec(Don_Lapre_Road_to_Self_Improvement)
58
+
59
+ module.__name__ = "__main__"
60
+ Don_Lapre_Road_to_Self_Improvement.loader.exec_module(module)
61
+
62
+ standardizedEqualToCallableReturn(str(getFoldsTotalKnown(mapShape)), pathFilenameFoldsTotal.read_text().strip)
tests/test_filesystem.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from contextlib import redirect_stdout
2
2
  from mapFolding.filesystem import getFilenameFoldsTotal, getPathFilenameFoldsTotal, saveFoldsTotal
3
3
  from mapFolding.beDRY import validateListDimensions
4
- from mapFolding.theSSOT import getPathJobRootDEFAULT
4
+ from mapFolding.filesystem import getPathRootJobDEFAULT
5
5
  from pathlib import Path
6
6
  import io
7
7
  import pytest
@@ -33,14 +33,14 @@ def test_getPathFilenameFoldsTotal_defaultPath(mapShapeTestFunctionality: tuple[
33
33
  pathFilenameFoldsTotal = getPathFilenameFoldsTotal(mapShapeTestFunctionality)
34
34
  assert pathFilenameFoldsTotal.is_absolute(), "Path should be absolute"
35
35
  assert pathFilenameFoldsTotal.name == getFilenameFoldsTotal(mapShapeTestFunctionality), "Filename should match getFilenameFoldsTotal output"
36
- assert pathFilenameFoldsTotal.parent == getPathJobRootDEFAULT(), "Parent directory should match default job root"
36
+ assert pathFilenameFoldsTotal.parent == getPathRootJobDEFAULT(), "Parent directory should match default job root"
37
37
 
38
38
  def test_getPathFilenameFoldsTotal_relativeFilename(mapShapeTestFunctionality: tuple[int, ...]) -> None:
39
39
  """Test getPathFilenameFoldsTotal with relative filename."""
40
40
  relativeFilename = Path("custom/path/test.foldsTotal")
41
41
  pathFilenameFoldsTotal = getPathFilenameFoldsTotal(mapShapeTestFunctionality, relativeFilename)
42
42
  assert pathFilenameFoldsTotal.is_absolute(), "Path should be absolute"
43
- assert pathFilenameFoldsTotal == getPathJobRootDEFAULT() / relativeFilename, "Relative path should be appended to default job root"
43
+ assert pathFilenameFoldsTotal == getPathRootJobDEFAULT() / relativeFilename, "Relative path should be appended to default job root"
44
44
 
45
45
  def test_getPathFilenameFoldsTotal_createsDirs(pathTmpTesting: Path, mapShapeTestFunctionality: tuple[int, ...]) -> None:
46
46
  """Test that getPathFilenameFoldsTotal creates necessary directories."""
@@ -1,413 +0,0 @@
1
- """Synthesize one file to compute `foldsTotal` of `mapShape`."""
2
- from collections.abc import Sequence
3
- from typing import Any, cast, TYPE_CHECKING
4
- from mapFolding.filesystem import getFilenameFoldsTotal, getPathFilenameFoldsTotal
5
- from mapFolding.someAssemblyRequired import ( ifThis, LedgerOfImports, Make, NodeReplacer, Then, )
6
- from mapFolding.theSSOT import ( ComputationState, raiseIfNoneGitHubIssueNumber3, getPathJobRootDEFAULT, )
7
- from os import PathLike
8
- from pathlib import Path
9
- from types import ModuleType
10
- from Z0Z_tools import autoDecodingRLE
11
- import ast
12
- import python_minifier
13
- import autoflake
14
- import copy
15
- import inspect
16
- import numpy
17
- if TYPE_CHECKING:
18
- from mapFolding.someAssemblyRequired.transformDataStructures import makeStateJobOUTDATED
19
- from mapFolding.someAssemblyRequired.ingredientsNumba import thisIsNumbaDotJit, decorateCallableWithNumba
20
- from mapFolding.someAssemblyRequired.ingredientsNumba import ParametersNumba, parametersNumbaDEFAULT
21
-
22
- def Z0Z_gamma(FunctionDefTarget: ast.FunctionDef, astAssignee: ast.Name, statement: ast.Assign | ast.stmt, identifier: str, arrayTarget: numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.integer[Any]]], allImports: LedgerOfImports) -> tuple[ast.FunctionDef, LedgerOfImports]:
23
- arrayType = type(arrayTarget)
24
- moduleConstructor: str = arrayType.__module__
25
- constructorName: str = arrayType.__name__.replace('ndarray', 'array') # NOTE hack
26
- dataAsStrRLE: str = autoDecodingRLE(arrayTarget, addSpaces=True)
27
- dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
28
- dtypeName: str = identifier
29
- dtypeAsName: str = f"{moduleConstructor}_{dtypeName}"
30
- list_astKeywords: list[ast.keyword] = [ast.keyword(arg='dtype', value=ast.Name(id=dtypeAsName, ctx=ast.Load()))]
31
- allImports.addImportFromStr(moduleConstructor, dtypeName, dtypeAsName)
32
- astCall: ast.Call = Make.astCall(Make.astName(constructorName), [dataAs_astExpr], list_astKeywords)
33
- assignment = ast.Assign(targets=[astAssignee], value=astCall)
34
- FunctionDefTarget.body.insert(0, assignment)
35
- FunctionDefTarget.body.remove(statement)
36
- allImports.addImportFromStr(moduleConstructor, constructorName)
37
- return FunctionDefTarget, allImports
38
-
39
- def insertArrayIn_body(FunctionDefTarget: ast.FunctionDef, identifier: str, arrayTarget: numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.integer[Any]]], allImports: LedgerOfImports, unrollSlices: int | None = None) -> tuple[ast.FunctionDef, LedgerOfImports]:
40
- def insertAssign(FunctionDefTarget: ast.FunctionDef, assignee: str, arraySlice: numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.integer[Any]]], allImports: LedgerOfImports) -> tuple[ast.FunctionDef, LedgerOfImports]:
41
- statement = ast.Assign(targets=[ast.Name(id='beans', ctx=ast.Load())], value=ast.Constant(value='and cornbread'))
42
- FunctionDefTarget.body.insert(0, statement)
43
- astAssignee = ast.Name(id=assignee, ctx=ast.Store())
44
- return Z0Z_gamma(FunctionDefTarget, astAssignee, statement, identifier, arraySlice, allImports)
45
-
46
- if not unrollSlices:
47
- FunctionDefTarget, allImports = insertAssign(FunctionDefTarget, identifier, arrayTarget, allImports)
48
- else:
49
- for index, arraySlice in enumerate(arrayTarget):
50
- FunctionDefTarget, allImports = insertAssign(FunctionDefTarget, f"{identifier}_{index}", arraySlice, allImports)
51
-
52
- return FunctionDefTarget, allImports
53
-
54
- def findAndReplaceTrackArrayIn_body(FunctionDefTarget: ast.FunctionDef, identifier: str, arrayTarget: numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.integer[Any]]], allImports: LedgerOfImports) -> tuple[ast.FunctionDef, LedgerOfImports]:
55
- for statement in FunctionDefTarget.body.copy():
56
- if True:
57
- indexAsStr: str = ast.unparse(statement.value.slice) # type: ignore
58
- arraySlice: numpy.ndarray[Any, numpy.dtype[numpy.integer[Any]]] = arrayTarget[eval(indexAsStr)]
59
- astAssignee: ast.Name = cast(ast.Name, statement.targets[0]) # type: ignore
60
- FunctionDefTarget, allImports = Z0Z_gamma(FunctionDefTarget, astAssignee, statement, identifier, arraySlice, allImports)
61
- return FunctionDefTarget, allImports
62
-
63
- def findAndReplaceArraySubscriptIn_body(FunctionDefTarget: ast.FunctionDef, identifier: str, arrayTarget: numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.integer[Any]]], allImports: LedgerOfImports) -> tuple[ast.FunctionDef, LedgerOfImports]:
64
- # parameter: I define moduleConstructor
65
- moduleConstructor = 'numba'
66
-
67
- for statement in FunctionDefTarget.body.copy():
68
- if True:
69
- indexAsStr: str = ast.unparse(statement.value.slice) # type: ignore
70
- arraySlice: numpy.ndarray[Any, numpy.dtype[numpy.integer[Any]]] = arrayTarget[eval(indexAsStr)]
71
- astAssignee: ast.Name = cast(ast.Name, statement.targets[0]) # type: ignore
72
- arraySliceItem: int = arraySlice.item()
73
- constructorName: str = astAssignee.id
74
- dataAs_astExpr = ast.Constant(value=arraySliceItem)
75
- list_astKeywords: list[ast.keyword] = []
76
- astCall: ast.Call = Make.astCall(Make.astName(constructorName), [dataAs_astExpr], list_astKeywords)
77
- assignment = ast.Assign(targets=[astAssignee], value=astCall)
78
- FunctionDefTarget.body.insert(0, assignment)
79
- FunctionDefTarget.body.remove(statement)
80
- allImports.addImportFromStr(moduleConstructor, constructorName)
81
- return FunctionDefTarget, allImports
82
-
83
- def removeAssignmentFrom_body(FunctionDefTarget: ast.FunctionDef, identifier: str) -> ast.FunctionDef:
84
- FunctionDefSherpa: ast.AST | Sequence[ast.AST] | None = NodeReplacer(ifThis.isAnyAssignmentTo(identifier), Then.removeThis).visit(FunctionDefTarget)
85
- if not FunctionDefSherpa:
86
- raise raiseIfNoneGitHubIssueNumber3("Dude, where's my function?")
87
- else:
88
- FunctionDefTarget = cast(ast.FunctionDef, FunctionDefSherpa)
89
- ast.fix_missing_locations(FunctionDefTarget)
90
- return FunctionDefTarget
91
-
92
- def findAndReplaceAnnAssignIn_body(FunctionDefTarget: ast.FunctionDef, allImports: LedgerOfImports) -> tuple[ast.FunctionDef, LedgerOfImports]:
93
- """Unlike most of the other functions, this is generic: it tries to turn an annotation into a construction call."""
94
- moduleConstructor: str = 'numba'
95
- for stmt in FunctionDefTarget.body.copy():
96
- if isinstance(stmt, ast.AnnAssign):
97
- if isinstance(stmt.target, ast.Name) and isinstance(stmt.value, ast.Constant):
98
- astAssignee: ast.Name = stmt.target
99
- argData_dtypeName: str = astAssignee.id
100
- allImports.addImportFromStr(moduleConstructor, argData_dtypeName)
101
- astCall = ast.Call(func=ast.Name(id=argData_dtypeName, ctx=ast.Load()), args=[stmt.value], keywords=[])
102
- assignment = ast.Assign(targets=[astAssignee], value=astCall)
103
- FunctionDefTarget.body.insert(0, assignment)
104
- FunctionDefTarget.body.remove(stmt)
105
- return FunctionDefTarget, allImports
106
-
107
- def findThingyReplaceWithConstantIn_body(FunctionDefTarget: ast.FunctionDef, object: str, value: int) -> ast.FunctionDef:
108
- """
109
- Replaces nodes in astFunction matching the AST of the string `object`
110
- with a constant node holding the provided value.
111
- """
112
- targetExpression: ast.expr = ast.parse(object, mode='eval').body
113
- targetDump: str = ast.dump(targetExpression, annotate_fields=False)
114
-
115
- def findNode(node: ast.AST) -> bool:
116
- return ast.dump(node, annotate_fields=False) == targetDump
117
-
118
- def replaceWithConstant(node: ast.AST) -> ast.AST:
119
- return ast.copy_location(ast.Constant(value=value), node)
120
-
121
- transformer = NodeReplacer(findNode, replaceWithConstant)
122
- newFunction: ast.FunctionDef = cast(ast.FunctionDef, transformer.visit(FunctionDefTarget))
123
- ast.fix_missing_locations(newFunction)
124
- return newFunction
125
-
126
- def findAstNameReplaceWithConstantIn_body(FunctionDefTarget: ast.FunctionDef, name: str, value: int) -> ast.FunctionDef:
127
- def replaceWithConstant(node: ast.AST) -> ast.AST:
128
- return ast.copy_location(ast.Constant(value=value), node)
129
-
130
- return cast(ast.FunctionDef, NodeReplacer(ifThis.isName_Identifier(name), replaceWithConstant).visit(FunctionDefTarget))
131
-
132
- def insertReturnStatementIn_body(FunctionDefTarget: ast.FunctionDef, arrayTarget: numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.integer[Any]]], allImports: LedgerOfImports) -> tuple[ast.FunctionDef, LedgerOfImports]:
133
- """Add multiplication and return statement to function, properly constructing AST nodes."""
134
- # Create AST for multiplication operation
135
- multiplicand = 'Z0Z_identifierCountFolds'
136
- multiplyOperation = ast.BinOp(
137
- left=ast.Name(id=multiplicand, ctx=ast.Load()),
138
- op=ast.Mult(), right=ast.Constant(value=int(arrayTarget[-1])))
139
-
140
- returnStatement = ast.Return(value=multiplyOperation)
141
-
142
- datatype: str = 'Z0Z_identifierCountFolds'
143
- FunctionDefTarget.returns = ast.Name(id=datatype, ctx=ast.Load())
144
- datatypeModuleScalar: str = 'numba'
145
- allImports.addImportFromStr(datatypeModuleScalar, datatype)
146
-
147
- FunctionDefTarget.body.append(returnStatement)
148
-
149
- return FunctionDefTarget, allImports
150
-
151
- def findAndReplaceWhileLoopIn_body(FunctionDefTarget: ast.FunctionDef, iteratorName: str, iterationsTotal: int) -> ast.FunctionDef:
152
- """
153
- Unroll all nested while loops matching the condition that their test uses `iteratorName`.
154
- """
155
- # Helper transformer to replace iterator occurrences with a constant.
156
- class ReplaceIterator(ast.NodeTransformer):
157
- def __init__(self, iteratorName: str, constantValue: int) -> None:
158
- super().__init__()
159
- self.iteratorName: str = iteratorName
160
- self.constantValue: int = constantValue
161
-
162
- def visit_Name(self, node: ast.Name) -> ast.AST:
163
- if node.id == self.iteratorName:
164
- return ast.copy_location(ast.Constant(value=self.constantValue), node)
165
- return self.generic_visit(node)
166
-
167
- # NodeTransformer that finds while loops (even if deeply nested) and unrolls them.
168
- class WhileLoopUnroller(ast.NodeTransformer):
169
- def __init__(self, iteratorName: str, iterationsTotal: int) -> None:
170
- super().__init__()
171
- self.iteratorName: str = iteratorName
172
- self.iterationsTotal: int = iterationsTotal
173
-
174
- def visit_While(self, node: ast.While) -> list[ast.stmt]:
175
- # Check if the while loop's test uses the iterator.
176
- if isinstance(node.test, ast.Compare) and ifThis.isName_Identifier(self.iteratorName)(node.test.left):
177
- # Recurse the while loop body and remove AugAssign that increments the iterator.
178
- cleanBodyStatements: list[ast.stmt] = []
179
- for loopStatement in node.body:
180
- # Recursively visit nested statements.
181
- visitedStatement = self.visit(loopStatement)
182
- # Remove direct AugAssign: iterator += 1.
183
- if (isinstance(loopStatement, ast.AugAssign) and
184
- isinstance(loopStatement.target, ast.Name) and
185
- loopStatement.target.id == self.iteratorName and
186
- isinstance(loopStatement.op, ast.Add) and
187
- isinstance(loopStatement.value, ast.Constant) and
188
- loopStatement.value.value == 1):
189
- continue
190
- cleanBodyStatements.append(visitedStatement)
191
-
192
- newStatements: list[ast.stmt] = []
193
- # Unroll using the filtered body.
194
- for iterationIndex in range(self.iterationsTotal):
195
- for loopStatement in cleanBodyStatements:
196
- copiedStatement: ast.stmt = copy.deepcopy(loopStatement)
197
- replacer = ReplaceIterator(self.iteratorName, iterationIndex)
198
- newStatement = replacer.visit(copiedStatement)
199
- ast.fix_missing_locations(newStatement)
200
- newStatements.append(newStatement)
201
- # Optionally, process the orelse block.
202
- if node.orelse:
203
- for elseStmt in node.orelse:
204
- visitedElse = self.visit(elseStmt)
205
- if isinstance(visitedElse, list):
206
- newStatements.extend(cast(list[ast.stmt], visitedElse))
207
- else:
208
- newStatements.append(visitedElse)
209
- return newStatements
210
- return [cast(ast.stmt, self.generic_visit(node))]
211
-
212
- newFunctionDef = WhileLoopUnroller(iteratorName, iterationsTotal).visit(FunctionDefTarget)
213
- ast.fix_missing_locations(newFunctionDef)
214
- return newFunctionDef
215
-
216
- def makeLauncherTqdmJobNumba(callableTarget: str, pathFilenameFoldsTotal: Path, totalEstimated: int, leavesTotal:int) -> ast.Module:
217
- linesLaunch: str = f"""
218
- if __name__ == '__main__':
219
- with ProgressBar(total={totalEstimated}, update_interval=2) as statusUpdate:
220
- {callableTarget}(statusUpdate)
221
- foldsTotal = statusUpdate.n * {leavesTotal}
222
- print("", foldsTotal)
223
- writeStream = open('{pathFilenameFoldsTotal.as_posix()}', 'w')
224
- writeStream.write(str(foldsTotal))
225
- writeStream.close()
226
- """
227
- return ast.parse(linesLaunch)
228
-
229
- def makeLauncherBasicJobNumba(callableTarget: str, pathFilenameFoldsTotal: Path) -> ast.Module:
230
- linesLaunch: str = f"""
231
- if __name__ == '__main__':
232
- import time
233
- timeStart = time.perf_counter()
234
- foldsTotal = {callableTarget}()
235
- print(foldsTotal, time.perf_counter() - timeStart)
236
- writeStream = open('{pathFilenameFoldsTotal.as_posix()}', 'w')
237
- writeStream.write(str(foldsTotal))
238
- writeStream.close()
239
- """
240
- return ast.parse(linesLaunch)
241
-
242
- def doUnrollCountGaps(FunctionDefTarget: ast.FunctionDef, stateJob: ComputationState, allImports: LedgerOfImports) -> tuple[ast.FunctionDef, LedgerOfImports]:
243
- """The initial results were very bad."""
244
- FunctionDefTarget = findAndReplaceWhileLoopIn_body(FunctionDefTarget, 'indexDimension', stateJob.dimensionsTotal)
245
- FunctionDefTarget = removeAssignmentFrom_body(FunctionDefTarget, 'indexDimension')
246
- FunctionDefTarget = removeAssignmentFrom_body(FunctionDefTarget, 'connectionGraph')
247
- FunctionDefTarget, allImports = insertArrayIn_body(FunctionDefTarget, 'connectionGraph', stateJob.connectionGraph, allImports, stateJob.dimensionsTotal)
248
- for index in range(stateJob.dimensionsTotal):
249
- class ReplaceConnectionGraph(ast.NodeTransformer):
250
- def visit_Subscript(self, node: ast.Subscript) -> ast.AST:
251
- node = cast(ast.Subscript, self.generic_visit(node))
252
- if (isinstance(node.value, ast.Name) and node.value.id == "connectionGraph" and
253
- isinstance(node.slice, ast.Tuple) and len(node.slice.elts) >= 1):
254
- firstElement: ast.expr = node.slice.elts[0]
255
- if isinstance(firstElement, ast.Constant) and firstElement.value == index:
256
- newName = ast.Name(id=f"connectionGraph_{index}", ctx=ast.Load())
257
- remainingIndices: list[ast.expr] = node.slice.elts[1:]
258
- if len(remainingIndices) == 1:
259
- newSlice: ast.expr = remainingIndices[0]
260
- else:
261
- newSlice = ast.Tuple(elts=remainingIndices, ctx=ast.Load())
262
- return ast.copy_location(ast.Subscript(value=newName, slice=newSlice, ctx=node.ctx), node)
263
- return node
264
- transformer = ReplaceConnectionGraph()
265
- FunctionDefTarget = transformer.visit(FunctionDefTarget)
266
- return FunctionDefTarget, allImports
267
-
268
- def writeJobNumba(mapShape: Sequence[int], algorithmSource: ModuleType, callableTarget: str | None = None, parametersNumba: ParametersNumba | None = None, pathFilenameWriteJob: str | PathLike[str] | None = None, unrollCountGaps: bool | None = False, Z0Z_totalEstimated: int = 0, **keywordArguments: Any | None) -> Path:
269
- """ Parameters: **keywordArguments: most especially for `computationDivisions` if you want to make a parallel job. Also `CPUlimit`.
270
- Notes:
271
- Hypothetically, everything can now be configured with parameters and functions. And changing how the job is written is relatively easy.
272
-
273
- Overview
274
- - the code starts life in theDao.py, which has many optimizations; `makeNumbaOptimizedFlow` increase optimization especially by using numba; `writeJobNumba` increases optimization especially by limiting its capabilities to just one set of parameters
275
- - the synthesized module must run well as a standalone interpreted-Python script
276
- - the next major optimization step will (probably) be to use the module synthesized by `writeJobNumba` to compile a standalone executable
277
- - Nevertheless, at each major optimization step, the code is constantly being improved and optimized, so everything must be well organized and able to handle upstream and downstream changes
278
-
279
- Minutia
280
- - perf_counter is for testing. When I run a real job, I delete those lines
281
- - avoid `with` statement
282
-
283
- Necessary
284
- - Move the function's parameters to the function body,
285
- - initialize identifiers with their state types and values,
286
-
287
- Optimizations
288
- - replace static-valued identifiers with their values
289
- - narrowly focused imports
290
- """
291
-
292
- # NOTE get the raw ingredients: data and the algorithm
293
- stateJob = makeStateJobOUTDATED(mapShape, writeJob=False, **keywordArguments)
294
- pythonSource: str = inspect.getsource(algorithmSource)
295
- astModule: ast.Module = ast.parse(pythonSource)
296
- setFunctionDef: set[ast.FunctionDef] = {statement for statement in astModule.body if isinstance(statement, ast.FunctionDef)}
297
-
298
- if not callableTarget:
299
- if len(setFunctionDef) == 1:
300
- FunctionDefTarget = setFunctionDef.pop()
301
- callableTarget = FunctionDefTarget.name
302
- else:
303
- raise ValueError(f"I did not receive a `callableTarget` and {algorithmSource.__name__=} has more than one callable: {setFunctionDef}. Please select one.")
304
- else:
305
- listFunctionDefTarget: list[ast.FunctionDef] = [statement for statement in setFunctionDef if statement.name == callableTarget]
306
- FunctionDefTarget = listFunctionDefTarget[0] if listFunctionDefTarget else None # type: ignore
307
- if not FunctionDefTarget: raise ValueError(f"I received `{callableTarget=}` and {algorithmSource.__name__=}, but I could not find that function in that source.")
308
-
309
- # NOTE `allImports` is a complementary container to `FunctionDefTarget`; the `FunctionDefTarget` cannot track its own imports very well.
310
- allImports = LedgerOfImports(astModule)
311
-
312
- # NOTE remove the parameters from the function signature
313
- for pirateScowl in FunctionDefTarget.args.args.copy():
314
- match pirateScowl.arg:
315
- case 'connectionGraph':
316
- FunctionDefTarget, allImports = insertArrayIn_body(FunctionDefTarget, pirateScowl.arg, stateJob.connectionGraph, allImports)
317
- case 'gapsWhere':
318
- FunctionDefTarget, allImports = insertArrayIn_body(FunctionDefTarget, pirateScowl.arg, stateJob.gapsWhere, allImports)
319
- case 'foldGroups':
320
- FunctionDefTarget = removeAssignmentFrom_body(FunctionDefTarget, pirateScowl.arg)
321
- case _:
322
- pass
323
- FunctionDefTarget.args.args.remove(pirateScowl)
324
-
325
- identifierCounter = 'Z0Z_identifierCountFolds'
326
- astExprIncrementCounter = ast.Expr(value = Make.astCall(Make.nameDOTname(identifierCounter, 'update'), listArguments=[ast.Constant(value=1)], list_astKeywords=[]))
327
- FunctionDefTarget= cast(ast.FunctionDef, NodeReplacer(ifThis.isAugAssignTo(identifierCounter), Then.replaceWith(astExprIncrementCounter)).visit(FunctionDefTarget))
328
- ast.fix_missing_locations(FunctionDefTarget)
329
-
330
- for assignmentTarget in ['taskIndex', 'dimensionsTotal', identifierCounter]:
331
- FunctionDefTarget = removeAssignmentFrom_body(FunctionDefTarget, assignmentTarget)
332
- # NOTE replace identifiers with static values with their values
333
- FunctionDefTarget = findAstNameReplaceWithConstantIn_body(FunctionDefTarget, 'dimensionsTotal', int(stateJob.dimensionsTotal))
334
- FunctionDefTarget = findThingyReplaceWithConstantIn_body(FunctionDefTarget, 'foldGroups[-1]', int(stateJob.foldGroups[-1]))
335
-
336
- # NOTE an attempt at optimization
337
- if unrollCountGaps:
338
- FunctionDefTarget, allImports = doUnrollCountGaps(FunctionDefTarget, stateJob, allImports)
339
-
340
- # NOTE starting the count and printing the total
341
- pathFilenameFoldsTotal: Path = getPathFilenameFoldsTotal(stateJob.mapShape)
342
-
343
- astLauncher: ast.Module = makeLauncherBasicJobNumba(FunctionDefTarget.name, pathFilenameFoldsTotal)
344
-
345
- # TODO create function for assigning value to `totalEstimated`
346
- totalEstimated: int = Z0Z_totalEstimated
347
- astLauncher = makeLauncherTqdmJobNumba(FunctionDefTarget.name, pathFilenameFoldsTotal, totalEstimated, stateJob.foldGroups[-1])
348
-
349
- allImports.addImportFromStr('numba_progress', 'ProgressBar')
350
- allImports.addImportFromStr('numba_progress', 'ProgressBarType')
351
-
352
- # add ProgressBarType parameter to function args
353
- counterArg = ast.arg(arg=identifierCounter, annotation=ast.Name(id='ProgressBarType', ctx=ast.Load()))
354
- FunctionDefTarget.args.args.append(counterArg)
355
-
356
- if parametersNumba is None:
357
- parametersNumba = parametersNumbaDEFAULT
358
- parametersNumba['nogil'] = True
359
-
360
- FunctionDefTarget, allImports = insertReturnStatementIn_body(FunctionDefTarget, stateJob.foldGroups, allImports)
361
-
362
- FunctionDefTarget, allImports = findAndReplaceAnnAssignIn_body(FunctionDefTarget, allImports)
363
- # NOTE add the perfect decorator
364
- if thisIsNumbaDotJit(FunctionDefTarget.decorator_list[0]):
365
- astCall: ast.Call = cast(ast.Call, FunctionDefTarget.decorator_list[0])
366
- astCall.func = ast.Name(id='jit', ctx=ast.Load())
367
- FunctionDefTarget.decorator_list[0] = astCall
368
-
369
- # NOTE add imports, make str, remove unused imports
370
- astImports: list[ast.ImportFrom | ast.Import] = allImports.makeListAst()
371
- astModule = ast.Module(body=cast(list[ast.stmt], astImports + [FunctionDefTarget] + [astLauncher]), type_ignores=[])
372
- ast.fix_missing_locations(astModule)
373
- pythonSource = ast.unparse(astModule)
374
- pythonSource = autoflake.fix_code(pythonSource, ['mapFolding', 'numba', 'numpy'])
375
- pythonSource = python_minifier.minify(pythonSource, remove_annotations = False, remove_pass = False, remove_literal_statements = False, combine_imports = True, hoist_literals = False, rename_locals = False, rename_globals = False, remove_object_base = False, convert_posargs_to_args = False, preserve_shebang = True, remove_asserts = False, remove_debug = False, remove_explicit_return_none = False, remove_builtin_exception_brackets = False, constant_folding = False)
376
-
377
- # NOTE put on disk
378
- if pathFilenameWriteJob is None:
379
- filename: str = getFilenameFoldsTotal(stateJob.mapShape)
380
- pathRoot: Path = getPathJobRootDEFAULT()
381
- pathFilenameWriteJob = Path(pathRoot, Path(filename).stem, Path(filename).with_suffix('.py'))
382
- else:
383
- pathFilenameWriteJob = Path(pathFilenameWriteJob)
384
- pathFilenameWriteJob.parent.mkdir(parents=True, exist_ok=True)
385
-
386
- pathFilenameWriteJob.write_text(pythonSource)
387
-
388
- return pathFilenameWriteJob
389
-
390
- if __name__ == '__main__':
391
- mapShape: list[int] = [5,5]
392
- dictionaryEstimates: dict[tuple[int, ...], int] = {
393
- (2,2,2,2,2,2,2,2): 362794844160000,
394
- (2,21): 1493028892051200,
395
- (3,15): 9842024675968800,
396
- (3,3,3,3,3): 85109616000000,
397
- (3,3,3,3): 85109616000,
398
- (8,8): 129950723279272000,
399
- }
400
-
401
- totalEstimated: int = dictionaryEstimates.get(tuple(mapShape), 10**8)
402
- from mapFolding.syntheticModules import numbaCount_doTheNeedful
403
- algorithmSource: ModuleType = numbaCount_doTheNeedful
404
-
405
- callableTarget = 'countSequential'
406
-
407
- parametersNumba: ParametersNumba = parametersNumbaDEFAULT
408
- parametersNumba['nogil'] = True
409
- parametersNumba['boundscheck'] = False
410
-
411
- pathFilenameWriteJob = None
412
-
413
- writeJobNumba(mapShape, algorithmSource, callableTarget, parametersNumba, pathFilenameWriteJob, Z0Z_totalEstimated=totalEstimated)
@@ -1,43 +0,0 @@
1
- mapFolding/__init__.py,sha256=XRcskvsF7PTdsNOWWeR1FhQLA3fyBUScCqdfxYhAy8c,1998
2
- mapFolding/basecamp.py,sha256=uPwbb_fi8zqqBbVjb355qanSNUqqJ9aefcf_nrvA7qI,4510
3
- mapFolding/beDRY.py,sha256=UhH52BryHQNRjphf_PirtMkV45rhdemdC9PmnpACq7I,9397
4
- mapFolding/filesystem.py,sha256=-pYpWugd0p3TrAz7xf9YIJW-pn1X-iRCGtJgEAF9Rns,5923
5
- mapFolding/noHomeYet.py,sha256=UKZeWlyn0SKlF9dhYoud7E6gWXpiSEekZOOoJp88WeI,1362
6
- mapFolding/oeis.py,sha256=TbY8KtAGbQlT6eEsa_7HVMF7bMLN-aBFKclyTMHfqHk,12615
7
- mapFolding/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- mapFolding/theDao.py,sha256=Blzm5j24x1BE2nvgXjdzHEeuc2na6kAH9b_eP6PcwlI,9836
9
- mapFolding/theSSOT.py,sha256=DH0so-BVQm8RrBrqhehRC9spmb5Gg1vFegbMSeeoMcM,12236
10
- mapFolding/reference/__init__.py,sha256=UIEU8BJR_YDzjFQcLel3XtHzOCJiOUGlGiWzOzbvhik,2206
11
- mapFolding/reference/flattened.py,sha256=QK1xG9SllqCoi68e86Hyl9d9ATUAAFNpTQI-3zmcp5I,16072
12
- mapFolding/reference/hunterNumba.py,sha256=espFiX92EPZ1Ub1YQVoBnNYvh2kFg1HR6Qa4djx8Ixg,7253
13
- mapFolding/reference/irvineJavaPort.py,sha256=UEfIX4QbPLl5jnyfYIyX5YRR3_rYvPUikK8jLehsFko,4076
14
- mapFolding/reference/jaxCount.py,sha256=TuDNKOnyhQfuixKmIxO9Algv7dvy7KMGhgsV3h96FGE,14853
15
- mapFolding/reference/lunnanNumpy.py,sha256=mMgrgbrBpe4nmo72ThEI-MGH0OwEHmfMPczSXHp2qKo,4357
16
- mapFolding/reference/lunnanWhile.py,sha256=ZL8GAQtPs5nJZSgoDl5USrLSS_zs03y98y1Z9E4jOmQ,3799
17
- mapFolding/reference/rotatedEntryPoint.py,sha256=5ughpKUT2JQhoAKgoDUdYNjgWQYPGV8v-7dWEAdDmfE,10274
18
- mapFolding/reference/total_countPlus1vsPlusN.py,sha256=yJZAVLVdoXqHag2_N6_6CT-Q6HXBgRro-eny93-Rlpw,9307
19
- mapFolding/reference/jobsCompleted/__init__.py,sha256=TU93ZGUW1xEkT6d9mQFn_rp5DvRy0ZslEB2Q6MF5ZDc,2596
20
- mapFolding/reference/jobsCompleted/[2x19]/p2x19.py,sha256=_tvYtfzMWVo2VtUbIAieoscb4N8FFflgTdW4-ljBUuA,19626
21
- mapFolding/reference/jobsCompleted/p2x19/p2x19.py,sha256=eZEw4Me4ocTt6VXoK2-Sbd5SowZtxRIbN9dZmc7OCVg,6395
22
- mapFolding/someAssemblyRequired/__init__.py,sha256=xA5a-nZjXIwcqEOig5PEZSxde4_m3JJ5Pb0CN4aiRjw,2488
23
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py,sha256=CDbesDJSQE-P8uznXIAttRw9f413UpUt-RowK38hqbY,2735
24
- mapFolding/someAssemblyRequired/ingredientsNumba.py,sha256=g6Z7t35NpoDskzm0OLwTQhHw5CYiYktVYxI2NhCQHww,8435
25
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py,sha256=scEozf2dy4pvrRMtQSycZf3RkNJtYLGKQVDhN6_H8_4,11812
26
- mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py,sha256=RBSrtr7US2P7mkY-EA-b2WIOxjs2b0WJaCln1ERxOcI,22314
27
- mapFolding/someAssemblyRequired/transformDataStructures.py,sha256=ssgnGpO4Z8tfdep-lzeodua8ZxA0qvjIwDGv6wbP_ew,8605
28
- mapFolding/someAssemblyRequired/transformationTools.py,sha256=_m4i6TylMBCkh-f-LPAtUIzHhZm4nhyuQOceK3yNwIo,41067
29
- mapFolding/syntheticModules/__init__.py,sha256=evVFqhCGa-WZKDiLcnQWjs-Bj34eRnfSLqz_d7dFYZY,83
30
- mapFolding/syntheticModules/numbaCount_doTheNeedful.py,sha256=52RuwJVH2fROvWU2dT8wYcQvLgRuvkNZPq01kujCC_U,15725
31
- mapfolding-0.8.3.dist-info/licenses/LICENSE,sha256=NxH5Y8BdC-gNU-WSMwim3uMbID2iNDXJz7fHtuTdXhk,19346
32
- tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- tests/conftest.py,sha256=hTpUTW7MtYGP5aeQnnoZMKgTEGCKdLJ8Fnmnv9d4NJw,11115
34
- tests/test_computations.py,sha256=RHHByyuC8w-qbaag4Iqo_QNYm_7A-9BslbstMOdbZbU,3329
35
- tests/test_filesystem.py,sha256=Kou0gj5T72oISao6umYfU6L_W5Hi7QS9_IxTv2hU0Pw,3147
36
- tests/test_oeis.py,sha256=uxvwmgbnylSDdsVJfuAT0LuYLbIVFwSgdLxHm-xUGBM,5043
37
- tests/test_other.py,sha256=AzsCXiX8x5WJ7i0SocWQY6lT30IJg1lKoybx03X2eqU,4281
38
- tests/test_tasks.py,sha256=hkZygihT8bCEO2zc-2VcxReQrZJBwgLNbYx0YP4lTDg,2853
39
- mapfolding-0.8.3.dist-info/METADATA,sha256=LPHFjXnPJA3N4TmHLA7EAEL20sRrjMatn-kxmL1_118,9286
40
- mapfolding-0.8.3.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
41
- mapfolding-0.8.3.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
42
- mapfolding-0.8.3.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
43
- mapfolding-0.8.3.dist-info/RECORD,,