mapFolding 0.8.1__py3-none-any.whl → 0.8.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 +5 -1
- mapFolding/basecamp.py +2 -2
- mapFolding/beDRY.py +24 -31
- mapFolding/oeis.py +2 -2
- mapFolding/reference/__init__.py +45 -0
- mapFolding/reference/flattened.py +20 -2
- mapFolding/reference/hunterNumba.py +24 -0
- mapFolding/reference/irvineJavaPort.py +12 -0
- mapFolding/reference/{jax.py → jaxCount.py} +46 -27
- mapFolding/reference/jobsCompleted/[2x19]/p2x19.py +197 -0
- mapFolding/reference/jobsCompleted/__init__.py +50 -0
- mapFolding/reference/jobsCompleted/p2x19/p2x19.py +29 -0
- mapFolding/reference/lunnanNumpy.py +16 -1
- mapFolding/reference/lunnanWhile.py +15 -1
- mapFolding/reference/rotatedEntryPoint.py +18 -0
- mapFolding/reference/total_countPlus1vsPlusN.py +226 -203
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +20 -1
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +52 -37
- mapFolding/someAssemblyRequired/transformDataStructures.py +11 -5
- mapFolding/someAssemblyRequired/transformationTools.py +40 -42
- mapFolding/syntheticModules/__init__.py +1 -0
- mapFolding/theSSOT.py +69 -127
- {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/METADATA +56 -31
- mapfolding-0.8.3.dist-info/RECORD +43 -0
- {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/WHEEL +1 -1
- tests/conftest.py +43 -33
- tests/test_computations.py +7 -7
- tests/test_other.py +5 -4
- mapfolding-0.8.1.dist-info/RECORD +0 -39
- {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/top_level.txt +0 -0
|
@@ -21,7 +21,7 @@ designed to be applicable to various data structure transformation scenarios.
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
from collections.abc import Sequence
|
|
24
|
-
from importlib import import_module
|
|
24
|
+
from importlib import import_module as importlib_import_module
|
|
25
25
|
from inspect import getsource as inspect_getsource
|
|
26
26
|
from mapFolding.beDRY import outfitCountFolds, validateListDimensions
|
|
27
27
|
from mapFolding.filesystem import getPathFilenameFoldsTotal
|
|
@@ -36,7 +36,7 @@ from mapFolding.someAssemblyRequired import (
|
|
|
36
36
|
Then,
|
|
37
37
|
Z0Z_executeActionUnlessDescendantMatches,
|
|
38
38
|
)
|
|
39
|
-
from mapFolding.theSSOT import ComputationState,
|
|
39
|
+
from mapFolding.theSSOT import ComputationState, The
|
|
40
40
|
from pathlib import Path
|
|
41
41
|
from types import ModuleType
|
|
42
42
|
from typing import Any, Literal, overload
|
|
@@ -69,10 +69,12 @@ def shatter_dataclassesDOTdataclass(logicalPathModule: strDotStrCuzPyStoopid, da
|
|
|
69
69
|
dataclass_Identifier: The identifier of the dataclass to be dismantled.
|
|
70
70
|
instance_Identifier: In the synthesized module/function/scope, the identifier that will be used for the instance.
|
|
71
71
|
"""
|
|
72
|
-
|
|
72
|
+
# TODO learn whether dataclasses.make_dataclass would be useful to transform the target dataclass into the `ShatteredDataclass`
|
|
73
|
+
|
|
74
|
+
module: ast.Module = ast.parse(inspect_getsource(importlib_import_module(logicalPathModule)))
|
|
73
75
|
astName_dataclassesDOTdataclass = Make.astName(dataclass_Identifier)
|
|
74
76
|
|
|
75
|
-
dataclass = extractClassDef(
|
|
77
|
+
dataclass = extractClassDef(module, dataclass_Identifier)
|
|
76
78
|
if not isinstance(dataclass, ast.ClassDef):
|
|
77
79
|
raise ValueError(f"I could not find {dataclass_Identifier=} in {logicalPathModule=}.")
|
|
78
80
|
|
|
@@ -122,6 +124,10 @@ def shatter_dataclassesDOTdataclass(logicalPathModule: strDotStrCuzPyStoopid, da
|
|
|
122
124
|
shatteredDataclass.ledgerDataclassANDFragments.addImportFromStr(logicalPathModule, dataclass_Identifier)
|
|
123
125
|
return shatteredDataclass
|
|
124
126
|
|
|
127
|
+
def getSourceAlgorithmVESTIGIAL() -> ModuleType:
|
|
128
|
+
moduleImported: ModuleType = importlib_import_module(The.logicalPathModuleSourceAlgorithm)
|
|
129
|
+
return moduleImported
|
|
130
|
+
|
|
125
131
|
@overload
|
|
126
132
|
def makeStateJobOUTDATED(listDimensions: Sequence[int], *, writeJob: Literal[True], **keywordArguments: Any) -> Path: ...
|
|
127
133
|
@overload
|
|
@@ -145,7 +151,7 @@ def makeStateJobOUTDATED(listDimensions: Sequence[int], *, writeJob: bool = True
|
|
|
145
151
|
mapShape = validateListDimensions(listDimensions)
|
|
146
152
|
stateUniversal: ComputationState = outfitCountFolds(mapShape, **keywordArguments)
|
|
147
153
|
|
|
148
|
-
moduleSource: ModuleType =
|
|
154
|
+
moduleSource: ModuleType = getSourceAlgorithmVESTIGIAL()
|
|
149
155
|
# TODO `countInitialize` is hardcoded
|
|
150
156
|
stateUniversal = moduleSource.countInitialize(stateUniversal)
|
|
151
157
|
|
|
@@ -26,27 +26,16 @@ from autoflake import fix_code as autoflake_fix_code
|
|
|
26
26
|
from collections import defaultdict
|
|
27
27
|
from collections.abc import Callable, Container, Sequence
|
|
28
28
|
from copy import deepcopy
|
|
29
|
+
from importlib import import_module as importlib_import_module
|
|
29
30
|
from inspect import getsource as inspect_getsource
|
|
30
31
|
from mapFolding.filesystem import writeStringToHere
|
|
31
32
|
from mapFolding.theSSOT import (
|
|
32
|
-
getSourceAlgorithm,
|
|
33
33
|
raiseIfNoneGitHubIssueNumber3,
|
|
34
|
-
|
|
35
|
-
theDataclassInstance,
|
|
36
|
-
theDataclassInstanceTaskDistribution,
|
|
37
|
-
theDispatcherCallable,
|
|
38
|
-
theFileExtension,
|
|
34
|
+
The,
|
|
39
35
|
theFormatStrModuleForCallableSynthetic,
|
|
40
36
|
theFormatStrModuleSynthetic,
|
|
41
|
-
theLogicalPathModuleDataclass,
|
|
42
37
|
theLogicalPathModuleDispatcherSynthetic,
|
|
43
38
|
theModuleDispatcherSynthetic,
|
|
44
|
-
theModuleOfSyntheticModules,
|
|
45
|
-
thePackageName,
|
|
46
|
-
thePathPackage,
|
|
47
|
-
theSourceInitializeCallable,
|
|
48
|
-
theSourceParallelCallable,
|
|
49
|
-
theSourceSequentialCallable,
|
|
50
39
|
)
|
|
51
40
|
from os import PathLike
|
|
52
41
|
from pathlib import Path, PurePath, PurePosixPath
|
|
@@ -200,7 +189,8 @@ class ifThis:
|
|
|
200
189
|
return isinstance(node, ast.Call)
|
|
201
190
|
@staticmethod
|
|
202
191
|
def isCall_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Call] | bool]:
|
|
203
|
-
|
|
192
|
+
def workhorse(node: ast.AST) -> TypeGuard[ast.Call] | bool: return ifThis.isCall(node) and ifThis.isName_Identifier(identifier)(node.func)
|
|
193
|
+
return workhorse
|
|
204
194
|
@staticmethod
|
|
205
195
|
def isCallNamespace_Identifier(namespace: ast_Identifier, identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Call] | bool]:
|
|
206
196
|
return lambda node: ifThis.isCall(node) and ifThis.is_nameDOTnameNamespace_Identifier(namespace, identifier)(node.func)
|
|
@@ -226,8 +216,7 @@ class ifThis:
|
|
|
226
216
|
def isExpr(node: ast.AST) -> TypeGuard[ast.Expr]:
|
|
227
217
|
return isinstance(node, ast.Expr)
|
|
228
218
|
@staticmethod
|
|
229
|
-
def isFunctionDef(node: ast.AST) -> TypeGuard[ast.FunctionDef]:
|
|
230
|
-
return isinstance(node, ast.FunctionDef)
|
|
219
|
+
def isFunctionDef(node: ast.AST) -> TypeGuard[ast.FunctionDef]: return isinstance(node, ast.FunctionDef)
|
|
231
220
|
@staticmethod
|
|
232
221
|
def isFunctionDef_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.FunctionDef] | bool]:
|
|
233
222
|
return lambda node: ifThis.isFunctionDef(node) and node.name == identifier
|
|
@@ -277,9 +266,9 @@ class ifThis:
|
|
|
277
266
|
Parameters:
|
|
278
267
|
identifier: The identifier to look for in the value chain
|
|
279
268
|
Returns:
|
|
280
|
-
|
|
269
|
+
workhorse: function that checks if a node matches the criteria
|
|
281
270
|
"""
|
|
282
|
-
def
|
|
271
|
+
def workhorse(node: ast.AST) -> TypeGuard[ast.Subscript]:
|
|
283
272
|
if not ifThis.isSubscript(node):
|
|
284
273
|
return False
|
|
285
274
|
def checkNodeDOTvalue(nodeDOTvalue: ast.AST) -> bool:
|
|
@@ -290,7 +279,7 @@ class ifThis:
|
|
|
290
279
|
return checkNodeDOTvalue(nodeDOTvalue.value) # type: ignore
|
|
291
280
|
return False
|
|
292
281
|
return checkNodeDOTvalue(node.value)
|
|
293
|
-
return
|
|
282
|
+
return workhorse
|
|
294
283
|
@staticmethod
|
|
295
284
|
def isSubscriptIsName_Identifier(identifier: ast_Identifier) -> Callable[[ast.AST], TypeGuard[ast.Subscript] | bool]:
|
|
296
285
|
return lambda node: ifThis.isSubscript(node) and ifThis.isName_Identifier(identifier)(node.value)
|
|
@@ -320,12 +309,12 @@ class ifThis:
|
|
|
320
309
|
@staticmethod
|
|
321
310
|
def matchesNoDescendant(predicate: Callable[[ast.AST], bool]) -> Callable[[ast.AST], bool]:
|
|
322
311
|
"""Create a predicate that returns True if no descendant of the node matches the given predicate."""
|
|
323
|
-
def
|
|
312
|
+
def workhorse(node: ast.AST) -> bool:
|
|
324
313
|
for descendant in ast.walk(node):
|
|
325
314
|
if descendant is not node and predicate(descendant):
|
|
326
315
|
return False
|
|
327
316
|
return True
|
|
328
|
-
return
|
|
317
|
+
return workhorse
|
|
329
318
|
@staticmethod
|
|
330
319
|
def onlyReturnAnyCompare(astFunctionDef: ast.AST) -> TypeGuard[ast.FunctionDef]:
|
|
331
320
|
return ifThis.isFunctionDef(astFunctionDef) and len(astFunctionDef.body) == 1 and ifThis.isReturnAnyCompare(astFunctionDef.body[0])
|
|
@@ -487,11 +476,15 @@ class Then:
|
|
|
487
476
|
def insertThisBelow(list_astAST: Sequence[ast.AST]) -> Callable[[ast.AST], Sequence[ast.AST]]:
|
|
488
477
|
return lambda belowMe: [belowMe, *list_astAST]
|
|
489
478
|
@staticmethod
|
|
490
|
-
def removeThis(_node: ast.AST) -> None:
|
|
491
|
-
|
|
479
|
+
def removeThis(_node: ast.AST) -> None: return None
|
|
480
|
+
@staticmethod
|
|
481
|
+
def replaceWith(astAST: ast.AST) -> Callable[[ast.AST], ast.AST]: return lambda _replaceMe: astAST
|
|
492
482
|
@staticmethod
|
|
493
|
-
def
|
|
494
|
-
|
|
483
|
+
def replaceDOTfuncWith(ast_expr: ast.expr) -> Callable[[ast.Call], ast.Call]:
|
|
484
|
+
def workhorse(node: ast.Call) -> ast.Call:
|
|
485
|
+
node.func = ast_expr
|
|
486
|
+
return node
|
|
487
|
+
return workhorse
|
|
495
488
|
@staticmethod
|
|
496
489
|
def updateThis(dictionaryOf_astMosDef: dict[ast_Identifier, astMosDef]) -> Callable[[astMosDef], astMosDef]:
|
|
497
490
|
return lambda node: dictionaryOf_astMosDef.setdefault(node.name, node)
|
|
@@ -563,25 +556,27 @@ class RecipeSynthesizeFlow:
|
|
|
563
556
|
"""Settings for synthesizing flow."""
|
|
564
557
|
# ========================================
|
|
565
558
|
# Source
|
|
566
|
-
sourceAlgorithm: ModuleType =
|
|
559
|
+
sourceAlgorithm: ModuleType = importlib_import_module(The.logicalPathModuleSourceAlgorithm)
|
|
567
560
|
sourcePython: str = inspect_getsource(sourceAlgorithm)
|
|
568
561
|
source_astModule: ast.Module = ast.parse(sourcePython)
|
|
569
562
|
|
|
570
563
|
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
571
|
-
sourceDispatcherCallable: str =
|
|
572
|
-
sourceInitializeCallable: str =
|
|
573
|
-
sourceParallelCallable: str =
|
|
574
|
-
sourceSequentialCallable: str =
|
|
575
|
-
|
|
576
|
-
sourceDataclassIdentifier: str =
|
|
577
|
-
sourceDataclassInstance: str =
|
|
578
|
-
sourceDataclassInstanceTaskDistribution: str =
|
|
579
|
-
sourcePathModuleDataclass: str =
|
|
580
|
-
|
|
564
|
+
sourceDispatcherCallable: str = The.dispatcherCallable
|
|
565
|
+
sourceInitializeCallable: str = The.sourceInitializeCallable
|
|
566
|
+
sourceParallelCallable: str = The.sourceParallelCallable
|
|
567
|
+
sourceSequentialCallable: str = The.sourceSequentialCallable
|
|
568
|
+
|
|
569
|
+
sourceDataclassIdentifier: str = The.dataclassIdentifier
|
|
570
|
+
sourceDataclassInstance: str = The.dataclassInstance
|
|
571
|
+
sourceDataclassInstanceTaskDistribution: str = The.dataclassInstanceTaskDistribution
|
|
572
|
+
sourcePathModuleDataclass: str = The.logicalPathModuleDataclass
|
|
573
|
+
|
|
574
|
+
sourceConcurrencyManagerNamespace = The.sourceConcurrencyManagerNamespace
|
|
575
|
+
sourceConcurrencyManagerIdentifier = The.sourceConcurrencyManagerIdentifier
|
|
581
576
|
# ========================================
|
|
582
577
|
# Filesystem
|
|
583
|
-
pathPackage: PurePosixPath | None = PurePosixPath(
|
|
584
|
-
fileExtension: str =
|
|
578
|
+
pathPackage: PurePosixPath | None = PurePosixPath(The.pathPackage)
|
|
579
|
+
fileExtension: str = The.fileExtension
|
|
585
580
|
|
|
586
581
|
# ========================================
|
|
587
582
|
# Logical identifiers
|
|
@@ -590,11 +585,11 @@ class RecipeSynthesizeFlow:
|
|
|
590
585
|
formatStrModuleForCallableSynthetic: str = theFormatStrModuleForCallableSynthetic
|
|
591
586
|
|
|
592
587
|
# Package
|
|
593
|
-
packageName: ast_Identifier | None =
|
|
588
|
+
packageName: ast_Identifier | None = The.packageName
|
|
594
589
|
|
|
595
590
|
# Module
|
|
596
591
|
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
597
|
-
Z0Z_flowLogicalPathRoot: str =
|
|
592
|
+
Z0Z_flowLogicalPathRoot: str | None = The.moduleOfSyntheticModules
|
|
598
593
|
moduleDispatcher: str = theModuleDispatcherSynthetic
|
|
599
594
|
logicalPathModuleDataclass: str = sourcePathModuleDataclass
|
|
600
595
|
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
@@ -606,6 +601,9 @@ class RecipeSynthesizeFlow:
|
|
|
606
601
|
initializeCallable: str = sourceInitializeCallable
|
|
607
602
|
parallelCallable: str = sourceParallelCallable
|
|
608
603
|
sequentialCallable: str = sourceSequentialCallable
|
|
604
|
+
# initializeCallable: str = 'StartTheCommotion'
|
|
605
|
+
# parallelCallable: str = sourceParallelCallable
|
|
606
|
+
# sequentialCallable: str = sourceSequentialCallable
|
|
609
607
|
|
|
610
608
|
dataclassIdentifier: str = sourceDataclassIdentifier
|
|
611
609
|
|
|
@@ -632,14 +630,14 @@ class RecipeSynthesizeFlow:
|
|
|
632
630
|
def pathFilenameDispatcher(self) -> PurePosixPath:
|
|
633
631
|
return self._makePathFilename(filenameStem=self.moduleDispatcher, logicalPathINFIX=self.Z0Z_flowLogicalPathRoot)
|
|
634
632
|
|
|
635
|
-
def extractClassDef(
|
|
633
|
+
def extractClassDef(module: ast.Module, identifier: ast_Identifier) -> ast.ClassDef | None:
|
|
636
634
|
sherpa: list[ast.ClassDef] = []
|
|
637
635
|
extractor = NodeCollector(ifThis.isClassDef_Identifier(identifier), [Then.appendTo(sherpa)])
|
|
638
636
|
extractor.visit(module)
|
|
639
637
|
astClassDef = sherpa[0] if sherpa else None
|
|
640
638
|
return astClassDef
|
|
641
639
|
|
|
642
|
-
def extractFunctionDef(
|
|
640
|
+
def extractFunctionDef(module: ast.Module, identifier: ast_Identifier) -> ast.FunctionDef | None:
|
|
643
641
|
sherpa: list[ast.FunctionDef] = []
|
|
644
642
|
extractor = NodeCollector(ifThis.isFunctionDef_Identifier(identifier), [Then.appendTo(sherpa)])
|
|
645
643
|
extractor.visit(module)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Everything in this directory is synthesized by other modules in the package."""
|
mapFolding/theSSOT.py
CHANGED
|
@@ -19,114 +19,85 @@ to avoid namespace collisions when transforming algorithms.
|
|
|
19
19
|
from collections.abc import Callable
|
|
20
20
|
from importlib import import_module as importlib_import_module
|
|
21
21
|
from inspect import getfile as inspect_getfile
|
|
22
|
-
from numpy import dtype, int64 as numpy_int64, int16 as numpy_int16, ndarray
|
|
22
|
+
from numpy import dtype, int64 as numpy_int64, int16 as numpy_int16, ndarray
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from sys import modules as sysModules
|
|
25
25
|
from tomli import load as tomli_load
|
|
26
26
|
from types import ModuleType
|
|
27
|
-
from typing import
|
|
27
|
+
from typing import TypeAlias
|
|
28
28
|
import dataclasses
|
|
29
29
|
|
|
30
|
-
"""
|
|
31
|
-
2025 March 11
|
|
32
|
-
Note to self: fundamental concept in Python:
|
|
33
|
-
Identifiers: scope and resolution, LEGB (Local, Enclosing, Global, Builtin)
|
|
34
|
-
- Local: Inside the function
|
|
35
|
-
- Enclosing: Inside enclosing functions
|
|
36
|
-
- Global: At the uppermost level
|
|
37
|
-
- Builtin: Python's built-in names
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
# I _think_, in theSSOT, I have abstracted the flow settings to only these couple of lines:
|
|
41
30
|
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
31
|
+
# I _think_, in theSSOT, I have abstracted the flow settings to only these couple of lines:
|
|
42
32
|
packageFlowSynthetic = 'numba'
|
|
43
33
|
# Z0Z_packageFlow = 'algorithm'
|
|
44
34
|
Z0Z_packageFlow = packageFlowSynthetic
|
|
45
35
|
Z0Z_concurrencyPackage = 'multiprocessing'
|
|
46
|
-
# =============================================================================
|
|
47
|
-
# The Wrong Way The Wrong Way The Wrong Way The Wrong Way The Wrong Way
|
|
48
|
-
# Evaluate When Packaging Evaluate When Packaging Evaluate When Packaging
|
|
49
|
-
|
|
50
|
-
sourceAlgorithmPACKAGING: str = 'theDao'
|
|
51
|
-
datatypePackagePACKAGING: Final[str] = 'numpy'
|
|
52
|
-
dispatcherCallablePACKAGING: str = 'doTheNeedful'
|
|
53
|
-
moduleOfSyntheticModulesPACKAGING: Final[str] = 'syntheticModules'
|
|
54
36
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
dataclassInstancePACKAGING: str = 'state'
|
|
58
|
-
dataclassInstanceTaskDistributionPACKAGING = dataclassInstancePACKAGING + 'Parallel'
|
|
59
|
-
|
|
60
|
-
sourceInitializeCallablePACKAGING = 'countInitialize'
|
|
61
|
-
sourceSequentialCallablePACKAGING = 'countSequential'
|
|
62
|
-
sourceParallelCallablePACKAGING = 'countParallel'
|
|
37
|
+
# =============================================================================
|
|
38
|
+
# The Wrong Way: Evaluate When Packaging
|
|
63
39
|
|
|
64
40
|
try:
|
|
65
|
-
|
|
41
|
+
packageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
|
|
66
42
|
except Exception:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# =============================================================================
|
|
70
|
-
# The Wrong Way The Wrong Way The Wrong Way The Wrong Way The Wrong Way
|
|
71
|
-
# Evaluate When Installing Evaluate When Installing Evaluate When Installing
|
|
43
|
+
packageNamePACKAGING = "mapFolding"
|
|
72
44
|
|
|
73
|
-
|
|
45
|
+
# The Wrong Way: Evaluate When Installing
|
|
74
46
|
|
|
75
47
|
def getPathPackageINSTALLING() -> Path:
|
|
76
|
-
pathPackage: Path = Path(inspect_getfile(importlib_import_module(
|
|
48
|
+
pathPackage: Path = Path(inspect_getfile(importlib_import_module(packageNamePACKAGING)))
|
|
77
49
|
if pathPackage.is_file():
|
|
78
50
|
pathPackage = pathPackage.parent
|
|
79
51
|
return pathPackage
|
|
80
52
|
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
53
|
+
# The following is an improvement, but it is not the full solution.
|
|
54
|
+
# I hope that the standardized markers, `metadata={'evaluateWhen': 'packaging'}` will help to automate
|
|
55
|
+
# whatever needs to happen so that the following is well implemented.
|
|
56
|
+
@dataclasses.dataclass(frozen=True)
|
|
57
|
+
class PackageSettings:
|
|
58
|
+
concurrencyPackage = Z0Z_concurrencyPackage
|
|
59
|
+
dataclassIdentifier: str = dataclasses.field(default='ComputationState', metadata={'evaluateWhen': 'packaging'})
|
|
60
|
+
dataclassInstance: str = dataclasses.field(default='state', metadata={'evaluateWhen': 'packaging'})
|
|
61
|
+
dataclassInstanceTaskDistributionSuffix: str = dataclasses.field(default='Parallel', metadata={'evaluateWhen': 'packaging'})
|
|
62
|
+
dataclassModule: str = dataclasses.field(default='theSSOT', metadata={'evaluateWhen': 'packaging'})
|
|
63
|
+
datatypePackage: str = dataclasses.field(default='numpy', metadata={'evaluateWhen': 'packaging'})
|
|
64
|
+
dispatcherCallable: str = dataclasses.field(default='doTheNeedful', metadata={'evaluateWhen': 'packaging'})
|
|
65
|
+
fileExtension: str = dataclasses.field(default='.py', metadata={'evaluateWhen': 'installing'})
|
|
66
|
+
moduleOfSyntheticModules: str = dataclasses.field(default='syntheticModules', metadata={'evaluateWhen': 'packaging'})
|
|
67
|
+
packageName: str = dataclasses.field(default = packageNamePACKAGING, metadata={'evaluateWhen': 'packaging'})
|
|
68
|
+
pathPackage: Path = dataclasses.field(default_factory=getPathPackageINSTALLING, init=False, metadata={'evaluateWhen': 'installing'})
|
|
69
|
+
sourceAlgorithm: str = dataclasses.field(default='theDao', metadata={'evaluateWhen': 'packaging'})
|
|
70
|
+
sourceConcurrencyManagerIdentifier: str = dataclasses.field(default='submit', metadata={'evaluateWhen': 'packaging'})
|
|
71
|
+
sourceConcurrencyManagerNamespace: str = dataclasses.field(default='concurrencyManager', metadata={'evaluateWhen': 'packaging'})
|
|
72
|
+
sourceInitializeCallable: str = dataclasses.field(default='countInitialize', metadata={'evaluateWhen': 'packaging'})
|
|
73
|
+
sourceParallelCallable: str = dataclasses.field(default='countParallel', metadata={'evaluateWhen': 'packaging'})
|
|
74
|
+
sourceSequentialCallable: str = dataclasses.field(default='countSequential', metadata={'evaluateWhen': 'packaging'})
|
|
75
|
+
|
|
76
|
+
@property # These are not fields, and that annoys me.
|
|
77
|
+
def dataclassInstanceTaskDistribution(self) -> str:
|
|
78
|
+
""" Compute the task distribution identifier by concatenating dataclassInstance and dataclassInstanceTaskDistributionSuffix. """
|
|
79
|
+
# it follows that `metadata={'evaluateWhen': 'packaging'}`
|
|
80
|
+
return self.dataclassInstance + self.dataclassInstanceTaskDistributionSuffix
|
|
81
|
+
|
|
82
|
+
@property # These are not fields, and that annoys me.
|
|
83
|
+
def logicalPathModuleSourceAlgorithm(self) -> str:
|
|
84
|
+
""" Compute the logical path module for the source algorithm by joining packageName and sourceAlgorithm. """
|
|
85
|
+
# it follows that `metadata={'evaluateWhen': 'packaging'}`
|
|
86
|
+
return '.'.join([self.packageName, self.sourceAlgorithm])
|
|
87
|
+
|
|
88
|
+
@property # These are not fields, and that annoys me.
|
|
89
|
+
def logicalPathModuleDataclass(self) -> str:
|
|
90
|
+
""" Compute the logical path module for the dataclass by joining packageName and dataclassModule. """
|
|
91
|
+
# it follows that `metadata={'evaluateWhen': 'packaging'}`
|
|
92
|
+
return '.'.join([self.packageName, self.dataclassModule])
|
|
93
|
+
|
|
94
|
+
The = PackageSettings()
|
|
113
95
|
|
|
114
96
|
# =============================================================================
|
|
115
|
-
|
|
116
|
-
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
117
|
-
concurrencyPackage: str = Z0Z_packageFlow
|
|
118
|
-
concurrencyPackage = Z0Z_concurrencyPackage
|
|
119
|
-
|
|
120
|
-
# =============================================================================
|
|
121
|
-
# The relatively flexible type system needs a different paradigm, but I don't
|
|
122
|
-
# know what it should be. The system needs to 1) help optimize computation, 2)
|
|
123
|
-
# make it possible to change the basic type of the package (e.g., from numpy
|
|
124
|
-
# to superTypePy), 3) make it possible to synthesize the optimized flow of used
|
|
125
|
-
# by the package, and 4) make it possible to synthesize arbitrary modules with
|
|
126
|
-
# different type systems.
|
|
97
|
+
# Flexible Data Structure System Needs Enhanced Paradigm https://github.com/hunterhogan/mapFolding/issues/9
|
|
127
98
|
|
|
128
99
|
DatatypeLeavesTotal: TypeAlias = int
|
|
129
|
-
# this would be uint8, but mapShape (2,2,2,2, 2,2,2,2) has 256 leaves, so generic containers accommodate
|
|
100
|
+
# this would be uint8, but mapShape (2,2,2,2, 2,2,2,2) has 256 leaves, so generic containers must accommodate at least 256 leaves
|
|
130
101
|
numpyLeavesTotal: TypeAlias = numpy_int16
|
|
131
102
|
|
|
132
103
|
DatatypeElephino: TypeAlias = int
|
|
@@ -134,18 +105,12 @@ numpyElephino: TypeAlias = numpy_int16
|
|
|
134
105
|
|
|
135
106
|
DatatypeFoldsTotal: TypeAlias = int
|
|
136
107
|
numpyFoldsTotal: TypeAlias = numpy_int64
|
|
137
|
-
numpyDtypeDefault = numpyFoldsTotal
|
|
138
108
|
|
|
139
109
|
Array3D: TypeAlias = ndarray[tuple[int, int, int], dtype[numpyLeavesTotal]]
|
|
140
110
|
Array1DLeavesTotal: TypeAlias = ndarray[tuple[int], dtype[numpyLeavesTotal]]
|
|
141
111
|
Array1DElephino: TypeAlias = ndarray[tuple[int], dtype[numpyElephino]]
|
|
142
112
|
Array1DFoldsTotal: TypeAlias = ndarray[tuple[int], dtype[numpyFoldsTotal]]
|
|
143
113
|
|
|
144
|
-
# =============================================================================
|
|
145
|
-
# The right way.
|
|
146
|
-
# (The dataclass, not the typing of the dataclass.)
|
|
147
|
-
# (Also, my noobplementation of the dataclass certainly needs improvement.)
|
|
148
|
-
|
|
149
114
|
@dataclasses.dataclass
|
|
150
115
|
class ComputationState:
|
|
151
116
|
mapShape: tuple[DatatypeLeavesTotal, ...]
|
|
@@ -191,9 +156,9 @@ class ComputationState:
|
|
|
191
156
|
leavesTotalAsInt = int(self.leavesTotal)
|
|
192
157
|
|
|
193
158
|
if self.countDimensionsGapped is None:
|
|
194
|
-
self.countDimensionsGapped = makeDataContainer(leavesTotalAsInt + 1,
|
|
159
|
+
self.countDimensionsGapped = makeDataContainer(leavesTotalAsInt + 1, numpyLeavesTotal)
|
|
195
160
|
if self.gapRangeStart is None:
|
|
196
|
-
self.gapRangeStart = makeDataContainer(leavesTotalAsInt + 1,
|
|
161
|
+
self.gapRangeStart = makeDataContainer(leavesTotalAsInt + 1, numpyElephino)
|
|
197
162
|
if self.gapsWhere is None:
|
|
198
163
|
self.gapsWhere = makeDataContainer(leavesTotalAsInt * leavesTotalAsInt + 1, numpyLeavesTotal)
|
|
199
164
|
if self.leafAbove is None:
|
|
@@ -205,75 +170,43 @@ class ComputationState:
|
|
|
205
170
|
self.foldsTotal = DatatypeFoldsTotal(self.foldGroups[0:-1].sum() * self.leavesTotal)
|
|
206
171
|
|
|
207
172
|
# =============================================================================
|
|
208
|
-
# The most right way I know how to implement.
|
|
209
|
-
|
|
210
|
-
theLogicalPathModuleSourceAlgorithm: str = '.'.join([thePackageName, theSourceAlgorithm])
|
|
211
|
-
theLogicalPathModuleDispatcher: str = theLogicalPathModuleSourceAlgorithm
|
|
212
|
-
theLogicalPathModuleDataclass: str = '.'.join([thePackageName, theDataclassModule])
|
|
213
|
-
|
|
214
|
-
def getSourceAlgorithm() -> ModuleType:
|
|
215
|
-
moduleImported: ModuleType = importlib_import_module(theLogicalPathModuleSourceAlgorithm)
|
|
216
|
-
return moduleImported
|
|
217
|
-
|
|
218
|
-
def getAlgorithmDispatcher() -> Callable[[ComputationState], ComputationState]:
|
|
219
|
-
moduleImported: ModuleType = getSourceAlgorithm()
|
|
220
|
-
dispatcherCallable = getattr(moduleImported, theDispatcherCallable)
|
|
221
|
-
return dispatcherCallable
|
|
222
|
-
|
|
223
|
-
def getPathSyntheticModules() -> Path:
|
|
224
|
-
return thePathPackage / theModuleOfSyntheticModules
|
|
225
173
|
|
|
226
174
|
# TODO learn how to see this from the user's perspective
|
|
227
175
|
def getPathJobRootDEFAULT() -> Path:
|
|
228
176
|
if 'google.colab' in sysModules:
|
|
229
177
|
pathJobDEFAULT: Path = Path("/content/drive/MyDrive") / "jobs"
|
|
230
178
|
else:
|
|
231
|
-
pathJobDEFAULT =
|
|
179
|
+
pathJobDEFAULT = The.pathPackage / "jobs"
|
|
232
180
|
return pathJobDEFAULT
|
|
233
181
|
|
|
234
|
-
_datatypePackage: str = ''
|
|
235
|
-
def getDatatypePackage() -> str:
|
|
236
|
-
global _datatypePackage
|
|
237
|
-
if not _datatypePackage:
|
|
238
|
-
_datatypePackage = theDatatypePackage
|
|
239
|
-
return _datatypePackage
|
|
240
|
-
|
|
241
|
-
def getNumpyDtypeDefault() -> type[signedinteger[Any]]:
|
|
242
|
-
return numpyDtypeDefault
|
|
243
|
-
|
|
244
182
|
# =============================================================================
|
|
245
183
|
# The coping way.
|
|
246
184
|
|
|
247
185
|
class raiseIfNoneGitHubIssueNumber3(Exception): pass
|
|
248
186
|
|
|
249
187
|
# =============================================================================
|
|
250
|
-
# Temporary or transient or something; probably still the wrong way
|
|
251
|
-
|
|
252
188
|
# THIS IS A STUPID SYSTEM BUT I CAN'T FIGURE OUT AN IMPROVEMENT
|
|
253
189
|
# NOTE This section for _default_ values probably has value
|
|
254
190
|
# https://github.com/hunterhogan/mapFolding/issues/4
|
|
255
191
|
theFormatStrModuleSynthetic = "{packageFlow}Count"
|
|
256
192
|
theFormatStrModuleForCallableSynthetic = theFormatStrModuleSynthetic + "_{callableTarget}"
|
|
257
193
|
|
|
258
|
-
|
|
259
|
-
theLogicalPathModuleDispatcherSynthetic: str = '.'.join([thePackageName, theModuleOfSyntheticModules, theModuleDispatcherSynthetic])
|
|
194
|
+
theLogicalPathModuleDispatcher: str = The.logicalPathModuleSourceAlgorithm
|
|
260
195
|
|
|
261
|
-
|
|
262
|
-
|
|
196
|
+
theModuleDispatcherSynthetic: str = theFormatStrModuleForCallableSynthetic.format(packageFlow=packageFlowSynthetic, callableTarget=The.dispatcherCallable)
|
|
197
|
+
theLogicalPathModuleDispatcherSynthetic: str = '.'.join([The.packageName, The.moduleOfSyntheticModules, theModuleDispatcherSynthetic])
|
|
263
198
|
|
|
264
|
-
# https://github.com/hunterhogan/mapFolding/issues/4
|
|
265
199
|
if Z0Z_packageFlow == packageFlowSynthetic: # pyright: ignore [reportUnnecessaryComparison]
|
|
266
200
|
# NOTE this as a default value _might_ have value
|
|
267
201
|
theLogicalPathModuleDispatcher = theLogicalPathModuleDispatcherSynthetic
|
|
268
202
|
|
|
269
|
-
# https://github.com/hunterhogan/mapFolding/issues/4
|
|
270
203
|
# dynamically set the return type https://github.com/hunterhogan/mapFolding/issues/5
|
|
271
204
|
def getPackageDispatcher() -> Callable[[ComputationState], ComputationState]:
|
|
272
205
|
# NOTE but this part, if the package flow is synthetic, probably needs to be delegated
|
|
273
206
|
# to the authority for creating _that_ synthetic flow.
|
|
274
207
|
|
|
275
208
|
moduleImported: ModuleType = importlib_import_module(theLogicalPathModuleDispatcher)
|
|
276
|
-
dispatcherCallable = getattr(moduleImported,
|
|
209
|
+
dispatcherCallable = getattr(moduleImported, The.dispatcherCallable)
|
|
277
210
|
return dispatcherCallable
|
|
278
211
|
|
|
279
212
|
"""Technical concepts I am likely using and likely want to use more effectively:
|
|
@@ -288,4 +221,13 @@ theSSOT and yourSSOT
|
|
|
288
221
|
----
|
|
289
222
|
delay realization/instantiation until a concrete value is desired
|
|
290
223
|
moment of truth: when the value is needed, not when the value is defined
|
|
224
|
+
|
|
225
|
+
----
|
|
226
|
+
2025 March 11
|
|
227
|
+
Note to self: fundamental concept in Python:
|
|
228
|
+
Identifiers: scope and resolution, LEGB (Local, Enclosing, Global, Builtin)
|
|
229
|
+
- Local: Inside the function
|
|
230
|
+
- Enclosing: Inside enclosing functions
|
|
231
|
+
- Global: At the uppermost level
|
|
232
|
+
- Builtin: Python's built-in names
|
|
291
233
|
"""
|