mapFolding 0.8.4__py3-none-any.whl → 0.8.6__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.
- mapFolding/__init__.py +10 -6
- mapFolding/basecamp.py +3 -3
- mapFolding/beDRY.py +241 -68
- mapFolding/oeis.py +41 -26
- mapFolding/reference/hunterNumba.py +1 -1
- mapFolding/someAssemblyRequired/__init__.py +16 -15
- mapFolding/someAssemblyRequired/_theTypes.py +31 -13
- mapFolding/someAssemblyRequired/_tool_Make.py +13 -5
- mapFolding/someAssemblyRequired/_tool_Then.py +12 -5
- mapFolding/someAssemblyRequired/_toolboxAntecedents.py +131 -99
- mapFolding/someAssemblyRequired/_toolboxContainers.py +92 -15
- mapFolding/someAssemblyRequired/_toolboxPython.py +17 -31
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +2 -2
- mapFolding/someAssemblyRequired/newInliner.py +22 -0
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +65 -116
- mapFolding/someAssemblyRequired/toolboxNumba.py +364 -0
- mapFolding/someAssemblyRequired/transformationTools.py +262 -41
- mapFolding/syntheticModules/numbaCount_doTheNeedful.py +0 -1
- mapFolding/theSSOT.py +30 -33
- mapFolding/{filesystem.py → toolboxFilesystem.py} +90 -25
- {mapfolding-0.8.4.dist-info → mapfolding-0.8.6.dist-info}/METADATA +3 -2
- mapfolding-0.8.6.dist-info/RECORD +47 -0
- tests/conftest.py +30 -31
- tests/test_computations.py +8 -7
- tests/test_filesystem.py +2 -2
- tests/test_other.py +2 -2
- tests/test_tasks.py +3 -3
- mapFolding/noHomeYet.py +0 -32
- mapFolding/someAssemblyRequired/ingredientsNumba.py +0 -199
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +0 -156
- mapFolding/someAssemblyRequired/transformDataStructures.py +0 -235
- mapfolding-0.8.4.dist-info/RECORD +0 -49
- {mapfolding-0.8.4.dist-info → mapfolding-0.8.6.dist-info}/WHEEL +0 -0
- {mapfolding-0.8.4.dist-info → mapfolding-0.8.6.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.4.dist-info → mapfolding-0.8.6.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.8.4.dist-info → mapfolding-0.8.6.dist-info}/top_level.txt +0 -0
|
@@ -7,9 +7,10 @@ circular imports while providing reusable data structures.
|
|
|
7
7
|
"""
|
|
8
8
|
from collections import defaultdict
|
|
9
9
|
from collections.abc import Sequence
|
|
10
|
-
from mapFolding.someAssemblyRequired import ast_Identifier, be,
|
|
11
|
-
from mapFolding.theSSOT import callableDispatcherHARDCODED,
|
|
10
|
+
from mapFolding.someAssemblyRequired import ImaAnnotationType, ast_Identifier, be, Make, parseLogicalPath2astModule, str_nameDOTname
|
|
11
|
+
from mapFolding.theSSOT import callableDispatcherHARDCODED, The
|
|
12
12
|
from pathlib import Path, PurePosixPath
|
|
13
|
+
from typing import Literal
|
|
13
14
|
from Z0Z_tools import updateExtendPolishDictionaryLists
|
|
14
15
|
import ast
|
|
15
16
|
import dataclasses
|
|
@@ -36,11 +37,45 @@ class LedgerOfImports:
|
|
|
36
37
|
for alias in astImport____.names:
|
|
37
38
|
self.dictionaryImportFrom[astImport____.module].append((alias.name, alias.asname))
|
|
38
39
|
|
|
39
|
-
def addImport_asStr(self,
|
|
40
|
-
self.listImport.append(
|
|
41
|
-
|
|
42
|
-
def addImportFrom_asStr(self,
|
|
43
|
-
|
|
40
|
+
def addImport_asStr(self, moduleWithLogicalPath: str_nameDOTname) -> None:
|
|
41
|
+
self.listImport.append(moduleWithLogicalPath)
|
|
42
|
+
|
|
43
|
+
# def addImportFrom_asStr(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier, asname: ast_Identifier | None = None) -> None:
|
|
44
|
+
# self.dictionaryImportFrom[moduleWithLogicalPath].append((name, asname))
|
|
45
|
+
|
|
46
|
+
def addImportFrom_asStr(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier, asname: ast_Identifier | None = None) -> None:
|
|
47
|
+
if moduleWithLogicalPath not in self.dictionaryImportFrom:
|
|
48
|
+
self.dictionaryImportFrom[moduleWithLogicalPath] = []
|
|
49
|
+
self.dictionaryImportFrom[moduleWithLogicalPath].append((name, asname))
|
|
50
|
+
|
|
51
|
+
def removeImportFromModule(self, moduleWithLogicalPath: str_nameDOTname) -> None:
|
|
52
|
+
self.removeImportFrom(moduleWithLogicalPath, None, None)
|
|
53
|
+
"""Remove all imports from a specific module."""
|
|
54
|
+
|
|
55
|
+
def removeImportFrom(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier | None, asname: ast_Identifier | None = None) -> None:
|
|
56
|
+
if moduleWithLogicalPath is None:
|
|
57
|
+
raise SyntaxError(f"I received `{moduleWithLogicalPath = }`, but it must be the name of a module.")
|
|
58
|
+
if moduleWithLogicalPath in self.dictionaryImportFrom:
|
|
59
|
+
"""
|
|
60
|
+
name, asname Meaning
|
|
61
|
+
ast_Identifier, ast_Identifier : remove exact matches
|
|
62
|
+
ast_Identifier, None : remove exact matches
|
|
63
|
+
None, ast_Identifier : remove all matches for asname and if entry_asname is None remove name == ast_Identifier
|
|
64
|
+
None, None : remove all matches for the module
|
|
65
|
+
"""
|
|
66
|
+
if name is None and asname is None:
|
|
67
|
+
# Remove all entries for the module
|
|
68
|
+
self.dictionaryImportFrom.pop(moduleWithLogicalPath)
|
|
69
|
+
else:
|
|
70
|
+
if name is None:
|
|
71
|
+
self.dictionaryImportFrom[moduleWithLogicalPath] = [(entry_name, entry_asname) for entry_name, entry_asname in self.dictionaryImportFrom[moduleWithLogicalPath]
|
|
72
|
+
if not (entry_asname == asname) and not (entry_asname is None and entry_name == asname)]
|
|
73
|
+
else:
|
|
74
|
+
# Remove exact matches for the module
|
|
75
|
+
self.dictionaryImportFrom[moduleWithLogicalPath] = [(entry_name, entry_asname) for entry_name, entry_asname in self.dictionaryImportFrom[moduleWithLogicalPath]
|
|
76
|
+
if not (entry_name == name and entry_asname == asname)]
|
|
77
|
+
if not self.dictionaryImportFrom[moduleWithLogicalPath]:
|
|
78
|
+
self.dictionaryImportFrom.pop(moduleWithLogicalPath)
|
|
44
79
|
|
|
45
80
|
def exportListModuleIdentifiers(self) -> list[ast_Identifier]:
|
|
46
81
|
listModuleIdentifiers: list[ast_Identifier] = list(self.dictionaryImportFrom.keys())
|
|
@@ -49,13 +84,14 @@ class LedgerOfImports:
|
|
|
49
84
|
|
|
50
85
|
def makeList_ast(self) -> list[ast.ImportFrom | ast.Import]:
|
|
51
86
|
listImportFrom: list[ast.ImportFrom] = []
|
|
52
|
-
for
|
|
87
|
+
for moduleWithLogicalPath, listOfNameTuples in sorted(self.dictionaryImportFrom.items()):
|
|
53
88
|
listOfNameTuples = sorted(list(set(listOfNameTuples)), key=lambda nameTuple: nameTuple[0])
|
|
54
89
|
list_alias: list[ast.alias] = []
|
|
55
90
|
for name, asname in listOfNameTuples:
|
|
56
91
|
list_alias.append(Make.alias(name, asname))
|
|
57
|
-
|
|
58
|
-
|
|
92
|
+
if list_alias:
|
|
93
|
+
listImportFrom.append(Make.ImportFrom(moduleWithLogicalPath, list_alias))
|
|
94
|
+
list_astImport: list[ast.Import] = [Make.Import(moduleWithLogicalPath) for moduleWithLogicalPath in sorted(set(self.listImport))]
|
|
59
95
|
return listImportFrom + list_astImport
|
|
60
96
|
|
|
61
97
|
def update(self, *fromLedger: 'LedgerOfImports') -> None:
|
|
@@ -158,6 +194,19 @@ class IngredientsModule:
|
|
|
158
194
|
else:
|
|
159
195
|
raise ValueError(f"I received `{type(allegedIngredientsFunction) = }`, but I can only accept `{IngredientsFunction}`.")
|
|
160
196
|
|
|
197
|
+
def removeImportFromModule(self, moduleWithLogicalPath: str_nameDOTname) -> None:
|
|
198
|
+
self.removeImportFrom(moduleWithLogicalPath, None, None)
|
|
199
|
+
"""Remove all imports from a specific module."""
|
|
200
|
+
|
|
201
|
+
def removeImportFrom(self, moduleWithLogicalPath: str_nameDOTname, name: ast_Identifier | None, asname: ast_Identifier | None = None) -> None:
|
|
202
|
+
"""
|
|
203
|
+
This method modifies all `LedgerOfImports` in this `IngredientsModule` and all `IngredientsFunction` in `listIngredientsFunctions`.
|
|
204
|
+
It is not a "blacklist", so the import from could be added after this modification.
|
|
205
|
+
"""
|
|
206
|
+
self.imports.removeImportFrom(moduleWithLogicalPath, name, asname)
|
|
207
|
+
for ingredientsFunction in self.listIngredientsFunctions:
|
|
208
|
+
ingredientsFunction.imports.removeImportFrom(moduleWithLogicalPath, name, asname)
|
|
209
|
+
|
|
161
210
|
@property
|
|
162
211
|
def list_astImportImportFrom(self) -> list[ast.Import | ast.ImportFrom]:
|
|
163
212
|
"""List of `ast.Import` and `ast.ImportFrom` statements."""
|
|
@@ -299,8 +348,36 @@ theLogicalPathModuleDispatcherSynthetic: str = '.'.join([The.packageName, The.mo
|
|
|
299
348
|
if self.callableDispatcher!=callableDispatcherHARDCODED:
|
|
300
349
|
print(f"fyi: `{self.callableDispatcher=}` but\n\t`{callableDispatcherHARDCODED=}`.")
|
|
301
350
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
351
|
+
dummyAssign = Make.Assign([Make.Name("dummyTarget")], Make.Constant(None))
|
|
352
|
+
dummySubscript = Make.Subscript(Make.Name("dummy"), Make.Name("slice"))
|
|
353
|
+
dummyTuple = Make.Tuple([Make.Name("dummyElement")])
|
|
354
|
+
|
|
355
|
+
@dataclasses.dataclass
|
|
356
|
+
class ShatteredDataclass:
|
|
357
|
+
countingVariableAnnotation: ImaAnnotationType
|
|
358
|
+
"""Type annotation for the counting variable extracted from the dataclass."""
|
|
359
|
+
countingVariableName: ast.Name
|
|
360
|
+
"""AST name node representing the counting variable identifier."""
|
|
361
|
+
field2AnnAssign: dict[ast_Identifier, ast.AnnAssign] = dataclasses.field(default_factory=dict)
|
|
362
|
+
"""Maps field names to their corresponding AST call expressions."""
|
|
363
|
+
Z0Z_field2AnnAssign: dict[ast_Identifier, tuple[ast.AnnAssign, str]] = dataclasses.field(default_factory=dict)
|
|
364
|
+
fragments4AssignmentOrParameters: ast.Tuple = dummyTuple
|
|
365
|
+
"""AST tuple used as target for assignment to capture returned fragments."""
|
|
366
|
+
ledger: LedgerOfImports = dataclasses.field(default_factory=LedgerOfImports)
|
|
367
|
+
"""Import records for the dataclass and its constituent parts."""
|
|
368
|
+
list_argAnnotated4ArgumentsSpecification: list[ast.arg] = dataclasses.field(default_factory=list)
|
|
369
|
+
"""Function argument nodes with annotations for parameter specification."""
|
|
370
|
+
list_keyword_field__field4init: list[ast.keyword] = dataclasses.field(default_factory=list)
|
|
371
|
+
"""Keyword arguments for dataclass initialization with field=field format."""
|
|
372
|
+
listAnnotations: list[ImaAnnotationType] = dataclasses.field(default_factory=list)
|
|
373
|
+
"""Type annotations for each dataclass field."""
|
|
374
|
+
listName4Parameters: list[ast.Name] = dataclasses.field(default_factory=list)
|
|
375
|
+
"""Name nodes for each dataclass field used as function parameters."""
|
|
376
|
+
listUnpack: list[ast.AnnAssign] = dataclasses.field(default_factory=list)
|
|
377
|
+
"""Annotated assignment statements to extract fields from dataclass."""
|
|
378
|
+
map_stateDOTfield2Name: dict[ast.expr, ast.Name] = dataclasses.field(default_factory=dict)
|
|
379
|
+
"""Maps AST expressions to Name nodes for find-replace operations."""
|
|
380
|
+
repack: ast.Assign = dummyAssign
|
|
381
|
+
"""AST assignment statement that reconstructs the original dataclass instance."""
|
|
382
|
+
signatureReturnAnnotation: ast.Subscript = dummySubscript
|
|
383
|
+
"""tuple-based return type annotation for function definitions."""
|
|
@@ -1,57 +1,43 @@
|
|
|
1
|
-
from collections.abc import Callable
|
|
1
|
+
from collections.abc import Callable, Sequence
|
|
2
2
|
from inspect import getsource as inspect_getsource
|
|
3
|
-
from mapFolding.someAssemblyRequired import ast_Identifier, str_nameDOTname
|
|
3
|
+
from mapFolding.someAssemblyRequired import ast_Identifier, str_nameDOTname, 个
|
|
4
4
|
from os import PathLike
|
|
5
5
|
from pathlib import Path, PurePath
|
|
6
6
|
from types import ModuleType
|
|
7
|
-
from typing import Any,
|
|
7
|
+
from typing import Any, cast, Generic, TypeGuard
|
|
8
8
|
import ast
|
|
9
9
|
import importlib
|
|
10
10
|
import importlib.util
|
|
11
11
|
|
|
12
12
|
# TODO Identify the logic that narrows the type and can help the user during static type checking.
|
|
13
13
|
|
|
14
|
-
class NodeTourist(ast.NodeVisitor):
|
|
15
|
-
def __init__(self, findThis, doThat
|
|
14
|
+
class NodeTourist(ast.NodeVisitor, Generic[个]):
|
|
15
|
+
def __init__(self, findThis: Callable[[个], TypeGuard[个] | bool], doThat: Callable[[个], 个 | None]) -> None:
|
|
16
16
|
self.findThis = findThis
|
|
17
17
|
self.doThat = doThat
|
|
18
|
-
self.nodeCaptured = None
|
|
18
|
+
self.nodeCaptured: 个 | None = None
|
|
19
19
|
|
|
20
|
-
def visit(self, node): #
|
|
20
|
+
def visit(self, node: 个) -> None: # pyright: ignore [reportGeneralTypeIssues]
|
|
21
21
|
if self.findThis(node):
|
|
22
|
-
nodeActionReturn = self.doThat(node)
|
|
22
|
+
nodeActionReturn = self.doThat(node)
|
|
23
23
|
if nodeActionReturn is not None:
|
|
24
|
-
self.nodeCaptured = nodeActionReturn
|
|
25
|
-
self.generic_visit(node)
|
|
26
|
-
|
|
27
|
-
def captureLastMatch(self, node): # type: ignore
|
|
28
|
-
"""Capture the last matched node that produces a non-None result.
|
|
29
|
-
|
|
30
|
-
This method traverses the entire tree starting at the given node
|
|
31
|
-
and returns the last non-None value produced by applying doThat
|
|
32
|
-
to a matching node. It will continue traversing after finding a match,
|
|
33
|
-
and the value captured can be replaced by later matches.
|
|
34
|
-
|
|
35
|
-
Parameters:
|
|
36
|
-
node: The AST node to start traversal from
|
|
24
|
+
self.nodeCaptured = nodeActionReturn
|
|
25
|
+
self.generic_visit(cast(ast.AST, node))
|
|
37
26
|
|
|
38
|
-
|
|
39
|
-
The result of applying doThat to the last matching node that returned
|
|
40
|
-
a non-None value, or None if no match found or all matches returned None
|
|
41
|
-
"""
|
|
27
|
+
def captureLastMatch(self, node: 个) -> 个 | None: # pyright: ignore [reportGeneralTypeIssues]
|
|
42
28
|
self.nodeCaptured = None
|
|
43
|
-
self.visit(node)
|
|
29
|
+
self.visit(node)
|
|
44
30
|
return self.nodeCaptured
|
|
45
31
|
|
|
46
|
-
class NodeChanger(ast.NodeTransformer):
|
|
47
|
-
def __init__(self, findThis, doThat
|
|
32
|
+
class NodeChanger(ast.NodeTransformer, Generic[个]):
|
|
33
|
+
def __init__(self, findThis: Callable[[个], bool], doThat: Callable[[个], Sequence[个] | 个 | None]) -> None:
|
|
48
34
|
self.findThis = findThis
|
|
49
35
|
self.doThat = doThat
|
|
50
36
|
|
|
51
|
-
def visit(self, node): #
|
|
37
|
+
def visit(self, node: 个) -> Sequence[个] | 个 | None: # pyright: ignore [reportGeneralTypeIssues]
|
|
52
38
|
if self.findThis(node):
|
|
53
|
-
return self.doThat(node)
|
|
54
|
-
return super().visit(node)
|
|
39
|
+
return self.doThat(node)
|
|
40
|
+
return super().visit(cast(ast.AST, node))
|
|
55
41
|
|
|
56
42
|
def importLogicalPath2Callable(logicalPathModule: str_nameDOTname, identifier: ast_Identifier, packageIdentifierIfRelative: ast_Identifier | None = None) -> Callable[..., Any]:
|
|
57
43
|
moduleImported: ModuleType = importlib.import_module(logicalPathModule, packageIdentifierIfRelative)
|
|
@@ -18,9 +18,9 @@ mapFolding/reference/jobsCompleted/[2x19]/[2x19].ll
|
|
|
18
18
|
|
|
19
19
|
This file demonstrates the low-level optimizations that made this previously
|
|
20
20
|
intractable calculation possible. The IR reveals how the abstract algorithm was
|
|
21
|
-
transformed into efficient machine code through Numba's compilation
|
|
21
|
+
transformed into efficient machine code through Numba's compilation assembly-line.
|
|
22
22
|
|
|
23
|
-
While originally part of a tighter integration with the code generation
|
|
23
|
+
While originally part of a tighter integration with the code generation assembly-line,
|
|
24
24
|
this module now operates as a standalone utility that can be applied to any module
|
|
25
25
|
containing Numba-compiled functions.
|
|
26
26
|
"""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from mapFolding.someAssemblyRequired import ast_Identifier, RecipeSynthesizeFlow, Then, be, ifThis, DOT, 又, NodeChanger
|
|
4
|
+
from mapFolding.someAssemblyRequired.transformationTools import makeDictionary4InliningFunction, makeDictionaryFunctionDef
|
|
5
|
+
from typing import cast
|
|
6
|
+
import ast
|
|
7
|
+
|
|
8
|
+
def inlineFunctionDef(astFunctionDef: ast.FunctionDef, dictionary4Inlining: dict[ast_Identifier, ast.FunctionDef]) -> ast.FunctionDef:
|
|
9
|
+
|
|
10
|
+
return astFunctionDef
|
|
11
|
+
|
|
12
|
+
# Test code
|
|
13
|
+
testFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
|
|
14
|
+
dictionary4Inlining: dict[ast_Identifier, ast.FunctionDef] = makeDictionary4InliningFunction(
|
|
15
|
+
testFlow.sourceCallableSequential,
|
|
16
|
+
(dictionaryFunctionDef := makeDictionaryFunctionDef(testFlow.source_astModule)))
|
|
17
|
+
|
|
18
|
+
astFunctionDef = dictionaryFunctionDef[testFlow.sourceCallableSequential]
|
|
19
|
+
|
|
20
|
+
astFunctionDefTransformed = inlineFunctionDef(
|
|
21
|
+
astFunctionDef,
|
|
22
|
+
dictionary4Inlining)
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
"""Synthesize one file to compute `foldsTotal` of `mapShape`."""
|
|
2
|
-
from mapFolding.
|
|
3
|
-
from mapFolding.someAssemblyRequired
|
|
4
|
-
from mapFolding.someAssemblyRequired.
|
|
5
|
-
from mapFolding.someAssemblyRequired.
|
|
6
|
-
from mapFolding.someAssemblyRequired.
|
|
7
|
-
from mapFolding.
|
|
8
|
-
from mapFolding.
|
|
9
|
-
from pathlib import Path, PurePosixPath
|
|
2
|
+
from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal
|
|
3
|
+
from mapFolding.someAssemblyRequired import ast_Identifier, be, ifThis, Make, NodeChanger, Then, IngredientsFunction, IngredientsModule, LedgerOfImports
|
|
4
|
+
from mapFolding.someAssemblyRequired.toolboxNumba import RecipeJob, SpicesJobNumba, decorateCallableWithNumba
|
|
5
|
+
from mapFolding.someAssemblyRequired.transformationTools import astModuleToIngredientsFunction, extractFunctionDef, write_astModule
|
|
6
|
+
from mapFolding.someAssemblyRequired.transformationTools import makeInitializedComputationState
|
|
7
|
+
from mapFolding.theSSOT import The, raiseIfNoneGitHubIssueNumber3
|
|
8
|
+
from mapFolding.oeis import getFoldsTotalKnown
|
|
10
9
|
from typing import cast
|
|
11
10
|
from Z0Z_tools import autoDecodingRLE
|
|
11
|
+
from pathlib import PurePosixPath
|
|
12
12
|
import ast
|
|
13
|
-
import dataclasses
|
|
14
13
|
|
|
15
14
|
list_IdentifiersNotUsedAllHARDCODED = ['concurrencyLimit', 'foldsTotal', 'mapShape',]
|
|
16
15
|
list_IdentifiersNotUsedParallelSequentialHARDCODED = ['indexLeaf']
|
|
@@ -22,105 +21,14 @@ list_IdentifiersStaticValuesHARDCODED = ['dimensionsTotal', 'leavesTotal',]
|
|
|
22
21
|
|
|
23
22
|
list_IdentifiersNotUsedHARDCODED = list_IdentifiersStaticValuesHARDCODED + list_IdentifiersReplacedHARDCODED + list_IdentifiersNotUsedAllHARDCODED + list_IdentifiersNotUsedParallelSequentialHARDCODED + list_IdentifiersNotUsedSequentialHARDCODED
|
|
24
23
|
|
|
25
|
-
|
|
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:
|
|
24
|
+
def addLauncherNumbaProgress(ingredientsModule: IngredientsModule, ingredientsFunction: IngredientsFunction, job: RecipeJob, spices: SpicesJobNumba) -> tuple[IngredientsModule, IngredientsFunction]:
|
|
117
25
|
|
|
118
26
|
linesLaunch: str = f"""
|
|
119
27
|
if __name__ == '__main__':
|
|
120
28
|
with ProgressBar(total={job.foldsTotalEstimated}, update_interval=2) as statusUpdate:
|
|
121
29
|
{job.countCallable}(statusUpdate)
|
|
122
30
|
foldsTotal = statusUpdate.n * {job.state.leavesTotal}
|
|
123
|
-
print('
|
|
31
|
+
print('\\nmap {job.state.mapShape} =', foldsTotal)
|
|
124
32
|
writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
|
|
125
33
|
writeStream.write(str(foldsTotal))
|
|
126
34
|
writeStream.close()
|
|
@@ -130,19 +38,19 @@ if __name__ == '__main__':
|
|
|
130
38
|
ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressPythonClass)
|
|
131
39
|
ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressNumbaType)
|
|
132
40
|
|
|
133
|
-
ast_argNumbaProgress = ast.arg(arg=
|
|
41
|
+
ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
|
|
134
42
|
ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
|
|
135
43
|
|
|
136
44
|
findThis = ifThis.isAugAssign_targetIs(ifThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
|
|
137
|
-
doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(
|
|
138
|
-
countWithProgressBar = NodeChanger(findThis, doThat)
|
|
45
|
+
doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
|
|
46
|
+
countWithProgressBar = NodeChanger(findThis, doThat) # type: ignore
|
|
139
47
|
countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
|
|
140
48
|
|
|
141
49
|
ingredientsModule.appendLauncher(ast.parse(linesLaunch))
|
|
142
50
|
|
|
143
|
-
return ingredientsModule
|
|
51
|
+
return ingredientsModule, ingredientsFunction
|
|
144
52
|
|
|
145
|
-
def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job:
|
|
53
|
+
def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job: RecipeJob) -> IngredientsFunction:
|
|
146
54
|
ingredientsFunction.imports.update(job.shatteredDataclass.ledger)
|
|
147
55
|
|
|
148
56
|
list_IdentifiersNotUsed = list_IdentifiersNotUsedHARDCODED
|
|
@@ -158,7 +66,6 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
|
|
|
158
66
|
case 'scalar':
|
|
159
67
|
ImaAnnAssign.value.args[0].value = int(job.state.__dict__[ast_arg.arg]) # type: ignore
|
|
160
68
|
case 'array':
|
|
161
|
-
# print(ast.dump(ImaAnnAssign))
|
|
162
69
|
dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], addSpaces=True)
|
|
163
70
|
dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
|
|
164
71
|
ImaAnnAssign.value.args = [dataAs_astExpr] # type: ignore
|
|
@@ -180,9 +87,11 @@ def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: Ingre
|
|
|
180
87
|
ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
|
|
181
88
|
return ingredientsFunction
|
|
182
89
|
|
|
183
|
-
def makeJobNumba(job:
|
|
90
|
+
def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba):
|
|
184
91
|
# get the raw ingredients: data and the algorithm
|
|
185
|
-
|
|
92
|
+
astFunctionDef = extractFunctionDef(job.source_astModule, job.countCallable)
|
|
93
|
+
if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
|
|
94
|
+
ingredientsCount: IngredientsFunction = IngredientsFunction(astFunctionDef, LedgerOfImports())
|
|
186
95
|
|
|
187
96
|
# Change the return so you can dynamically determine which variables are not used
|
|
188
97
|
removeReturnStatement = NodeChanger(be.Return, Then.removeIt)
|
|
@@ -200,18 +109,54 @@ def makeJobNumba(job: Z0Z_RecipeJob, parametersNumba: ParametersNumba = paramete
|
|
|
200
109
|
for identifier in list_IdentifiersStaticValues:
|
|
201
110
|
findThis = ifThis.isName_Identifier(identifier)
|
|
202
111
|
doThat = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
|
|
203
|
-
NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
|
|
112
|
+
NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef) # type: ignore
|
|
204
113
|
|
|
205
114
|
# This launcher eliminates the use of one identifier, so run it now and you can dynamically determine which variables are not used
|
|
206
115
|
ingredientsModule = IngredientsModule()
|
|
207
|
-
|
|
208
|
-
|
|
116
|
+
if spices.useNumbaProgressBar:
|
|
117
|
+
ingredientsModule, ingredientsCount = addLauncherNumbaProgress(ingredientsModule, ingredientsCount, job, spices)
|
|
118
|
+
spices.parametersNumba['nogil'] = True
|
|
209
119
|
|
|
210
120
|
ingredientsCount = move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsCount, job)
|
|
211
121
|
|
|
122
|
+
Z0Z_Identifier = 'DatatypeLeavesTotal'
|
|
123
|
+
Z0Z_type = 'uint8'
|
|
124
|
+
ingredientsModule.imports.addImportFrom_asStr('numba', Z0Z_type)
|
|
125
|
+
Z0Z_module = 'typing'
|
|
126
|
+
Z0Z_annotation = 'TypeAlias'
|
|
127
|
+
ingredientsModule.imports.addImportFrom_asStr(Z0Z_module, Z0Z_annotation)
|
|
128
|
+
Z0Z_statement = Make.AnnAssign(Make.Name(Z0Z_Identifier, ast.Store()), Make.Name(Z0Z_annotation), Make.Name(Z0Z_type))
|
|
129
|
+
ingredientsModule.appendPrologue(statement=Z0Z_statement)
|
|
130
|
+
|
|
131
|
+
Z0Z_Identifier = 'DatatypeElephino'
|
|
132
|
+
Z0Z_type = 'int16'
|
|
133
|
+
ingredientsModule.imports.addImportFrom_asStr('numba', Z0Z_type)
|
|
134
|
+
Z0Z_module = 'typing'
|
|
135
|
+
Z0Z_annotation = 'TypeAlias'
|
|
136
|
+
ingredientsModule.imports.addImportFrom_asStr(Z0Z_module, Z0Z_annotation)
|
|
137
|
+
Z0Z_statement = Make.AnnAssign(Make.Name(Z0Z_Identifier, ast.Store()), Make.Name(Z0Z_annotation), Make.Name(Z0Z_type))
|
|
138
|
+
ingredientsModule.appendPrologue(statement=Z0Z_statement)
|
|
139
|
+
|
|
140
|
+
ingredientsCount.imports.removeImportFromModule('mapFolding.theSSOT')
|
|
141
|
+
Z0Z_module = 'numpy'
|
|
142
|
+
Z0Z_asname = 'Array1DLeavesTotal'
|
|
143
|
+
ingredientsCount.imports.removeImportFrom(Z0Z_module, None, Z0Z_asname)
|
|
144
|
+
Z0Z_type_name = 'uint8'
|
|
145
|
+
ingredientsCount.imports.addImportFrom_asStr(Z0Z_module, Z0Z_type_name, Z0Z_asname)
|
|
146
|
+
Z0Z_asname = 'Array1DElephino'
|
|
147
|
+
ingredientsCount.imports.removeImportFrom(Z0Z_module, None, Z0Z_asname)
|
|
148
|
+
Z0Z_type_name = 'int16'
|
|
149
|
+
ingredientsCount.imports.addImportFrom_asStr(Z0Z_module, Z0Z_type_name, Z0Z_asname)
|
|
150
|
+
Z0Z_asname = 'Array3D'
|
|
151
|
+
ingredientsCount.imports.removeImportFrom(Z0Z_module, None, Z0Z_asname)
|
|
152
|
+
Z0Z_type_name = 'uint8'
|
|
153
|
+
ingredientsCount.imports.addImportFrom_asStr(Z0Z_module, Z0Z_type_name, Z0Z_asname)
|
|
154
|
+
|
|
155
|
+
from numpy import int16 as Array1DLeavesTotal, int16 as Array1DElephino, int16 as Array3D
|
|
156
|
+
|
|
212
157
|
ingredientsCount.astFunctionDef.decorator_list = [] # TODO low-priority, handle this more elegantly
|
|
213
158
|
# 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)
|
|
159
|
+
ingredientsCount = decorateCallableWithNumba(ingredientsCount, spices.parametersNumba)
|
|
215
160
|
|
|
216
161
|
ingredientsModule.appendIngredientsFunction(ingredientsCount)
|
|
217
162
|
|
|
@@ -243,5 +188,9 @@ def makeJobNumba(job: Z0Z_RecipeJob, parametersNumba: ParametersNumba = paramete
|
|
|
243
188
|
if __name__ == '__main__':
|
|
244
189
|
mapShape = (6,6)
|
|
245
190
|
state = makeInitializedComputationState(mapShape)
|
|
246
|
-
|
|
247
|
-
|
|
191
|
+
foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
|
|
192
|
+
pathModule = PurePosixPath(The.pathPackage, 'jobs')
|
|
193
|
+
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
|
|
194
|
+
aJob = RecipeJob(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
|
|
195
|
+
spices = SpicesJobNumba()
|
|
196
|
+
makeJobNumba(aJob, spices)
|