mapFolding 0.11.2__py3-none-any.whl → 0.11.3__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 +0 -13
- mapFolding/basecamp.py +2 -3
- mapFolding/beDRY.py +2 -145
- mapFolding/datatypes.py +0 -3
- mapFolding/oeis.py +0 -3
- mapFolding/someAssemblyRequired/RecipeJob.py +7 -114
- mapFolding/someAssemblyRequired/{Z0Z_makeSomeModules.py → Z0Z_makeAllModules.py} +33 -31
- mapFolding/someAssemblyRequired/__init__.py +4 -30
- mapFolding/someAssemblyRequired/_toolIfThis.py +1 -2
- mapFolding/someAssemblyRequired/_toolkitContainers.py +2 -122
- mapFolding/{infoBooth.py → someAssemblyRequired/infoBooth.py} +5 -31
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +9 -9
- mapFolding/someAssemblyRequired/toolkitNumba.py +2 -44
- mapFolding/someAssemblyRequired/transformationTools.py +7 -166
- mapFolding/theSSOT.py +9 -4
- {mapfolding-0.11.2.dist-info → mapfolding-0.11.3.dist-info}/METADATA +1 -4
- {mapfolding-0.11.2.dist-info → mapfolding-0.11.3.dist-info}/RECORD +24 -27
- {mapfolding-0.11.2.dist-info → mapfolding-0.11.3.dist-info}/WHEEL +1 -1
- tests/conftest.py +2 -77
- tests/test_computations.py +11 -18
- tests/test_tasks.py +2 -1
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +0 -315
- mapFolding/syntheticModules/numbaCount.py +0 -202
- mapFolding/theDao.py +0 -243
- {mapfolding-0.11.2.dist-info → mapfolding-0.11.3.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.11.2.dist-info → mapfolding-0.11.3.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.11.2.dist-info → mapfolding-0.11.3.dist-info}/top_level.txt +0 -0
|
@@ -18,138 +18,18 @@ The containers work in conjunction with transformation tools that manipulate the
|
|
|
18
18
|
specific optimizations and transformations.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
+
from astToolkit import ast_Identifier, ClassIsAndAttribute, DOT, LedgerOfImports, Make, NodeTourist, str_nameDOTname, Then
|
|
21
22
|
from collections.abc import Callable
|
|
22
|
-
from astToolkit import ClassIsAndAttribute
|
|
23
23
|
from copy import deepcopy
|
|
24
|
-
from mapFolding.someAssemblyRequired import
|
|
25
|
-
from mapFolding import raiseIfNoneGitHubIssueNumber3, The
|
|
26
|
-
from pathlib import Path, PurePosixPath
|
|
24
|
+
from mapFolding.someAssemblyRequired import IfThis, raiseIfNoneGitHubIssueNumber3
|
|
27
25
|
from typing import Any, cast
|
|
28
26
|
import ast
|
|
29
27
|
import dataclasses
|
|
30
28
|
|
|
31
|
-
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
32
|
-
@dataclasses.dataclass
|
|
33
|
-
class RecipeSynthesizeFlow:
|
|
34
|
-
"""
|
|
35
|
-
Configure the generation of new modules, including Numba-accelerated code modules.
|
|
36
|
-
|
|
37
|
-
RecipeSynthesizeFlow defines the complete blueprint for transforming an original Python algorithm into an optimized,
|
|
38
|
-
accelerated implementation. It specifies:
|
|
39
|
-
|
|
40
|
-
1. Source code locations and identifiers.
|
|
41
|
-
2. Target code locations and identifiers.
|
|
42
|
-
3. Naming conventions for generated modules and functions.
|
|
43
|
-
4. File system paths for output files.
|
|
44
|
-
5. Import relationships between components.
|
|
45
|
-
|
|
46
|
-
This configuration class serves as a single source of truth for the code generation process, ensuring consistency
|
|
47
|
-
across all generated artifacts while enabling customization of the transformation assembly line.
|
|
48
|
-
|
|
49
|
-
The transformation process uses this configuration to extract functions from the source module, transform them
|
|
50
|
-
according to optimization rules, and output properly structured optimized modules with all necessary imports.
|
|
51
|
-
"""
|
|
52
|
-
# ========================================
|
|
53
|
-
# Source
|
|
54
|
-
source_astModule: ast.Module = parseLogicalPath2astModule(The.logicalPathModuleSourceAlgorithm)
|
|
55
|
-
"""AST of the source algorithm module containing the original implementation."""
|
|
56
|
-
|
|
57
|
-
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
58
|
-
sourceCallableDispatcher: ast_Identifier = The.sourceCallableDispatcher
|
|
59
|
-
sourceCallableInitialize: ast_Identifier = The.sourceCallableInitialize
|
|
60
|
-
sourceCallableParallel: ast_Identifier = The.sourceCallableParallel
|
|
61
|
-
sourceCallableSequential: ast_Identifier = The.sourceCallableSequential
|
|
62
|
-
|
|
63
|
-
sourceDataclassIdentifier: ast_Identifier = The.dataclassIdentifier
|
|
64
|
-
sourceDataclassInstance: ast_Identifier = The.dataclassInstance
|
|
65
|
-
sourceDataclassInstanceTaskDistribution: ast_Identifier = The.dataclassInstanceTaskDistribution
|
|
66
|
-
sourceLogicalPathModuleDataclass: str_nameDOTname = The.logicalPathModuleDataclass
|
|
67
|
-
|
|
68
|
-
sourceConcurrencyManagerNamespace = The.sourceConcurrencyManagerNamespace
|
|
69
|
-
sourceConcurrencyManagerIdentifier = The.sourceConcurrencyManagerIdentifier
|
|
70
|
-
|
|
71
|
-
# ========================================
|
|
72
|
-
# Logical identifiers (as opposed to physical identifiers)
|
|
73
|
-
# ========================================
|
|
74
|
-
# Package ================================
|
|
75
|
-
packageIdentifier: ast_Identifier | None = The.packageName
|
|
76
|
-
|
|
77
|
-
# Qualified logical path ================================
|
|
78
|
-
logicalPathModuleDataclass: str_nameDOTname = sourceLogicalPathModuleDataclass
|
|
79
|
-
logicalPathFlowRoot: ast_Identifier | None = 'syntheticModules'
|
|
80
|
-
""" `logicalPathFlowRoot` likely corresponds to a physical filesystem directory."""
|
|
81
|
-
|
|
82
|
-
# Module ================================
|
|
83
|
-
moduleDispatcher: ast_Identifier = 'numbaCount'
|
|
84
|
-
moduleInitialize: ast_Identifier = moduleDispatcher
|
|
85
|
-
moduleParallel: ast_Identifier = moduleDispatcher
|
|
86
|
-
moduleSequential: ast_Identifier = moduleDispatcher
|
|
87
|
-
|
|
88
|
-
# Function ================================
|
|
89
|
-
callableDispatcher: ast_Identifier = sourceCallableDispatcher
|
|
90
|
-
callableInitialize: ast_Identifier = sourceCallableInitialize
|
|
91
|
-
callableParallel: ast_Identifier = sourceCallableParallel
|
|
92
|
-
callableSequential: ast_Identifier = sourceCallableSequential
|
|
93
|
-
concurrencyManagerNamespace: ast_Identifier = sourceConcurrencyManagerNamespace
|
|
94
|
-
concurrencyManagerIdentifier: ast_Identifier = sourceConcurrencyManagerIdentifier
|
|
95
|
-
dataclassIdentifier: ast_Identifier = sourceDataclassIdentifier
|
|
96
|
-
|
|
97
|
-
# Variable ================================
|
|
98
|
-
dataclassInstance: ast_Identifier = sourceDataclassInstance
|
|
99
|
-
dataclassInstanceTaskDistribution: ast_Identifier = sourceDataclassInstanceTaskDistribution
|
|
100
|
-
|
|
101
|
-
removeDataclassDispatcher: bool = False
|
|
102
|
-
removeDataclassInitialize: bool = False
|
|
103
|
-
removeDataclassParallel: bool = True
|
|
104
|
-
removeDataclassSequential: bool = True
|
|
105
|
-
# ========================================
|
|
106
|
-
# Computed
|
|
107
|
-
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
108
|
-
# theFormatStrModuleSynthetic = "{packageFlow}Count"
|
|
109
|
-
# theFormatStrModuleForCallableSynthetic = theFormatStrModuleSynthetic + "_{callableTarget}"
|
|
110
|
-
# theModuleDispatcherSynthetic: ast_Identifier = theFormatStrModuleForCallableSynthetic.format(packageFlow=packageFlowSynthetic, callableTarget=The.sourceCallableDispatcher)
|
|
111
|
-
# theLogicalPathModuleDispatcherSynthetic: str = '.'.join([The.packageName, The.moduleOfSyntheticModules, theModuleDispatcherSynthetic])
|
|
112
|
-
# logicalPathModuleDispatcher: str = '.'.join([Z0Z_flowLogicalPathRoot, moduleDispatcher])
|
|
113
|
-
|
|
114
|
-
# ========================================
|
|
115
|
-
# Filesystem (names of physical objects)
|
|
116
|
-
pathPackage: PurePosixPath | None = PurePosixPath(The.pathPackage)
|
|
117
|
-
fileExtension: str = The.fileExtension
|
|
118
|
-
|
|
119
|
-
def _makePathFilename(self, filenameStem: str,
|
|
120
|
-
pathRoot: PurePosixPath | None = None,
|
|
121
|
-
logicalPathINFIX: str_nameDOTname | None = None,
|
|
122
|
-
fileExtension: str | None = None,
|
|
123
|
-
) -> PurePosixPath:
|
|
124
|
-
"""filenameStem: (hint: the name of the logical module)"""
|
|
125
|
-
if pathRoot is None:
|
|
126
|
-
pathRoot = self.pathPackage or PurePosixPath(Path.cwd())
|
|
127
|
-
if logicalPathINFIX:
|
|
128
|
-
whyIsThisStillAThing: list[str] = logicalPathINFIX.split('.')
|
|
129
|
-
pathRoot = pathRoot.joinpath(*whyIsThisStillAThing)
|
|
130
|
-
if fileExtension is None:
|
|
131
|
-
fileExtension = self.fileExtension
|
|
132
|
-
filename: str = filenameStem + fileExtension
|
|
133
|
-
return pathRoot.joinpath(filename)
|
|
134
|
-
|
|
135
|
-
@property
|
|
136
|
-
def pathFilenameDispatcher(self) -> PurePosixPath:
|
|
137
|
-
return self._makePathFilename(filenameStem=self.moduleDispatcher, logicalPathINFIX=self.logicalPathFlowRoot)
|
|
138
|
-
@property
|
|
139
|
-
def pathFilenameInitialize(self) -> PurePosixPath:
|
|
140
|
-
return self._makePathFilename(filenameStem=self.moduleInitialize, logicalPathINFIX=self.logicalPathFlowRoot)
|
|
141
|
-
@property
|
|
142
|
-
def pathFilenameParallel(self) -> PurePosixPath:
|
|
143
|
-
return self._makePathFilename(filenameStem=self.moduleParallel, logicalPathINFIX=self.logicalPathFlowRoot)
|
|
144
|
-
@property
|
|
145
|
-
def pathFilenameSequential(self) -> PurePosixPath:
|
|
146
|
-
return self._makePathFilename(filenameStem=self.moduleSequential, logicalPathINFIX=self.logicalPathFlowRoot)
|
|
147
|
-
|
|
148
29
|
dummyAssign = Make.Assign([Make.Name("dummyTarget")], Make.Constant(None))
|
|
149
30
|
dummySubscript = Make.Subscript(Make.Name("dummy"), Make.Name("slice"))
|
|
150
31
|
dummyTuple = Make.Tuple([Make.Name("dummyElement")])
|
|
151
32
|
|
|
152
|
-
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
153
33
|
@dataclasses.dataclass
|
|
154
34
|
class ShatteredDataclass:
|
|
155
35
|
countingVariableAnnotation: ast.expr
|
|
@@ -1,27 +1,13 @@
|
|
|
1
|
-
from
|
|
2
|
-
from importlib import import_module as importlib_import_module
|
|
3
|
-
from mapFolding import ComputationState, PackageSettings
|
|
4
|
-
from types import ModuleType
|
|
1
|
+
from mapFolding import PackageSettings
|
|
5
2
|
import dataclasses
|
|
6
3
|
|
|
7
4
|
@dataclasses.dataclass
|
|
8
5
|
class PackageInformation(PackageSettings):
|
|
9
|
-
|
|
10
|
-
In _all_ of the root directory and "syntheticModules", the _only_ `PackageInformation` that are used are:
|
|
11
|
-
The.concurrencyPackage
|
|
12
|
-
The.dispatcher
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
logicalPathModuleDispatcher: str | None = None
|
|
16
|
-
"""Logical import path to the module containing the dispatcher function."""
|
|
17
|
-
|
|
18
|
-
callableDispatcher: str | None = None
|
|
6
|
+
callableDispatcher: str = 'doTheNeedful'
|
|
19
7
|
"""Name of the function within the dispatcher module that will be called."""
|
|
20
8
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# "Evaluate When Packaging" and "Evaluate When Installing" https://github.com/hunterhogan/mapFolding/issues/18
|
|
9
|
+
# "Evaluate When Packaging" and "Evaluate When Installing"
|
|
10
|
+
# https://github.com/hunterhogan/mapFolding/issues/18
|
|
25
11
|
dataclassIdentifier: str = dataclasses.field(default='ComputationState', metadata={'evaluateWhen': 'packaging'})
|
|
26
12
|
"""Name of the dataclass used to track computation state."""
|
|
27
13
|
|
|
@@ -70,14 +56,6 @@ class PackageInformation(PackageSettings):
|
|
|
70
56
|
logicalPathModuleSourceAlgorithm: str = dataclasses.field(default=None, metadata={'evaluateWhen': 'packaging'}) # pyright: ignore[reportAssignmentType]
|
|
71
57
|
"""Fully qualified import path to the module containing the source algorithm."""
|
|
72
58
|
|
|
73
|
-
@property
|
|
74
|
-
def dispatcher(self) -> Callable[['ComputationState'], 'ComputationState']:
|
|
75
|
-
""" _The_ callable that connects `countFolds` to the logic that does the work."""
|
|
76
|
-
logicalPath: str = self.logicalPathModuleDispatcher or self.logicalPathModuleSourceAlgorithm
|
|
77
|
-
identifier: str = self.callableDispatcher or self.sourceCallableDispatcher
|
|
78
|
-
moduleImported: ModuleType = importlib_import_module(logicalPath)
|
|
79
|
-
return getattr(moduleImported, identifier)
|
|
80
|
-
|
|
81
59
|
def __post_init__(self) -> None:
|
|
82
60
|
if self.dataclassInstanceTaskDistribution is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
83
61
|
self.dataclassInstanceTaskDistribution = self.dataclassInstance + self.dataclassInstanceTaskDistributionSuffix
|
|
@@ -89,8 +67,4 @@ class PackageInformation(PackageSettings):
|
|
|
89
67
|
|
|
90
68
|
class raiseIfNoneGitHubIssueNumber3(Exception): pass
|
|
91
69
|
|
|
92
|
-
|
|
93
|
-
callableDispatcherHARDCODED: str = 'doTheNeedful'
|
|
94
|
-
concurrencyPackageHARDCODED = 'multiprocessing'
|
|
95
|
-
|
|
96
|
-
The = PackageInformation(logicalPathModuleDispatcher=logicalPathModuleDispatcherHARDCODED, callableDispatcher=callableDispatcherHARDCODED, concurrencyPackage=concurrencyPackageHARDCODED)
|
|
70
|
+
packageInformation = PackageInformation()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from
|
|
2
|
-
from mapFolding import
|
|
3
|
-
from
|
|
1
|
+
from mapFolding import getPathFilenameFoldsTotal, MapFoldingState
|
|
2
|
+
from mapFolding.someAssemblyRequired import IfThis, packageInformation, raiseIfNoneGitHubIssueNumber3
|
|
3
|
+
from astToolkit import (
|
|
4
4
|
ast_Identifier,
|
|
5
5
|
Be,
|
|
6
|
+
ClassIsAndAttribute,
|
|
6
7
|
extractFunctionDef,
|
|
7
|
-
IfThis,
|
|
8
8
|
IngredientsFunction,
|
|
9
9
|
IngredientsModule,
|
|
10
10
|
LedgerOfImports,
|
|
@@ -13,10 +13,10 @@ from mapFolding.someAssemblyRequired import (
|
|
|
13
13
|
NodeTourist,
|
|
14
14
|
str_nameDOTname,
|
|
15
15
|
Then,
|
|
16
|
-
write_astModule,
|
|
17
16
|
)
|
|
17
|
+
from astToolkit.transformationTools import write_astModule
|
|
18
18
|
from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2Numba
|
|
19
|
-
from mapFolding.someAssemblyRequired.toolkitNumba import parametersNumbaLight, SpicesJobNumba
|
|
19
|
+
from mapFolding.someAssemblyRequired.toolkitNumba import decorateCallableWithNumba, parametersNumbaLight, SpicesJobNumba
|
|
20
20
|
from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
|
|
21
21
|
from pathlib import PurePosixPath
|
|
22
22
|
from typing import cast, NamedTuple
|
|
@@ -77,7 +77,7 @@ if __name__ == '__main__':
|
|
|
77
77
|
ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
|
|
78
78
|
ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
|
|
79
79
|
|
|
80
|
-
findThis = ClassIsAndAttribute.targetIs(ast.AugAssign, IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
|
|
80
|
+
findThis = ClassIsAndAttribute.targetIs(ast.AugAssign, IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id))
|
|
81
81
|
doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
|
|
82
82
|
countWithProgressBar = NodeChanger(findThis, doThat)
|
|
83
83
|
countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
|
|
@@ -184,7 +184,7 @@ def makeJobNumba(job: RecipeJobTheorem2Numba, spices: SpicesJobNumba) -> None:
|
|
|
184
184
|
if __name__ == '__main__':
|
|
185
185
|
import time
|
|
186
186
|
timeStart = time.perf_counter()
|
|
187
|
-
foldsTotal = {job.countCallable}() * {job.state.leavesTotal}
|
|
187
|
+
foldsTotal = int({job.countCallable}() * {job.state.leavesTotal})
|
|
188
188
|
print(time.perf_counter() - timeStart)
|
|
189
189
|
print('\\nmap {job.state.mapShape} =', foldsTotal)
|
|
190
190
|
writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
|
|
@@ -267,7 +267,7 @@ if __name__ == '__main__':
|
|
|
267
267
|
# foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
|
|
268
268
|
# foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal
|
|
269
269
|
foldsTotalEstimated = 0
|
|
270
|
-
pathModule = PurePosixPath(
|
|
270
|
+
pathModule = PurePosixPath(packageInformation.pathPackage, 'jobs')
|
|
271
271
|
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
|
|
272
272
|
aJob = RecipeJobTheorem2Numba(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
|
|
273
273
|
spices = SpicesJobNumba(useNumbaProgressBar=False, parametersNumba=parametersNumbaLight)
|
|
@@ -17,16 +17,13 @@ performance improvements while preserving code semantics and correctness.
|
|
|
17
17
|
|
|
18
18
|
from collections.abc import Callable, Sequence
|
|
19
19
|
from mapFolding import NotRequired, TypedDict
|
|
20
|
-
from
|
|
21
|
-
from
|
|
20
|
+
from astToolkit import ast_Identifier, IngredientsFunction, Make, str_nameDOTname
|
|
21
|
+
from astToolkit.transformationTools import write_astModule
|
|
22
22
|
from numba.core.compiler import CompilerBase as numbaCompilerBase
|
|
23
23
|
from typing import Any, cast, Final
|
|
24
24
|
import ast
|
|
25
25
|
import dataclasses
|
|
26
26
|
|
|
27
|
-
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
28
|
-
theNumbaFlow: RecipeSynthesizeFlow = RecipeSynthesizeFlow()
|
|
29
|
-
|
|
30
27
|
class ParametersNumba(TypedDict):
|
|
31
28
|
_dbg_extend_lifetimes: NotRequired[bool]
|
|
32
29
|
_dbg_optnone: NotRequired[bool]
|
|
@@ -128,47 +125,8 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
128
125
|
ingredientsFunction.astFunctionDef.decorator_list = [astDecorator]
|
|
129
126
|
return ingredientsFunction
|
|
130
127
|
|
|
131
|
-
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
132
128
|
@dataclasses.dataclass
|
|
133
129
|
class SpicesJobNumba:
|
|
134
130
|
useNumbaProgressBar: bool = True
|
|
135
131
|
numbaProgressBarIdentifier: ast_Identifier = 'ProgressBarGroupsOfFolds'
|
|
136
132
|
parametersNumba: ParametersNumba = dataclasses.field(default_factory=ParametersNumba) # type: ignore
|
|
137
|
-
|
|
138
|
-
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
139
|
-
def makeNumbaFlow(numbaFlow: RecipeSynthesizeFlow) -> None:
|
|
140
|
-
"""
|
|
141
|
-
Transform standard Python algorithm code into optimized Numba implementations.
|
|
142
|
-
|
|
143
|
-
This function implements the complete transformation assembly line that converts
|
|
144
|
-
a conventional Python implementation into a high-performance Numba-accelerated
|
|
145
|
-
version. The process includes:
|
|
146
|
-
|
|
147
|
-
1. Extracting core algorithm functions from the source module
|
|
148
|
-
2. Inlining function calls to create self-contained implementations
|
|
149
|
-
3. Transforming dataclass access patterns for Numba compatibility
|
|
150
|
-
4. Applying appropriate Numba decorators with optimization settings
|
|
151
|
-
5. Generating a unified module with sequential and parallel implementations
|
|
152
|
-
6. Writing the transformed code to the filesystem with properly managed imports
|
|
153
|
-
|
|
154
|
-
The transformation preserves the logical structure and semantics of the original
|
|
155
|
-
implementation while making it compatible with Numba's constraints and
|
|
156
|
-
optimization capabilities. This creates a bridge between the general-purpose
|
|
157
|
-
implementation and the highly-optimized version needed for production use.
|
|
158
|
-
|
|
159
|
-
Parameters:
|
|
160
|
-
numbaFlow: Configuration object that specifies all aspects of the
|
|
161
|
-
transformation process, including source and target locations,
|
|
162
|
-
function and variable names, and output paths.
|
|
163
|
-
"""
|
|
164
|
-
|
|
165
|
-
ingredientsModuleNumbaUnified = makeNewFlow(numbaFlow)
|
|
166
|
-
|
|
167
|
-
# numba decorators =========================================
|
|
168
|
-
ingredientsModuleNumbaUnified.listIngredientsFunctions[1] = decorateCallableWithNumba(ingredientsModuleNumbaUnified.listIngredientsFunctions[1])
|
|
169
|
-
ingredientsModuleNumbaUnified.listIngredientsFunctions[2] = decorateCallableWithNumba(ingredientsModuleNumbaUnified.listIngredientsFunctions[2])
|
|
170
|
-
|
|
171
|
-
write_astModule(ingredientsModuleNumbaUnified, numbaFlow.pathFilenameDispatcher, numbaFlow.packageIdentifier)
|
|
172
|
-
|
|
173
|
-
if __name__ == '__main__':
|
|
174
|
-
makeNumbaFlow(theNumbaFlow)
|
|
@@ -18,78 +18,27 @@ readable, maintainable implementations to highly optimized versions while preser
|
|
|
18
18
|
logical structure and correctness.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
from collections.abc import Callable
|
|
22
21
|
from astToolkit import ClassIsAndAttribute
|
|
23
|
-
from mapFolding import outfitCountFolds, ComputationState, The, getPathFilenameFoldsTotal
|
|
24
22
|
from mapFolding.someAssemblyRequired import (
|
|
23
|
+
DeReConstructField2ast,
|
|
24
|
+
IfThis,
|
|
25
|
+
ShatteredDataclass,
|
|
26
|
+
)
|
|
27
|
+
from astToolkit import(
|
|
25
28
|
ast_Identifier,
|
|
26
|
-
astModuleToIngredientsFunction,
|
|
27
29
|
Be,
|
|
28
|
-
DeReConstructField2ast,
|
|
29
30
|
extractClassDef,
|
|
30
|
-
Grab,
|
|
31
|
-
IfThis,
|
|
32
|
-
importLogicalPath2Callable,
|
|
33
31
|
IngredientsFunction,
|
|
34
|
-
IngredientsModule,
|
|
35
|
-
inlineFunctionDef,
|
|
36
|
-
LedgerOfImports,
|
|
37
32
|
Make,
|
|
38
33
|
NodeChanger,
|
|
39
|
-
NodeTourist,
|
|
40
34
|
parseLogicalPath2astModule,
|
|
41
|
-
RecipeSynthesizeFlow,
|
|
42
|
-
removeUnusedParameters,
|
|
43
|
-
ShatteredDataclass,
|
|
44
35
|
str_nameDOTname,
|
|
45
36
|
Then,
|
|
46
|
-
unparseFindReplace,
|
|
47
37
|
)
|
|
48
|
-
from
|
|
49
|
-
from
|
|
50
|
-
from typing import Any, Literal, overload
|
|
38
|
+
from astToolkit.transformationTools import unparseFindReplace
|
|
39
|
+
from Z0Z_tools import importLogicalPath2Callable
|
|
51
40
|
import ast
|
|
52
41
|
import dataclasses
|
|
53
|
-
import pickle
|
|
54
|
-
|
|
55
|
-
@overload
|
|
56
|
-
def makeInitializedComputationState(mapShape: tuple[int, ...], writeJob: Literal[True], *, pathFilename: PathLike[str] | PurePath | None = None, **keywordArguments: Any) -> Path: ...
|
|
57
|
-
@overload
|
|
58
|
-
def makeInitializedComputationState(mapShape: tuple[int, ...], writeJob: Literal[False] = False, **keywordArguments: Any) -> ComputationState: ...
|
|
59
|
-
def makeInitializedComputationState(mapShape: tuple[int, ...], writeJob: bool = False, *, pathFilename: PathLike[str] | PurePath | None = None, **keywordArguments: Any) -> ComputationState | Path:
|
|
60
|
-
"""
|
|
61
|
-
Initializes a computation state and optionally saves it to disk.
|
|
62
|
-
|
|
63
|
-
This function initializes a computation state using the source algorithm.
|
|
64
|
-
|
|
65
|
-
Hint: If you want an uninitialized state, call `outfitCountFolds` directly.
|
|
66
|
-
|
|
67
|
-
Parameters:
|
|
68
|
-
mapShape: List of integers representing the dimensions of the map to be folded.
|
|
69
|
-
writeJob (False): Whether to save the state to disk.
|
|
70
|
-
pathFilename (getPathFilenameFoldsTotal.pkl): The path and filename to save the state. If None, uses a default path.
|
|
71
|
-
**keywordArguments: computationDivisions:int|str|None=None,concurrencyLimit:int=1.
|
|
72
|
-
Returns:
|
|
73
|
-
stateUniversal|pathFilenameJob: The computation state for the map folding calculations, or
|
|
74
|
-
the path to the saved state file if writeJob is True.
|
|
75
|
-
"""
|
|
76
|
-
stateUniversal: ComputationState = outfitCountFolds(mapShape, **keywordArguments)
|
|
77
|
-
|
|
78
|
-
initializeState = importLogicalPath2Callable(The.logicalPathModuleSourceAlgorithm, The.sourceCallableInitialize)
|
|
79
|
-
stateUniversal = initializeState(stateUniversal)
|
|
80
|
-
|
|
81
|
-
if not writeJob:
|
|
82
|
-
return stateUniversal
|
|
83
|
-
|
|
84
|
-
if pathFilename:
|
|
85
|
-
pathFilenameJob = Path(pathFilename)
|
|
86
|
-
pathFilenameJob.parent.mkdir(parents=True, exist_ok=True)
|
|
87
|
-
else:
|
|
88
|
-
pathFilenameJob = getPathFilenameFoldsTotal(stateUniversal.mapShape).with_suffix('.pkl')
|
|
89
|
-
|
|
90
|
-
# Fix code scanning alert - Consider possible security implications associated with pickle module. #17
|
|
91
|
-
pathFilenameJob.write_bytes(pickle.dumps(stateUniversal))
|
|
92
|
-
return pathFilenameJob
|
|
93
42
|
|
|
94
43
|
def shatter_dataclassesDOTdataclass(logicalPathModule: str_nameDOTname, dataclass_Identifier: ast_Identifier, instance_Identifier: ast_Identifier) -> ShatteredDataclass:
|
|
95
44
|
"""
|
|
@@ -161,114 +110,6 @@ def shatter_dataclassesDOTdataclass(logicalPathModule: str_nameDOTname, dataclas
|
|
|
161
110
|
return shatteredDataclass
|
|
162
111
|
|
|
163
112
|
# END of acceptable classes and functions ======================================================
|
|
164
|
-
def makeNewFlow(recipeFlow: RecipeSynthesizeFlow) -> IngredientsModule:
|
|
165
|
-
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
166
|
-
listAllIngredientsFunctions = [
|
|
167
|
-
(ingredientsInitialize := astModuleToIngredientsFunction(recipeFlow.source_astModule, recipeFlow.sourceCallableInitialize)),
|
|
168
|
-
(ingredientsParallel := astModuleToIngredientsFunction(recipeFlow.source_astModule, recipeFlow.sourceCallableParallel)),
|
|
169
|
-
(ingredientsSequential := astModuleToIngredientsFunction(recipeFlow.source_astModule, recipeFlow.sourceCallableSequential)),
|
|
170
|
-
(ingredientsDispatcher := astModuleToIngredientsFunction(recipeFlow.source_astModule, recipeFlow.sourceCallableDispatcher)),
|
|
171
|
-
]
|
|
172
|
-
|
|
173
|
-
# Inline functions ========================================================
|
|
174
|
-
# NOTE Replacements statements are based on the identifiers in the _source_, so operate on the source identifiers.
|
|
175
|
-
ingredientsInitialize.astFunctionDef = inlineFunctionDef(recipeFlow.sourceCallableInitialize, recipeFlow.source_astModule)
|
|
176
|
-
ingredientsParallel.astFunctionDef = inlineFunctionDef(recipeFlow.sourceCallableParallel, recipeFlow.source_astModule)
|
|
177
|
-
ingredientsSequential.astFunctionDef = inlineFunctionDef(recipeFlow.sourceCallableSequential, recipeFlow.source_astModule)
|
|
178
|
-
|
|
179
|
-
# assignRecipeIdentifiersToCallable. =============================
|
|
180
|
-
# Consolidate settings classes through inheritance https://github.com/hunterhogan/mapFolding/issues/15
|
|
181
|
-
# How can I use dataclass settings as the SSOT for specific actions? https://github.com/hunterhogan/mapFolding/issues/16
|
|
182
|
-
# NOTE reminder: you are updating these `ast.Name` here (and not in a more general search) because this is a
|
|
183
|
-
# narrow search for `ast.Call` so you won't accidentally replace unrelated `ast.Name`.
|
|
184
|
-
listFindReplace = [(recipeFlow.sourceCallableDispatcher, recipeFlow.callableDispatcher),
|
|
185
|
-
(recipeFlow.sourceCallableInitialize, recipeFlow.callableInitialize),
|
|
186
|
-
(recipeFlow.sourceCallableParallel, recipeFlow.callableParallel),
|
|
187
|
-
(recipeFlow.sourceCallableSequential, recipeFlow.callableSequential),]
|
|
188
|
-
for ingredients in listAllIngredientsFunctions:
|
|
189
|
-
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
190
|
-
updateCallName = NodeChanger(IfThis.isCall_Identifier(source_Identifier), Grab.funcAttribute(Then.replaceWith(Make.Name(recipe_Identifier))))
|
|
191
|
-
updateCallName.visit(ingredients.astFunctionDef)
|
|
192
|
-
|
|
193
|
-
ingredientsDispatcher.astFunctionDef.name = recipeFlow.callableDispatcher
|
|
194
|
-
ingredientsInitialize.astFunctionDef.name = recipeFlow.callableInitialize
|
|
195
|
-
ingredientsParallel.astFunctionDef.name = recipeFlow.callableParallel
|
|
196
|
-
ingredientsSequential.astFunctionDef.name = recipeFlow.callableSequential
|
|
197
|
-
|
|
198
|
-
# Assign identifiers per the recipe. ==============================
|
|
199
|
-
listFindReplace = [(recipeFlow.sourceDataclassInstance, recipeFlow.dataclassInstance),
|
|
200
|
-
(recipeFlow.sourceDataclassInstanceTaskDistribution, recipeFlow.dataclassInstanceTaskDistribution),
|
|
201
|
-
(recipeFlow.sourceConcurrencyManagerNamespace, recipeFlow.concurrencyManagerNamespace),]
|
|
202
|
-
for ingredients in listAllIngredientsFunctions:
|
|
203
|
-
for source_Identifier, recipe_Identifier in listFindReplace:
|
|
204
|
-
updateName = NodeChanger(IfThis.isName_Identifier(source_Identifier) , Grab.idAttribute(Then.replaceWith(recipe_Identifier)))
|
|
205
|
-
update_arg = NodeChanger(IfThis.isArgument_Identifier(source_Identifier), Grab.argAttribute(Then.replaceWith(recipe_Identifier)))
|
|
206
|
-
updateName.visit(ingredients.astFunctionDef)
|
|
207
|
-
update_arg.visit(ingredients.astFunctionDef)
|
|
208
|
-
|
|
209
|
-
updateConcurrencyManager = NodeChanger(IfThis.isCallAttributeNamespace_Identifier(recipeFlow.sourceConcurrencyManagerNamespace, recipeFlow.sourceConcurrencyManagerIdentifier)
|
|
210
|
-
, Grab.funcAttribute(Then.replaceWith(Make.Attribute(Make.Name(recipeFlow.concurrencyManagerNamespace), recipeFlow.concurrencyManagerIdentifier))))
|
|
211
|
-
updateConcurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
212
|
-
|
|
213
|
-
# shatter Dataclass =======================================================
|
|
214
|
-
instance_Identifier = recipeFlow.dataclassInstance
|
|
215
|
-
getTheOtherRecord_damn = recipeFlow.dataclassInstanceTaskDistribution
|
|
216
|
-
shatteredDataclass = shatter_dataclassesDOTdataclass(recipeFlow.logicalPathModuleDataclass, recipeFlow.sourceDataclassIdentifier, instance_Identifier)
|
|
217
|
-
ingredientsDispatcher.imports.update(shatteredDataclass.imports)
|
|
218
|
-
|
|
219
|
-
# How can I use dataclass settings as the SSOT for specific actions? https://github.com/hunterhogan/mapFolding/issues/16
|
|
220
|
-
# Change callable parameters and Call to the callable at the same time ====
|
|
221
|
-
# sequentialCallable =========================================================
|
|
222
|
-
if recipeFlow.removeDataclassSequential:
|
|
223
|
-
ingredientsSequential = removeDataclassFromFunction(ingredientsSequential, shatteredDataclass)
|
|
224
|
-
ingredientsDispatcher = unpackDataclassCallFunctionRepackDataclass(ingredientsDispatcher, recipeFlow.callableSequential, shatteredDataclass)
|
|
225
|
-
|
|
226
|
-
if recipeFlow.removeDataclassInitialize:
|
|
227
|
-
ingredientsInitialize = removeDataclassFromFunction(ingredientsInitialize, shatteredDataclass)
|
|
228
|
-
ingredientsDispatcher = unpackDataclassCallFunctionRepackDataclass(ingredientsDispatcher, recipeFlow.callableInitialize, shatteredDataclass)
|
|
229
|
-
|
|
230
|
-
# parallelCallable =========================================================
|
|
231
|
-
if recipeFlow.removeDataclassParallel:
|
|
232
|
-
ingredientsParallel.astFunctionDef.args = Make.arguments(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
233
|
-
|
|
234
|
-
ingredientsParallel.astFunctionDef = unparseFindReplace(ingredientsParallel.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
|
|
235
|
-
|
|
236
|
-
ingredientsParallel = removeUnusedParameters(ingredientsParallel)
|
|
237
|
-
|
|
238
|
-
list_argCuzMyBrainRefusesToThink = ingredientsParallel.astFunctionDef.args.args + ingredientsParallel.astFunctionDef.args.posonlyargs + ingredientsParallel.astFunctionDef.args.kwonlyargs
|
|
239
|
-
list_arg_arg: list[ast_Identifier] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
|
|
240
|
-
|
|
241
|
-
listParameters = [parameter for parameter in shatteredDataclass.listName4Parameters if parameter.id in list_arg_arg]
|
|
242
|
-
|
|
243
|
-
replaceCall2concurrencyManager = NodeChanger(IfThis.isCallAttributeNamespace_Identifier(recipeFlow.concurrencyManagerNamespace, recipeFlow.concurrencyManagerIdentifier), Then.replaceWith(Make.Call(Make.Attribute(Make.Name(recipeFlow.concurrencyManagerNamespace), recipeFlow.concurrencyManagerIdentifier), [Make.Name(recipeFlow.callableParallel)] + listParameters)))
|
|
244
|
-
|
|
245
|
-
def getIt(astCallConcurrencyResult: list[ast.Call]) -> Callable[[ast.AST], ast.AST]:
|
|
246
|
-
# TODO I cannot remember why I made this function. It doesn't fit with how I normally do things.
|
|
247
|
-
def workhorse(node: ast.AST) -> ast.AST:
|
|
248
|
-
NodeTourist(Be.Call, Then.appendTo(astCallConcurrencyResult)).visit(node)
|
|
249
|
-
return node
|
|
250
|
-
return workhorse
|
|
251
|
-
|
|
252
|
-
# NOTE I am dissatisfied with this logic for many reasons, including that it requires separate NodeCollector and NodeReplacer instances.
|
|
253
|
-
astCallConcurrencyResult: list[ast.Call] = []
|
|
254
|
-
get_astCallConcurrencyResult = NodeTourist(IfThis.isAssignAndTargets0Is(IfThis.isSubscript_Identifier(getTheOtherRecord_damn)), getIt(astCallConcurrencyResult))
|
|
255
|
-
get_astCallConcurrencyResult.visit(ingredientsDispatcher.astFunctionDef)
|
|
256
|
-
replaceAssignParallelCallable = NodeChanger(IfThis.isAssignAndTargets0Is(IfThis.isSubscript_Identifier(getTheOtherRecord_damn)), Grab.valueAttribute(Then.replaceWith(astCallConcurrencyResult[0])))
|
|
257
|
-
replaceAssignParallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
258
|
-
changeReturnParallelCallable = NodeChanger(Be.Return, Then.replaceWith(Make.Return(shatteredDataclass.countingVariableName)))
|
|
259
|
-
ingredientsParallel.astFunctionDef.returns = shatteredDataclass.countingVariableAnnotation
|
|
260
|
-
|
|
261
|
-
unpack4parallelCallable = NodeChanger(ClassIsAndAttribute.valueIs(ast.Assign, IfThis.isCallAttributeNamespace_Identifier(recipeFlow.concurrencyManagerNamespace, recipeFlow.concurrencyManagerIdentifier)), Then.insertThisAbove(shatteredDataclass.listUnpack))
|
|
262
|
-
|
|
263
|
-
unpack4parallelCallable.visit(ingredientsDispatcher.astFunctionDef)
|
|
264
|
-
replaceCall2concurrencyManager.visit(ingredientsDispatcher.astFunctionDef)
|
|
265
|
-
changeReturnParallelCallable.visit(ingredientsParallel.astFunctionDef)
|
|
266
|
-
|
|
267
|
-
# Module-level transformations ===========================================================
|
|
268
|
-
ingredientsModuleNumbaUnified = IngredientsModule(ingredientsFunction=listAllIngredientsFunctions, imports=LedgerOfImports(recipeFlow.source_astModule))
|
|
269
|
-
ingredientsModuleNumbaUnified.removeImportFromModule('numpy')
|
|
270
|
-
|
|
271
|
-
return ingredientsModuleNumbaUnified
|
|
272
113
|
|
|
273
114
|
def removeDataclassFromFunction(ingredientsTarget: IngredientsFunction, shatteredDataclass: ShatteredDataclass) -> IngredientsFunction:
|
|
274
115
|
ingredientsTarget.astFunctionDef.args = Make.arguments(args=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
mapFolding/theSSOT.py
CHANGED
|
@@ -5,25 +5,30 @@ from tomli import load as tomli_load
|
|
|
5
5
|
import dataclasses
|
|
6
6
|
|
|
7
7
|
packageNamePACKAGING_HARDCODED = "mapFolding"
|
|
8
|
+
concurrencyPackageHARDCODED = 'multiprocessing'
|
|
8
9
|
|
|
9
|
-
# Evaluate When Packaging
|
|
10
|
+
# Evaluate When Packaging
|
|
11
|
+
# https://github.com/hunterhogan/mapFolding/issues/18
|
|
10
12
|
try:
|
|
11
13
|
packageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
|
|
12
14
|
except Exception:
|
|
13
15
|
packageNamePACKAGING = packageNamePACKAGING_HARDCODED
|
|
14
16
|
|
|
15
|
-
# Evaluate When Installing
|
|
17
|
+
# Evaluate When Installing
|
|
18
|
+
# https://github.com/hunterhogan/mapFolding/issues/18
|
|
16
19
|
def getPathPackageINSTALLING() -> Path:
|
|
17
20
|
pathPackage: Path = Path(inspect_getfile(importlib_import_module(packageNamePACKAGING)))
|
|
18
21
|
if pathPackage.is_file():
|
|
19
22
|
pathPackage = pathPackage.parent
|
|
20
23
|
return pathPackage
|
|
21
24
|
|
|
22
|
-
# PackageSettings in theSSOT.py and immutability https://github.com/hunterhogan/mapFolding/issues/11
|
|
23
25
|
@dataclasses.dataclass
|
|
24
26
|
class PackageSettings:
|
|
25
27
|
fileExtension: str = dataclasses.field(default='.py', metadata={'evaluateWhen': 'installing'})
|
|
26
28
|
packageName: str = dataclasses.field(default = packageNamePACKAGING, metadata={'evaluateWhen': 'packaging'})
|
|
27
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')."""
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
concurrencyPackage = concurrencyPackageHARDCODED
|
|
34
|
+
packageSettings = PackageSettings(concurrencyPackage=concurrencyPackage)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mapFolding
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.3
|
|
4
4
|
Summary: Map folding algorithm with code transformation framework for optimizing numerical computations
|
|
5
5
|
Author-email: Hunter Hogan <HunterHogan@pm.me>
|
|
6
6
|
License: CC-BY-NC-4.0
|
|
@@ -33,8 +33,6 @@ Description-Content-Type: text/markdown
|
|
|
33
33
|
License-File: LICENSE
|
|
34
34
|
Requires-Dist: astToolkit
|
|
35
35
|
Requires-Dist: autoflake
|
|
36
|
-
Requires-Dist: cytoolz
|
|
37
|
-
Requires-Dist: more_itertools
|
|
38
36
|
Requires-Dist: numba_progress
|
|
39
37
|
Requires-Dist: numba
|
|
40
38
|
Requires-Dist: numpy
|
|
@@ -42,7 +40,6 @@ Requires-Dist: platformdirs
|
|
|
42
40
|
Requires-Dist: python_minifier
|
|
43
41
|
Requires-Dist: sympy
|
|
44
42
|
Requires-Dist: tomli
|
|
45
|
-
Requires-Dist: typeshed_client
|
|
46
43
|
Requires-Dist: Z0Z_tools
|
|
47
44
|
Provides-Extra: testing
|
|
48
45
|
Requires-Dist: mypy; extra == "testing"
|