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.
Files changed (32) hide show
  1. mapFolding/__init__.py +5 -1
  2. mapFolding/basecamp.py +2 -2
  3. mapFolding/beDRY.py +24 -31
  4. mapFolding/oeis.py +2 -2
  5. mapFolding/reference/__init__.py +45 -0
  6. mapFolding/reference/flattened.py +20 -2
  7. mapFolding/reference/hunterNumba.py +24 -0
  8. mapFolding/reference/irvineJavaPort.py +12 -0
  9. mapFolding/reference/{jax.py → jaxCount.py} +46 -27
  10. mapFolding/reference/jobsCompleted/[2x19]/p2x19.py +197 -0
  11. mapFolding/reference/jobsCompleted/__init__.py +50 -0
  12. mapFolding/reference/jobsCompleted/p2x19/p2x19.py +29 -0
  13. mapFolding/reference/lunnanNumpy.py +16 -1
  14. mapFolding/reference/lunnanWhile.py +15 -1
  15. mapFolding/reference/rotatedEntryPoint.py +18 -0
  16. mapFolding/reference/total_countPlus1vsPlusN.py +226 -203
  17. mapFolding/someAssemblyRequired/getLLVMforNoReason.py +20 -1
  18. mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +52 -37
  19. mapFolding/someAssemblyRequired/transformDataStructures.py +11 -5
  20. mapFolding/someAssemblyRequired/transformationTools.py +40 -42
  21. mapFolding/syntheticModules/__init__.py +1 -0
  22. mapFolding/theSSOT.py +69 -127
  23. {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/METADATA +56 -31
  24. mapfolding-0.8.3.dist-info/RECORD +43 -0
  25. {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/WHEEL +1 -1
  26. tests/conftest.py +43 -33
  27. tests/test_computations.py +7 -7
  28. tests/test_other.py +5 -4
  29. mapfolding-0.8.1.dist-info/RECORD +0 -39
  30. {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/entry_points.txt +0 -0
  31. {mapfolding-0.8.1.dist-info → mapfolding-0.8.3.dist-info}/licenses/LICENSE +0 -0
  32. {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, getSourceAlgorithm
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
- module: ast.Module = ast.parse(inspect_getsource(import_module(logicalPathModule)))
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(dataclass_Identifier, module)
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 = getSourceAlgorithm()
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
- theDataclassIdentifier,
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
- return lambda node: ifThis.isCall(node) and ifThis.isName_Identifier(identifier)(node.func)
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
- predicate: function that checks if a node matches the criteria
269
+ workhorse: function that checks if a node matches the criteria
281
270
  """
282
- def predicate(node: ast.AST) -> TypeGuard[ast.Subscript]:
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 predicate
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 checkNoMatchingDescendant(node: ast.AST) -> bool:
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 checkNoMatchingDescendant
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
- return None
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 replaceWith(astAST: ast.AST) -> Callable[[ast.AST], ast.AST]:
494
- return lambda _replaceMe: astAST
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 = getSourceAlgorithm()
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 = theDispatcherCallable
572
- sourceInitializeCallable: str = theSourceInitializeCallable
573
- sourceParallelCallable: str = theSourceParallelCallable
574
- sourceSequentialCallable: str = theSourceSequentialCallable
575
-
576
- sourceDataclassIdentifier: str = theDataclassIdentifier
577
- sourceDataclassInstance: str = theDataclassInstance
578
- sourceDataclassInstanceTaskDistribution: str = theDataclassInstanceTaskDistribution
579
- sourcePathModuleDataclass: str = theLogicalPathModuleDataclass
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(thePathPackage)
584
- fileExtension: str = theFileExtension
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 = thePackageName
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 = theModuleOfSyntheticModules
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(identifier: ast_Identifier, module: ast.Module) -> ast.ClassDef | None:
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(identifier: ast_Identifier, module: ast.Module) -> ast.FunctionDef | None:
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, signedinteger
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 Any, Final, TypeAlias
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
- dataclassModulePACKAGING: str = 'theSSOT'
56
- dataclassIdentifierPACKAGING: str = 'ComputationState'
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
- thePackageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
41
+ packageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
66
42
  except Exception:
67
- thePackageNamePACKAGING = "mapFolding"
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
- fileExtensionINSTALLING: str = '.py'
45
+ # The Wrong Way: Evaluate When Installing
74
46
 
75
47
  def getPathPackageINSTALLING() -> Path:
76
- pathPackage: Path = Path(inspect_getfile(importlib_import_module(thePackageNamePACKAGING)))
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
- # The right way, perhaps.
83
-
84
- # Create enduring identifiers from the hopefully transient identifiers above.
85
- thePackageName: Final[str] = thePackageNamePACKAGING
86
- thePathPackage: Path = getPathPackageINSTALLING()
87
-
88
- """
89
- NOTE on semiotics: `theIdentifier` vs `identifier`
90
-
91
- - This package has a typical, "hardcoded" algorithm for counting map folds.
92
- - This package has logic for transforming that algorithm into other forms.
93
- - The transformation logic can transform other algorithms if 1) they are similar enough to the "hardcoded" algorithm and 2) I have written the transformation logic well enough to handle the differences.
94
- - To avoid confusion and namespace collisions, I differentiate between, for example, `theSourceAlgorithm` of the package and any other `sourceAlgorithm` being transformed by the package.
95
- """
96
-
97
- theSourceAlgorithm: str = sourceAlgorithmPACKAGING
98
- theSourceInitializeCallable = sourceInitializeCallablePACKAGING
99
- theSourceSequentialCallable = sourceSequentialCallablePACKAGING
100
- theSourceParallelCallable = sourceParallelCallablePACKAGING
101
- theDatatypePackage: Final[str] = datatypePackagePACKAGING
102
-
103
- theDispatcherCallable: str = dispatcherCallablePACKAGING
104
-
105
- theDataclassModule: str = dataclassModulePACKAGING
106
- theDataclassIdentifier: str = dataclassIdentifierPACKAGING
107
- theDataclassInstance: str = dataclassInstancePACKAGING
108
- theDataclassInstanceTaskDistribution: str = dataclassInstanceTaskDistributionPACKAGING
109
-
110
- theFileExtension: str = fileExtensionINSTALLING
111
-
112
- theModuleOfSyntheticModules: Final[str] = moduleOfSyntheticModulesPACKAGING
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, numpyElephino)
159
+ self.countDimensionsGapped = makeDataContainer(leavesTotalAsInt + 1, numpyLeavesTotal)
195
160
  if self.gapRangeStart is None:
196
- self.gapRangeStart = makeDataContainer(leavesTotalAsInt + 1, numpyLeavesTotal)
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 = thePathPackage / "jobs"
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
- theModuleDispatcherSynthetic: str = theFormatStrModuleForCallableSynthetic.format(packageFlow=packageFlowSynthetic, callableTarget=theDispatcherCallable)
259
- theLogicalPathModuleDispatcherSynthetic: str = '.'.join([thePackageName, theModuleOfSyntheticModules, theModuleDispatcherSynthetic])
194
+ theLogicalPathModuleDispatcher: str = The.logicalPathModuleSourceAlgorithm
260
195
 
261
- # =============================================================================
262
- # The most right way I know how to implement.
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, theDispatcherCallable)
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
  """