mapFolding 0.11.1__py3-none-any.whl → 0.11.2__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 (33) hide show
  1. mapFolding/__init__.py +18 -58
  2. mapFolding/basecamp.py +13 -10
  3. mapFolding/beDRY.py +113 -2
  4. mapFolding/dataBaskets.py +24 -2
  5. mapFolding/{toolboxFilesystem.py → filesystemToolkit.py} +3 -3
  6. mapFolding/infoBooth.py +96 -0
  7. mapFolding/oeis.py +3 -2
  8. mapFolding/someAssemblyRequired/RecipeJob.py +3 -4
  9. mapFolding/someAssemblyRequired/Z0Z_makeSomeModules.py +182 -17
  10. mapFolding/someAssemblyRequired/__init__.py +3 -3
  11. mapFolding/someAssemblyRequired/_toolIfThis.py +5 -5
  12. mapFolding/someAssemblyRequired/{_toolboxContainers.py → _toolkitContainers.py} +6 -7
  13. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +8 -7
  14. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +3 -2
  15. mapFolding/someAssemblyRequired/transformationTools.py +11 -10
  16. mapFolding/syntheticModules/countParallel.py +98 -0
  17. mapFolding/syntheticModules/dataPacking.py +1 -1
  18. mapFolding/syntheticModules/numbaCount.py +189 -188
  19. mapFolding/theDao.py +1 -1
  20. mapFolding/theSSOT.py +4 -243
  21. {mapfolding-0.11.1.dist-info → mapfolding-0.11.2.dist-info}/METADATA +16 -8
  22. mapfolding-0.11.2.dist-info/RECORD +56 -0
  23. {mapfolding-0.11.1.dist-info → mapfolding-0.11.2.dist-info}/WHEEL +1 -1
  24. tests/conftest.py +7 -9
  25. tests/test_computations.py +1 -1
  26. tests/test_filesystem.py +1 -2
  27. tests/test_other.py +1 -1
  28. tests/test_tasks.py +1 -3
  29. mapfolding-0.11.1.dist-info/RECORD +0 -54
  30. /mapFolding/someAssemblyRequired/{toolboxNumba.py → toolkitNumba.py} +0 -0
  31. {mapfolding-0.11.1.dist-info → mapfolding-0.11.2.dist-info}/entry_points.txt +0 -0
  32. {mapfolding-0.11.1.dist-info → mapfolding-0.11.2.dist-info}/licenses/LICENSE +0 -0
  33. {mapfolding-0.11.1.dist-info → mapfolding-0.11.2.dist-info}/top_level.txt +0 -0
mapFolding/__init__.py CHANGED
@@ -1,49 +1,3 @@
1
- """
2
- Map folding enumeration and counting algorithms with advanced optimization capabilities.
3
-
4
- This package implements algorithms to count and enumerate the distinct ways a rectangular map can be folded, based on
5
- the mathematical problem described in Lunnon's 1971 paper. It provides multiple layers of functionality, from high-level
6
- user interfaces to sophisticated algorithmic optimizations and code transformation tools.
7
-
8
- Core modules:
9
- - basecamp: Public API with simplified interfaces for end users
10
- - theDao: Core computational algorithm using a functional state-transformation approach
11
- - beDRY: Core utility functions implementing consistent data handling, validation, and resource management across the
12
- package's computational assembly-line
13
- - theSSOT: Single Source of Truth for configuration, types, and state management
14
- - toolboxFilesystem: Cross-platform file management services for storing and retrieving computation results with robust
15
- error handling and fallback mechanisms
16
- - oeis: Interface to the Online Encyclopedia of Integer Sequences for known results
17
-
18
- Extended functionality:
19
- - someAssemblyRequired: Code transformation framework that optimizes the core algorithm through AST manipulation,
20
- dataclass transformation, and compilation techniques
21
- - The system converts readable code into high-performance implementations through a systematic analysis and
22
- transformation assembly line
23
- - Provides tools to "shatter" complex dataclasses into primitive components, enabling compatibility with Numba and
24
- other optimization frameworks
25
- - Creates specialized implementations tailored for specific input parameters
26
-
27
- Testing and extension:
28
- - tests: Comprehensive test suite designed for both verification and extension
29
- - Provides fixtures and utilities that simplify testing of custom implementations
30
- - Enables users to validate their own recipes and job configurations with minimal code
31
- - Offers standardized testing patterns that maintain consistency across the codebase
32
- - See tests/__init__.py for detailed documentation on extending the test suite
33
-
34
- Special directories:
35
- - .cache/: Stores cached data from external sources like OEIS to improve performance
36
- - syntheticModules/: Contains dynamically generated, optimized implementations of the core algorithm created by the code
37
- transformation framework
38
- - reference/: Historical implementations and educational resources for algorithm exploration
39
- - reference/jobsCompleted/: Contains successful computations for previously unknown values, including first-ever
40
- calculations for 2x19 and 2x20 maps (OEIS A001415)
41
-
42
- This package balances algorithm readability and understandability with high-performance computation capabilities,
43
- allowing users to compute map folding totals for larger dimensions than previously feasible while also providing a
44
- foundation for exploring advanced code transformation techniques.
45
- """
46
-
47
1
  from typing import Any, TypeAlias
48
2
  import sys
49
3
 
@@ -76,8 +30,23 @@ from mapFolding.datatypes import (
76
30
  NumPyLeavesTotal as NumPyLeavesTotal,
77
31
  )
78
32
 
79
- from mapFolding.theSSOT import (
33
+ from mapFolding.theSSOT import PackageSettings as PackageSettings, packageSettings as packageSettings
34
+
35
+ from mapFolding.beDRY import (
80
36
  ComputationState as ComputationState,
37
+ getConnectionGraph as getConnectionGraph,
38
+ getLeavesTotal as getLeavesTotal,
39
+ getTaskDivisions as getTaskDivisions,
40
+ makeDataContainer as makeDataContainer,
41
+ outfitCountFolds as outfitCountFolds,
42
+ setProcessorLimit as setProcessorLimit,
43
+ validateListDimensions as validateListDimensions,
44
+ )
45
+
46
+ from mapFolding.dataBaskets import MapFoldingState as MapFoldingState
47
+
48
+ from mapFolding.infoBooth import (
49
+ PackageInformation as PackageInformation,
81
50
  raiseIfNoneGitHubIssueNumber3 as raiseIfNoneGitHubIssueNumber3,
82
51
  The as The,
83
52
  )
@@ -87,23 +56,14 @@ from mapFolding.theDao import (
87
56
  doTheNeedful as doTheNeedful,
88
57
  )
89
58
 
90
- from mapFolding.beDRY import (
91
- getLeavesTotal as getLeavesTotal,
92
- getTaskDivisions as getTaskDivisions,
93
- outfitCountFolds as outfitCountFolds,
94
- setProcessorLimit as setProcessorLimit,
95
- validateListDimensions as validateListDimensions,
96
- )
97
-
98
- from mapFolding.toolboxFilesystem import (
59
+ from mapFolding.filesystemToolkit import (
60
+ getFilenameFoldsTotal as getFilenameFoldsTotal,
99
61
  getPathFilenameFoldsTotal as getPathFilenameFoldsTotal,
100
62
  getPathRootJobDEFAULT as getPathRootJobDEFAULT,
101
63
  saveFoldsTotal as saveFoldsTotal,
102
64
  saveFoldsTotalFAILearly as saveFoldsTotalFAILearly,
103
65
  )
104
66
 
105
- from Z0Z_tools import writeStringToHere as writeStringToHere
106
-
107
67
  from mapFolding.basecamp import countFolds as countFolds
108
68
 
109
69
  from mapFolding.oeis import (
mapFolding/basecamp.py CHANGED
@@ -11,9 +11,7 @@ appropriate algorithm implementation, and optional persistence of results.
11
11
 
12
12
  from collections.abc import Sequence
13
13
  from mapFolding import (
14
- ComputationState,
15
14
  getPathFilenameFoldsTotal,
16
- outfitCountFolds,
17
15
  saveFoldsTotal,
18
16
  saveFoldsTotalFAILearly,
19
17
  setProcessorLimit,
@@ -163,20 +161,25 @@ def countFolds(listDimensions: Sequence[int] | None = None
163
161
  from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
164
162
  mapFoldingState = initializeGroupsOfFolds(mapFoldingState)
165
163
 
166
- from mapFolding.syntheticModules.dataPacking import doTheNeedful
167
- mapFoldingState = doTheNeedful(mapFoldingState)
164
+ from mapFolding.syntheticModules.dataPacking import sequential
165
+ mapFoldingState = sequential(mapFoldingState)
168
166
 
169
167
  foldsTotal = mapFoldingState.foldsTotal
170
168
 
171
- # NOTE treat this as a default?
172
- # flow based on `The` and `ComputationState` ====================================
169
+ elif taskDivisions > 1:
170
+ from mapFolding.dataBaskets import ParallelMapFoldingState
171
+ parallelMapFoldingState: ParallelMapFoldingState = ParallelMapFoldingState(mapShape, taskDivisions=taskDivisions)
172
+
173
+ from mapFolding.syntheticModules.countParallel import doTheNeedful
174
+ foldsTotal, listStatesParallel = doTheNeedful(parallelMapFoldingState, concurrencyLimit)
173
175
 
174
176
  else:
175
- computationStateInitialized: ComputationState = outfitCountFolds(mapShape, computationDivisions, concurrencyLimit)
176
- computationStateComplete: ComputationState = The.dispatcher(computationStateInitialized)
177
+ from mapFolding.dataBaskets import MapFoldingState
178
+ mapFoldingState: MapFoldingState = MapFoldingState(mapShape)
177
179
 
178
- computationStateComplete.getFoldsTotal()
179
- foldsTotal = computationStateComplete.foldsTotal
180
+ from mapFolding.syntheticModules.daoOfMapFolding import doTheNeedful
181
+ mapFoldingState = doTheNeedful(mapFoldingState)
182
+ foldsTotal = mapFoldingState.foldsTotal
180
183
 
181
184
  # Follow memorialization instructions ===========================================
182
185
 
mapFolding/beDRY.py CHANGED
@@ -18,12 +18,13 @@ These utilities form a stable internal API that other modules depend on, particu
18
18
  theDao (core algorithm), and the synthetic module generators that produce optimized implementations.
19
19
  """
20
20
  from collections.abc import Sequence
21
- from mapFolding import ComputationState, NumPyIntegerType
21
+ from mapFolding import Array1DElephino, Array1DFoldsTotal, Array1DLeavesTotal, Array3D, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal, NumPyIntegerType
22
22
  from numpy import dtype as numpy_dtype, int64 as numpy_int64, ndarray
23
23
  from sys import maxsize as sysMaxsize
24
24
  from typing import Any
25
25
  from Z0Z_tools import defineConcurrencyLimit, intInnit, oopsieKwargsie
26
26
  import numpy
27
+ import dataclasses
27
28
 
28
29
  def getLeavesTotal(mapShape: tuple[int, ...]) -> int:
29
30
  """
@@ -59,7 +60,6 @@ def getTaskDivisions(computationDivisions: int | str | None, concurrencyLimit: i
59
60
  """
60
61
  Determines whether to divide the computation into tasks and how many divisions.
61
62
 
62
-
63
63
  Parameters
64
64
  ----------
65
65
  computationDivisions: None
@@ -208,6 +208,117 @@ def makeDataContainer(shape: int | tuple[int, ...], datatype: type[NumPyIntegerT
208
208
  """
209
209
  return numpy.zeros(shape, dtype=datatype)
210
210
 
211
+
212
+ @dataclasses.dataclass
213
+ class ComputationState:
214
+ """
215
+ Represents the complete state of a map folding computation.
216
+
217
+ This dataclass encapsulates all the information required to compute the number of possible ways to fold a map,
218
+ including the map dimensions, leaf connections, computation progress, and fold counting. It serves as the central
219
+ data structure that flows through the entire computational algorithm.
220
+
221
+ Fields are categorized into:
222
+ 1. Input parameters (`mapShape`, `leavesTotal`, etc.).
223
+ 2. Core computational structures (`connectionGraph`, etc.).
224
+ 3. Tracking variables for the folding algorithm state.
225
+ 4. Result accumulation fields (`foldsTotal`, `groupsOfFolds`).
226
+ """
227
+ # NOTE Python is anti-DRY, again, `DatatypeLeavesTotal` metadata needs to match the type
228
+ mapShape: tuple[DatatypeLeavesTotal, ...] = dataclasses.field(init=True, metadata={'elementConstructor': 'DatatypeLeavesTotal'})
229
+ """Dimensions of the map to be folded, as a tuple of integers."""
230
+
231
+ leavesTotal: DatatypeLeavesTotal
232
+ """Total number of leaves (unit squares) in the map, equal to the product of all dimensions."""
233
+
234
+ taskDivisions: DatatypeLeavesTotal
235
+ """Number of parallel tasks to divide the computation into. Zero means sequential computation."""
236
+
237
+ concurrencyLimit: DatatypeElephino
238
+ """Maximum number of concurrent processes to use during computation."""
239
+
240
+ connectionGraph: Array3D = dataclasses.field(init=False, metadata={'dtype': Array3D.__args__[1].__args__[0]}) # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
241
+ """3D array encoding the connections between leaves in all dimensions."""
242
+
243
+ dimensionsTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
244
+ """Total number of dimensions in the map shape."""
245
+
246
+ # I am using `dataclasses.field` metadata and `typeAlias.__args__[1].__args__[0]` to make the code more DRY. https://github.com/hunterhogan/mapFolding/issues/9
247
+ countDimensionsGapped: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
248
+ """Tracks how many dimensions are gapped for each leaf."""
249
+
250
+ dimensionsUnconstrained: DatatypeLeavesTotal = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
251
+ """Number of dimensions that are not constrained in the current folding state."""
252
+
253
+ gapRangeStart: Array1DElephino = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DElephino.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
254
+ """Starting index for the gap range for each leaf."""
255
+
256
+ gapsWhere: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
257
+ """Tracks where gaps occur in the folding pattern."""
258
+
259
+ leafAbove: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
260
+ """For each leaf, stores the index of the leaf above it in the folding pattern."""
261
+
262
+ leafBelow: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
263
+ """For each leaf, stores the index of the leaf below it in the folding pattern."""
264
+
265
+ foldGroups: Array1DFoldsTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DFoldsTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
266
+ """Accumulator for fold groups across parallel tasks."""
267
+
268
+ foldsTotal: DatatypeFoldsTotal = DatatypeFoldsTotal(0)
269
+ """The final computed total number of distinct folding patterns."""
270
+
271
+ gap1ndex: DatatypeElephino = DatatypeElephino(0)
272
+ """Current index into gaps array during algorithm execution."""
273
+
274
+ gap1ndexCeiling: DatatypeElephino = DatatypeElephino(0)
275
+ """Upper limit for gap index during the current algorithm phase."""
276
+
277
+ groupsOfFolds: DatatypeFoldsTotal = dataclasses.field(default=DatatypeFoldsTotal(0), metadata={'theCountingIdentifier': True})
278
+ """Accumulator for the number of fold groups found during computation."""
279
+
280
+ indexDimension: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
281
+ """Current dimension being processed during algorithm execution."""
282
+
283
+ indexLeaf: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
284
+ """Current leaf index during iteration."""
285
+
286
+ indexMiniGap: DatatypeElephino = DatatypeElephino(0)
287
+ """Index used when filtering common gaps."""
288
+
289
+ leaf1ndex: DatatypeLeavesTotal = DatatypeLeavesTotal(1)
290
+ """Active leaf being processed in the folding algorithm. Starts at 1, not 0."""
291
+
292
+ leafConnectee: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
293
+ """Leaf that is being connected to the active leaf."""
294
+
295
+ taskIndex: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
296
+ """Index of the current parallel task when using task divisions."""
297
+
298
+ def __post_init__(self) -> None:
299
+ from mapFolding.beDRY import getConnectionGraph, makeDataContainer
300
+ self.dimensionsTotal = DatatypeLeavesTotal(len(self.mapShape))
301
+ leavesTotalAsInt = int(self.leavesTotal)
302
+ self.connectionGraph = getConnectionGraph(self.mapShape, leavesTotalAsInt, self.__dataclass_fields__['connectionGraph'].metadata['dtype'])
303
+
304
+ if self.dimensionsUnconstrained is None: self.dimensionsUnconstrained = DatatypeLeavesTotal(int(self.dimensionsTotal)) # pyright: ignore[reportUnnecessaryComparison]
305
+
306
+ if self.foldGroups is None: # pyright: ignore[reportUnnecessaryComparison]
307
+ self.foldGroups = makeDataContainer(max(2, int(self.taskDivisions) + 1), self.__dataclass_fields__['foldGroups'].metadata['dtype'])
308
+ self.foldGroups[-1] = self.leavesTotal
309
+
310
+ # Dataclasses, Default factories, and arguments in `ComputationState` https://github.com/hunterhogan/mapFolding/issues/12
311
+ if self.gapsWhere is None: self.gapsWhere = makeDataContainer(leavesTotalAsInt * leavesTotalAsInt + 1, self.__dataclass_fields__['gapsWhere'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
312
+
313
+ if self.countDimensionsGapped is None: self.countDimensionsGapped = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['countDimensionsGapped'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
314
+ if self.gapRangeStart is None: self.gapRangeStart = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['gapRangeStart'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
315
+ if self.leafAbove is None: self.leafAbove = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['leafAbove'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
316
+ if self.leafBelow is None: self.leafBelow = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['leafBelow'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
317
+
318
+ # Automatic, or not, calculation in dataclass `ComputationState` https://github.com/hunterhogan/mapFolding/issues/14
319
+ def getFoldsTotal(self) -> None:
320
+ self.foldsTotal = DatatypeFoldsTotal(self.foldGroups[0:-1].sum() * self.leavesTotal)
321
+
211
322
  def outfitCountFolds(mapShape: tuple[int, ...], computationDivisions: int | str | None = None, concurrencyLimit: int = 1) -> ComputationState:
212
323
  """
213
324
  Initialize a `ComputationState` with validated parameters for map folding calculation.
mapFolding/dataBaskets.py CHANGED
@@ -1,5 +1,14 @@
1
- from mapFolding.beDRY import getConnectionGraph, getLeavesTotal, makeDataContainer
2
- from mapFolding.datatypes import Array3D, Array1DElephino, Array1DLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal
1
+ from mapFolding import (
2
+ Array1DElephino,
3
+ Array1DLeavesTotal,
4
+ Array3D,
5
+ DatatypeElephino,
6
+ DatatypeFoldsTotal,
7
+ DatatypeLeavesTotal,
8
+ getConnectionGraph,
9
+ getLeavesTotal,
10
+ makeDataContainer,
11
+ )
3
12
  import dataclasses
4
13
 
5
14
  @dataclasses.dataclass
@@ -48,6 +57,19 @@ class MapFoldingState:
48
57
  if self.leafAbove is None: self.leafAbove = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['leafAbove'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
49
58
  if self.leafBelow is None: self.leafBelow = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['leafBelow'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
50
59
 
60
+ @dataclasses.dataclass
61
+ class ParallelMapFoldingState(MapFoldingState):
62
+ taskDivisions: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
63
+ """Number of tasks into which to divide the computation. If the value is greater than `leavesTotal`, the computation will be wrong. Default is `leavesTotal`."""
64
+
65
+ taskIndex: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
66
+ """Index of the current task when using task divisions."""
67
+
68
+ def __post_init__(self) -> None:
69
+ super().__post_init__()
70
+ if self.taskDivisions == 0:
71
+ self.taskDivisions = DatatypeLeavesTotal(int(self.leavesTotal))
72
+
51
73
  @dataclasses.dataclass
52
74
  class LeafSequenceState(MapFoldingState):
53
75
  leafSequence: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
@@ -21,7 +21,7 @@ The functions here adhere to a consistent approach to path handling:
21
21
  - Progressive fallback strategies for saving critical computation results.
22
22
  - Preemptive filesystem validation to detect issues before computation begins.
23
23
  """
24
- from mapFolding import The
24
+ from mapFolding import packageSettings
25
25
  from os import PathLike
26
26
  from pathlib import Path, PurePath
27
27
  from sys import modules as sysModules
@@ -101,9 +101,9 @@ def getPathRootJobDEFAULT() -> Path:
101
101
  - For Google Colab, uses a specific path in Google Drive.
102
102
  - Creates the directory if it doesn't exist.
103
103
  """
104
- pathJobDEFAULT = Path(platformdirs.user_data_dir(appname=The.packageName, appauthor=False, ensure_exists=True))
104
+ pathJobDEFAULT = Path(platformdirs.user_data_dir(appname=packageSettings.packageName, appauthor=False, ensure_exists=True))
105
105
  if 'google.colab' in sysModules:
106
- pathJobDEFAULT = Path("/content/drive/MyDrive") / The.packageName
106
+ pathJobDEFAULT = Path("/content/drive/MyDrive") / packageSettings.packageName
107
107
  pathJobDEFAULT.mkdir(parents=True, exist_ok=True)
108
108
  return pathJobDEFAULT
109
109
 
@@ -0,0 +1,96 @@
1
+ from collections.abc import Callable
2
+ from importlib import import_module as importlib_import_module
3
+ from mapFolding import ComputationState, PackageSettings
4
+ from types import ModuleType
5
+ import dataclasses
6
+
7
+ @dataclasses.dataclass
8
+ 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
19
+ """Name of the function within the dispatcher module that will be called."""
20
+
21
+ concurrencyPackage: str | None = None
22
+ """Package to use for concurrent execution (e.g., 'multiprocessing', 'numba')."""
23
+
24
+ # "Evaluate When Packaging" and "Evaluate When Installing" https://github.com/hunterhogan/mapFolding/issues/18
25
+ dataclassIdentifier: str = dataclasses.field(default='ComputationState', metadata={'evaluateWhen': 'packaging'})
26
+ """Name of the dataclass used to track computation state."""
27
+
28
+ dataclassInstance: str = dataclasses.field(default='state', metadata={'evaluateWhen': 'packaging'})
29
+ """Default variable name for instances of the computation state dataclass."""
30
+
31
+ dataclassInstanceTaskDistributionSuffix: str = dataclasses.field(default='Parallel', metadata={'evaluateWhen': 'packaging'})
32
+ """Suffix added to dataclassInstance for parallel task distribution."""
33
+
34
+ dataclassModule: str = dataclasses.field(default='beDRY', metadata={'evaluateWhen': 'packaging'})
35
+ """Module containing the computation state dataclass definition."""
36
+
37
+ datatypePackage: str = dataclasses.field(default='numpy', metadata={'evaluateWhen': 'packaging'})
38
+ """Package providing the numeric data types used in computation."""
39
+
40
+ sourceAlgorithm: str = dataclasses.field(default='theDao', metadata={'evaluateWhen': 'packaging'})
41
+ """Module containing the reference implementation of the algorithm."""
42
+
43
+ sourceCallableDispatcher: str = dataclasses.field(default='doTheNeedful', metadata={'evaluateWhen': 'packaging'})
44
+ """Name of the function that dispatches computation in the source algorithm."""
45
+
46
+ sourceCallableInitialize: str = dataclasses.field(default='countInitialize', metadata={'evaluateWhen': 'packaging'})
47
+ """Name of the function that initializes computation in the source algorithm."""
48
+
49
+ sourceCallableParallel: str = dataclasses.field(default='countParallel', metadata={'evaluateWhen': 'packaging'})
50
+ """Name of the function that performs parallel computation in the source algorithm."""
51
+
52
+ sourceCallableSequential: str = dataclasses.field(default='countSequential', metadata={'evaluateWhen': 'packaging'})
53
+ """Name of the function that performs sequential computation in the source algorithm."""
54
+
55
+ sourceConcurrencyManagerIdentifier: str = dataclasses.field(default='submit', metadata={'evaluateWhen': 'packaging'})
56
+ """Method name used to submit tasks to the concurrency manager."""
57
+
58
+ sourceConcurrencyManagerNamespace: str = dataclasses.field(default='concurrencyManager', metadata={'evaluateWhen': 'packaging'})
59
+ """Variable name used for the concurrency manager instance."""
60
+
61
+ sourceConcurrencyPackage: str = dataclasses.field(default='multiprocessing', metadata={'evaluateWhen': 'packaging'})
62
+ """Default package used for concurrency in the source algorithm."""
63
+
64
+ dataclassInstanceTaskDistribution: str = dataclasses.field(default=None, metadata={'evaluateWhen': 'packaging'}) # pyright: ignore[reportAssignmentType]
65
+ """Variable name for the parallel distribution instance of the computation state."""
66
+
67
+ logicalPathModuleDataclass: str = dataclasses.field(default=None, metadata={'evaluateWhen': 'packaging'}) # pyright: ignore[reportAssignmentType]
68
+ """Fully qualified import path to the module containing the computation state dataclass."""
69
+
70
+ logicalPathModuleSourceAlgorithm: str = dataclasses.field(default=None, metadata={'evaluateWhen': 'packaging'}) # pyright: ignore[reportAssignmentType]
71
+ """Fully qualified import path to the module containing the source algorithm."""
72
+
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
+ def __post_init__(self) -> None:
82
+ if self.dataclassInstanceTaskDistribution is None: # pyright: ignore[reportUnnecessaryComparison]
83
+ self.dataclassInstanceTaskDistribution = self.dataclassInstance + self.dataclassInstanceTaskDistributionSuffix
84
+
85
+ if self.logicalPathModuleDataclass is None: # pyright: ignore[reportUnnecessaryComparison]
86
+ self.logicalPathModuleDataclass = '.'.join([self.packageName, self.dataclassModule])
87
+ if self.logicalPathModuleSourceAlgorithm is None: # pyright: ignore[reportUnnecessaryComparison]
88
+ self.logicalPathModuleSourceAlgorithm = '.'.join([self.packageName, self.sourceAlgorithm])
89
+
90
+ class raiseIfNoneGitHubIssueNumber3(Exception): pass
91
+
92
+ logicalPathModuleDispatcherHARDCODED: str = 'mapFolding.syntheticModules.numbaCount'
93
+ callableDispatcherHARDCODED: str = 'doTheNeedful'
94
+ concurrencyPackageHARDCODED = 'multiprocessing'
95
+
96
+ The = PackageInformation(logicalPathModuleDispatcher=logicalPathModuleDispatcherHARDCODED, callableDispatcher=callableDispatcherHARDCODED, concurrencyPackage=concurrencyPackageHARDCODED)
mapFolding/oeis.py CHANGED
@@ -20,9 +20,10 @@ mathematical definition in OEIS and the computational implementation in the pack
20
20
  from collections.abc import Callable
21
21
  from datetime import datetime, timedelta
22
22
  from functools import cache
23
- from mapFolding import countFolds, The, TypedDict, writeStringToHere
23
+ from mapFolding import countFolds, packageSettings, TypedDict
24
24
  from pathlib import Path
25
25
  from typing import Any, Final
26
+ from Z0Z_tools import writeStringToHere
26
27
  import argparse
27
28
  import random
28
29
  import sys
@@ -33,7 +34,7 @@ import warnings
33
34
 
34
35
  cacheDays = 30
35
36
 
36
- pathCache: Path = The.pathPackage / ".cache"
37
+ pathCache: Path = packageSettings.pathPackage / ".cache"
37
38
 
38
39
  class SettingsOEIS(TypedDict):
39
40
  description: str
@@ -1,9 +1,8 @@
1
+ from mapFolding import ComputationState, getPathFilenameFoldsTotal, getPathRootJobDEFAULT, MapFoldingState
2
+ from mapFolding import DatatypeElephino as TheDatatypeElephino, DatatypeFoldsTotal as TheDatatypeFoldsTotal, DatatypeLeavesTotal as TheDatatypeLeavesTotal
1
3
  from mapFolding.someAssemblyRequired import ShatteredDataclass, ast_Identifier, parseLogicalPath2astModule, parsePathFilename2astModule, str_nameDOTname
2
- from mapFolding.someAssemblyRequired.toolboxNumba import theNumbaFlow
4
+ from mapFolding.someAssemblyRequired.toolkitNumba import theNumbaFlow
3
5
  from mapFolding.someAssemblyRequired.transformationTools import shatter_dataclassesDOTdataclass
4
- from mapFolding.theSSOT import ComputationState, DatatypeElephino as TheDatatypeElephino, DatatypeFoldsTotal as TheDatatypeFoldsTotal, DatatypeLeavesTotal as TheDatatypeLeavesTotal
5
- from mapFolding.toolboxFilesystem import getPathFilenameFoldsTotal, getPathRootJobDEFAULT
6
- from mapFolding.dataBaskets import MapFoldingState
7
6
  from pathlib import Path, PurePosixPath
8
7
  from typing import TypeAlias
9
8
  import dataclasses