mapFolding 0.9.2__py3-none-any.whl → 0.9.4__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 (36) hide show
  1. mapFolding/Z0Z_flowControl.py +117 -0
  2. mapFolding/__init__.py +28 -26
  3. mapFolding/basecamp.py +1 -1
  4. mapFolding/beDRY.py +1 -2
  5. mapFolding/daoOfMapFolding.py +142 -0
  6. mapFolding/dataBaskets.py +49 -0
  7. mapFolding/datatypes.py +21 -0
  8. mapFolding/oeis.py +1 -2
  9. mapFolding/someAssemblyRequired/Z0Z_makeSomeModules.py +226 -0
  10. mapFolding/someAssemblyRequired/__init__.py +12 -2
  11. mapFolding/someAssemblyRequired/_theTypes.py +11 -5
  12. mapFolding/someAssemblyRequired/_tool_Make.py +8 -0
  13. mapFolding/someAssemblyRequired/_tool_Then.py +44 -1
  14. mapFolding/someAssemblyRequired/_toolboxAST.py +57 -0
  15. mapFolding/someAssemblyRequired/_toolboxAntecedents.py +95 -29
  16. mapFolding/someAssemblyRequired/_toolboxContainers.py +59 -53
  17. mapFolding/someAssemblyRequired/_toolboxPython.py +52 -50
  18. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +10 -9
  19. mapFolding/someAssemblyRequired/toolboxNumba.py +1 -1
  20. mapFolding/someAssemblyRequired/transformationTools.py +40 -58
  21. mapFolding/syntheticModules/dataPacking.py +25 -0
  22. mapFolding/syntheticModules/initializeCount.py +49 -0
  23. mapFolding/syntheticModules/theorem2.py +49 -0
  24. mapFolding/syntheticModules/theorem2Numba.py +51 -0
  25. mapFolding/theSSOT.py +13 -21
  26. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/METADATA +4 -3
  27. mapfolding-0.9.4.dist-info/RECORD +57 -0
  28. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/WHEEL +1 -1
  29. tests/__init__.py +2 -2
  30. tests/conftest.py +7 -7
  31. tests/test_computations.py +17 -13
  32. tests/test_tasks.py +2 -2
  33. mapfolding-0.9.2.dist-info/RECORD +0 -47
  34. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/entry_points.txt +0 -0
  35. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/licenses/LICENSE +0 -0
  36. {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,117 @@
1
+ from collections.abc import Sequence
2
+ from mapFolding import (
3
+ ComputationState,
4
+ getPathFilenameFoldsTotal,
5
+ outfitCountFolds,
6
+ saveFoldsTotal,
7
+ saveFoldsTotalFAILearly,
8
+ setProcessorLimit,
9
+ The,
10
+ validateListDimensions,
11
+ )
12
+ from os import PathLike
13
+ from pathlib import PurePath
14
+
15
+ def countFolds(listDimensions: Sequence[int] | None = None
16
+ , pathLikeWriteFoldsTotal: PathLike[str] | PurePath | None = None
17
+ , computationDivisions: int | str | None = None
18
+ , CPUlimit: int | float | bool | None = None
19
+ # , * I need to improve `standardizedEqualToCallableReturn` so it will work with keyword arguments
20
+ , mapShape: tuple[int, ...] | None = None
21
+ , oeisID: str | None = None
22
+ , oeis_n: int | None = None
23
+ , flow: str | None = None
24
+ ) -> int:
25
+
26
+ # mapShape =====================================================================
27
+
28
+ if mapShape:
29
+ pass
30
+ else:
31
+ if oeisID and oeis_n:
32
+ from mapFolding.oeis import settingsOEIS
33
+ try:
34
+ mapShape = settingsOEIS[oeisID]['getMapShape'](oeis_n)
35
+ except KeyError:
36
+ pass
37
+ if not mapShape and listDimensions:
38
+ mapShape = validateListDimensions(listDimensions)
39
+
40
+ if mapShape is None:
41
+ raise ValueError(f"""I received these values:
42
+ `{listDimensions = }`,
43
+ `{mapShape = }`,
44
+ `{oeisID = }` and `{oeis_n = }`,
45
+ but I was unable to select a map for which to count the folds.""")
46
+
47
+ # task division instructions ===============================================
48
+
49
+ if computationDivisions:
50
+ # NOTE `The.concurrencyPackage`
51
+ concurrencyLimit: int = setProcessorLimit(CPUlimit, The.concurrencyPackage)
52
+ from mapFolding.beDRY import getLeavesTotal, getTaskDivisions
53
+ leavesTotal: int = getLeavesTotal(mapShape)
54
+ taskDivisions = getTaskDivisions(computationDivisions, concurrencyLimit, leavesTotal)
55
+ del leavesTotal
56
+ else:
57
+ concurrencyLimit = 1
58
+ taskDivisions = 0
59
+
60
+ # memorialization instructions ===========================================
61
+
62
+ if pathLikeWriteFoldsTotal is not None:
63
+ pathFilenameFoldsTotal = getPathFilenameFoldsTotal(mapShape, pathLikeWriteFoldsTotal)
64
+ saveFoldsTotalFAILearly(pathFilenameFoldsTotal)
65
+ else:
66
+ pathFilenameFoldsTotal = None
67
+
68
+ # Flow control until I can figure out a good way ===============================
69
+
70
+ if flow == 'daoOfMapFolding':
71
+ from mapFolding.dataBaskets import MapFoldingState
72
+ mapFoldingState: MapFoldingState = MapFoldingState(mapShape)
73
+
74
+ from mapFolding.daoOfMapFolding import doTheNeedful
75
+ mapFoldingState = doTheNeedful(mapFoldingState)
76
+ foldsTotal = mapFoldingState.foldsTotal
77
+
78
+ elif flow == 'theorem2' and any((dimension > 2 for dimension in mapShape)):
79
+ from mapFolding.dataBaskets import MapFoldingState
80
+ mapFoldingState: MapFoldingState = MapFoldingState(mapShape)
81
+
82
+ from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
83
+ mapFoldingState = initializeGroupsOfFolds(mapFoldingState)
84
+
85
+ from mapFolding.syntheticModules.theorem2 import count
86
+ mapFoldingState = count(mapFoldingState)
87
+
88
+ foldsTotal = mapFoldingState.foldsTotal
89
+
90
+ elif (flow == 'theorem2Numba' or taskDivisions == 0) and any((dimension > 2 for dimension in mapShape)):
91
+ from mapFolding.dataBaskets import MapFoldingState
92
+ mapFoldingState: MapFoldingState = MapFoldingState(mapShape)
93
+
94
+ from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
95
+ mapFoldingState = initializeGroupsOfFolds(mapFoldingState)
96
+
97
+ from mapFolding.syntheticModules.dataPacking import doTheNeedful
98
+ mapFoldingState = doTheNeedful(mapFoldingState)
99
+
100
+ foldsTotal = mapFoldingState.foldsTotal
101
+
102
+ # NOTE treat this as a default?
103
+ # flow based on `The` and `ComputationState` ====================================
104
+
105
+ else:
106
+ computationStateInitialized: ComputationState = outfitCountFolds(mapShape, computationDivisions, concurrencyLimit)
107
+ computationStateComplete: ComputationState = The.dispatcher(computationStateInitialized)
108
+
109
+ computationStateComplete.getFoldsTotal()
110
+ foldsTotal = computationStateComplete.foldsTotal
111
+
112
+ # Follow memorialization instructions ===========================================
113
+
114
+ if pathFilenameFoldsTotal is not None:
115
+ saveFoldsTotal(pathFilenameFoldsTotal, foldsTotal)
116
+
117
+ return foldsTotal
mapFolding/__init__.py CHANGED
@@ -1,29 +1,27 @@
1
1
  """
2
2
  Map folding enumeration and counting algorithms with advanced optimization capabilities.
3
3
 
4
- This package implements algorithms to count and enumerate the distinct ways
5
- a rectangular map can be folded, based on the mathematical problem described
6
- in Lunnon's 1971 paper. It provides multiple layers of functionality, from
7
- high-level user interfaces to sophisticated algorithmic optimizations and code
8
- transformation tools.
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.
9
7
 
10
8
  Core modules:
11
9
  - basecamp: Public API with simplified interfaces for end users
12
10
  - theDao: Core computational algorithm using a functional state-transformation approach
13
- - beDRY: Core utility functions implementing consistent data handling, validation, and
14
- resource management across the package's computational assembly-line
11
+ - beDRY: Core utility functions implementing consistent data handling, validation, and resource management across the
12
+ package's computational assembly-line
15
13
  - theSSOT: Single Source of Truth for configuration, types, and state management
16
- - toolboxFilesystem: Cross-platform file management services for storing and retrieving
17
- computation results with robust error handling and fallback mechanisms
14
+ - toolboxFilesystem: Cross-platform file management services for storing and retrieving computation results with robust
15
+ error handling and fallback mechanisms
18
16
  - oeis: Interface to the Online Encyclopedia of Integer Sequences for known results
19
17
 
20
18
  Extended functionality:
21
- - someAssemblyRequired: Code transformation framework that optimizes the core algorithm
22
- through AST manipulation, dataclass transformation, and compilation techniques
23
- - The system converts readable code into high-performance implementations through
24
- a systematic analysis and transformation pipeline
25
- - Provides tools to "shatter" complex dataclasses into primitive components,
26
- enabling compatibility with Numba and other optimization frameworks
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
27
25
  - Creates specialized implementations tailored for specific input parameters
28
26
 
29
27
  Testing and extension:
@@ -35,24 +33,22 @@ Testing and extension:
35
33
 
36
34
  Special directories:
37
35
  - .cache/: Stores cached data from external sources like OEIS to improve performance
38
- - syntheticModules/: Contains dynamically generated, optimized implementations of the
39
- core algorithm created by the code transformation framework
36
+ - syntheticModules/: Contains dynamically generated, optimized implementations of the core algorithm created by the code
37
+ transformation framework
40
38
  - reference/: Historical implementations and educational resources for algorithm exploration
41
- - reference/jobsCompleted/: Contains successful computations for previously unknown values,
42
- including first-ever calculations for 2x19 and 2x20 maps (OEIS A001415)
39
+ - reference/jobsCompleted/: Contains successful computations for previously unknown values, including first-ever
40
+ calculations for 2x19 and 2x20 maps (OEIS A001415)
43
41
 
44
- This package balances algorithm readability and understandability with
45
- high-performance computation capabilities, allowing users to compute map folding
46
- totals for larger dimensions than previously feasible while also providing
47
- a foundation for exploring advanced code transformation techniques.
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.
48
45
  """
49
46
 
50
- from mapFolding.theSSOT import (
47
+ from mapFolding.datatypes import (
51
48
  Array1DElephino as Array1DElephino,
52
49
  Array1DFoldsTotal as Array1DFoldsTotal,
53
50
  Array1DLeavesTotal as Array1DLeavesTotal,
54
51
  Array3D as Array3D,
55
- ComputationState as ComputationState,
56
52
  DatatypeElephino as DatatypeElephino,
57
53
  DatatypeFoldsTotal as DatatypeFoldsTotal,
58
54
  DatatypeLeavesTotal as DatatypeLeavesTotal,
@@ -60,6 +56,10 @@ from mapFolding.theSSOT import (
60
56
  NumPyFoldsTotal as NumPyFoldsTotal,
61
57
  NumPyIntegerType as NumPyIntegerType,
62
58
  NumPyLeavesTotal as NumPyLeavesTotal,
59
+ )
60
+
61
+ from mapFolding.theSSOT import (
62
+ ComputationState as ComputationState,
63
63
  raiseIfNoneGitHubIssueNumber3 as raiseIfNoneGitHubIssueNumber3,
64
64
  The as The,
65
65
  )
@@ -70,6 +70,8 @@ from mapFolding.theDao import (
70
70
  )
71
71
 
72
72
  from mapFolding.beDRY import (
73
+ getLeavesTotal as getLeavesTotal,
74
+ getTaskDivisions as getTaskDivisions,
73
75
  outfitCountFolds as outfitCountFolds,
74
76
  setProcessorLimit as setProcessorLimit,
75
77
  validateListDimensions as validateListDimensions,
@@ -83,7 +85,7 @@ from mapFolding.toolboxFilesystem import (
83
85
  writeStringToHere as writeStringToHere,
84
86
  )
85
87
 
86
- from mapFolding.basecamp import countFolds as countFolds
88
+ from mapFolding.Z0Z_flowControl import countFolds
87
89
 
88
90
  from mapFolding.oeis import (
89
91
  clearOEIScache as clearOEIScache,
mapFolding/basecamp.py CHANGED
@@ -63,7 +63,7 @@ def countFolds(listDimensions: Sequence[int]
63
63
 
64
64
  Note well
65
65
  ---------
66
- You probably don't want to divide the computation into tasks.
66
+ You probably do not want to divide your computation into tasks.
67
67
 
68
68
  If you want to compute a large `foldsTotal`, dividing the computation into tasks is usually a bad idea. Dividing the
69
69
  algorithm into tasks is inherently inefficient: efficient division into tasks means there would be no overlap in the
mapFolding/beDRY.py CHANGED
@@ -29,8 +29,7 @@ def getLeavesTotal(mapShape: tuple[int, ...]) -> int:
29
29
  """
30
30
  Calculate the total number of leaves in a map with the given dimensions.
31
31
 
32
- The total number of leaves is the product of all dimensions in the map shape. This value is foundational for
33
- initializing the computation state and determining task divisions.
32
+ The total number of leaves is the product of all dimensions in the map shape.
34
33
 
35
34
  Parameters
36
35
  ----------
@@ -0,0 +1,142 @@
1
+ from mapFolding.dataBaskets import MapFoldingState
2
+
3
+ def activeLeafGreaterThan0(state: MapFoldingState) -> bool:
4
+ return state.leaf1ndex > 0
5
+
6
+ def activeLeafGreaterThanLeavesTotal(state: MapFoldingState) -> bool:
7
+ return state.leaf1ndex > state.leavesTotal
8
+
9
+ def activeLeafIsTheFirstLeaf(state: MapFoldingState) -> bool:
10
+ return state.leaf1ndex <= 1
11
+
12
+ def activeLeafIsUnconstrainedInAllDimensions(state: MapFoldingState) -> bool:
13
+ return not state.dimensionsUnconstrained
14
+
15
+ def activeLeafUnconstrainedInThisDimension(state: MapFoldingState) -> MapFoldingState:
16
+ state.dimensionsUnconstrained -= 1
17
+ return state
18
+
19
+ def filterCommonGaps(state: MapFoldingState) -> MapFoldingState:
20
+ state.gapsWhere[state.gap1ndex] = state.gapsWhere[state.indexMiniGap]
21
+ if state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] == state.dimensionsUnconstrained:
22
+ state = incrementActiveGap(state)
23
+ state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] = 0
24
+ return state
25
+
26
+ def gapAvailable(state: MapFoldingState) -> bool:
27
+ return state.leaf1ndex > 0
28
+
29
+ def incrementActiveGap(state: MapFoldingState) -> MapFoldingState:
30
+ state.gap1ndex += 1
31
+ return state
32
+
33
+ def incrementGap1ndexCeiling(state: MapFoldingState) -> MapFoldingState:
34
+ state.gap1ndexCeiling += 1
35
+ return state
36
+
37
+ def incrementIndexMiniGap(state: MapFoldingState) -> MapFoldingState:
38
+ state.indexMiniGap += 1
39
+ return state
40
+
41
+ def initializeIndexMiniGap(state: MapFoldingState) -> MapFoldingState:
42
+ state.indexMiniGap = state.gap1ndex
43
+ return state
44
+
45
+ def initializeVariablesToFindGaps(state: MapFoldingState) -> MapFoldingState:
46
+ state.dimensionsUnconstrained = state.dimensionsTotal
47
+ state.gap1ndexCeiling = state.gapRangeStart[state.leaf1ndex - 1]
48
+ state.indexDimension = 0
49
+ return state
50
+
51
+ def insertActiveLeaf(state: MapFoldingState) -> MapFoldingState:
52
+ state.indexLeaf = 0
53
+ while state.indexLeaf < state.leaf1ndex:
54
+ state.gapsWhere[state.gap1ndexCeiling] = state.indexLeaf
55
+ state.gap1ndexCeiling += 1
56
+ state.indexLeaf += 1
57
+ return state
58
+
59
+ def insertActiveLeafAtGap(state: MapFoldingState) -> MapFoldingState:
60
+ state.gap1ndex -= 1
61
+ state.leafAbove[state.leaf1ndex] = state.gapsWhere[state.gap1ndex]
62
+ state.leafBelow[state.leaf1ndex] = state.leafBelow[state.leafAbove[state.leaf1ndex]]
63
+ state.leafBelow[state.leafAbove[state.leaf1ndex]] = state.leaf1ndex
64
+ state.leafAbove[state.leafBelow[state.leaf1ndex]] = state.leaf1ndex
65
+ state.gapRangeStart[state.leaf1ndex] = state.gap1ndex
66
+ state.leaf1ndex += 1
67
+ return state
68
+
69
+ def leafBelowSentinelIs1(state: MapFoldingState) -> bool:
70
+ return state.leafBelow[0] == 1
71
+
72
+ def leafConnecteeIsActiveLeaf(state: MapFoldingState) -> bool:
73
+ return state.leafConnectee == state.leaf1ndex
74
+
75
+ def lookForGaps(state: MapFoldingState) -> MapFoldingState:
76
+ state.gapsWhere[state.gap1ndexCeiling] = state.leafConnectee
77
+ if state.countDimensionsGapped[state.leafConnectee] == 0:
78
+ state = incrementGap1ndexCeiling(state)
79
+ state.countDimensionsGapped[state.leafConnectee] += 1
80
+ return state
81
+
82
+ def lookupLeafConnecteeInConnectionGraph(state: MapFoldingState) -> MapFoldingState:
83
+ state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leaf1ndex]
84
+ return state
85
+
86
+ def loopingLeavesConnectedToActiveLeaf(state: MapFoldingState) -> bool:
87
+ return state.leafConnectee != state.leaf1ndex
88
+
89
+ def loopingThroughTheDimensions(state: MapFoldingState) -> bool:
90
+ return state.indexDimension < state.dimensionsTotal
91
+
92
+ def loopingToActiveGapCeiling(state: MapFoldingState) -> bool:
93
+ return state.indexMiniGap < state.gap1ndexCeiling
94
+
95
+ def noGapsHere(state: MapFoldingState) -> bool:
96
+ return (state.leaf1ndex > 0) and (state.gap1ndex == state.gapRangeStart[state.leaf1ndex - 1])
97
+
98
+ def tryAnotherLeafConnectee(state: MapFoldingState) -> MapFoldingState:
99
+ state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leafBelow[state.leafConnectee]]
100
+ return state
101
+
102
+ def tryNextDimension(state: MapFoldingState) -> MapFoldingState:
103
+ state.indexDimension += 1
104
+ return state
105
+
106
+ def undoLastLeafPlacement(state: MapFoldingState) -> MapFoldingState:
107
+ state.leaf1ndex -= 1
108
+ state.leafBelow[state.leafAbove[state.leaf1ndex]] = state.leafBelow[state.leaf1ndex]
109
+ state.leafAbove[state.leafBelow[state.leaf1ndex]] = state.leafAbove[state.leaf1ndex]
110
+ return state
111
+
112
+ def count(state: MapFoldingState) -> MapFoldingState:
113
+ while activeLeafGreaterThan0(state):
114
+ if activeLeafIsTheFirstLeaf(state) or leafBelowSentinelIs1(state):
115
+ if activeLeafGreaterThanLeavesTotal(state):
116
+ state.groupsOfFolds += 1
117
+ else:
118
+ state = initializeVariablesToFindGaps(state)
119
+ while loopingThroughTheDimensions(state):
120
+ state = lookupLeafConnecteeInConnectionGraph(state)
121
+ if leafConnecteeIsActiveLeaf(state):
122
+ state = activeLeafUnconstrainedInThisDimension(state)
123
+ else:
124
+ while loopingLeavesConnectedToActiveLeaf(state):
125
+ state = lookForGaps(state)
126
+ state = tryAnotherLeafConnectee(state)
127
+ state = tryNextDimension(state)
128
+ if activeLeafIsUnconstrainedInAllDimensions(state):
129
+ state = insertActiveLeaf(state)
130
+ state = initializeIndexMiniGap(state)
131
+ while loopingToActiveGapCeiling(state):
132
+ state = filterCommonGaps(state)
133
+ state = incrementIndexMiniGap(state)
134
+ while noGapsHere(state):
135
+ state = undoLastLeafPlacement(state)
136
+ if gapAvailable(state):
137
+ state = insertActiveLeafAtGap(state)
138
+ return state
139
+
140
+ def doTheNeedful(state: MapFoldingState) -> MapFoldingState:
141
+ state = count(state)
142
+ return state
@@ -0,0 +1,49 @@
1
+ from mapFolding.beDRY import getConnectionGraph, getLeavesTotal, makeDataContainer
2
+ from mapFolding.datatypes import Array3D, Array1DElephino, Array1DLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal
3
+ import dataclasses
4
+
5
+ @dataclasses.dataclass
6
+ class MapFoldingState:
7
+ mapShape: tuple[DatatypeLeavesTotal, ...] = dataclasses.field(init=True, metadata={'elementConstructor': 'DatatypeLeavesTotal'})
8
+
9
+ groupsOfFolds: DatatypeFoldsTotal = dataclasses.field(default=DatatypeFoldsTotal(0), metadata={'theCountingIdentifier': True})
10
+
11
+ gap1ndex: DatatypeElephino = DatatypeElephino(0)
12
+ gap1ndexCeiling: DatatypeElephino = DatatypeElephino(0)
13
+ indexDimension: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
14
+ indexLeaf: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
15
+ indexMiniGap: DatatypeElephino = DatatypeElephino(0)
16
+ leaf1ndex: DatatypeLeavesTotal = DatatypeLeavesTotal(1)
17
+ leafConnectee: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
18
+
19
+ dimensionsUnconstrained: DatatypeLeavesTotal = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
20
+
21
+ countDimensionsGapped: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
22
+ gapRangeStart: Array1DElephino = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DElephino.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
23
+ gapsWhere: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
24
+ leafAbove: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
25
+ leafBelow: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
26
+
27
+ connectionGraph: Array3D = dataclasses.field(init=False, metadata={'dtype': Array3D.__args__[1].__args__[0]}) # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
28
+ dimensionsTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
29
+ leavesTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
30
+
31
+ @property
32
+ def foldsTotal(self) -> DatatypeFoldsTotal:
33
+ _foldsTotal = DatatypeFoldsTotal(self.leavesTotal) * self.groupsOfFolds
34
+ return _foldsTotal
35
+
36
+ def __post_init__(self) -> None:
37
+ self.dimensionsTotal = DatatypeLeavesTotal(len(self.mapShape))
38
+ self.leavesTotal = DatatypeLeavesTotal(getLeavesTotal(self.mapShape))
39
+
40
+ leavesTotalAsInt = int(self.leavesTotal)
41
+
42
+ self.connectionGraph = getConnectionGraph(self.mapShape, leavesTotalAsInt, self.__dataclass_fields__['connectionGraph'].metadata['dtype'])
43
+
44
+ if self.dimensionsUnconstrained is None: self.dimensionsUnconstrained = DatatypeLeavesTotal(int(self.dimensionsTotal)) # pyright: ignore[reportUnnecessaryComparison]
45
+ if self.gapsWhere is None: self.gapsWhere = makeDataContainer(leavesTotalAsInt * leavesTotalAsInt + 1, self.__dataclass_fields__['gapsWhere'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
46
+ if self.countDimensionsGapped is None: self.countDimensionsGapped = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['countDimensionsGapped'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
47
+ if self.gapRangeStart is None: self.gapRangeStart = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['gapRangeStart'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
48
+ if self.leafAbove is None: self.leafAbove = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['leafAbove'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
49
+ if self.leafBelow is None: self.leafBelow = makeDataContainer(leavesTotalAsInt + 1, self.__dataclass_fields__['leafBelow'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison]
@@ -0,0 +1,21 @@
1
+ from numpy import dtype, int64 as numpy_int64, integer, ndarray
2
+ from typing import Any, TypeAlias, TypeVar
3
+
4
+ # =============================================================================
5
+ # Flexible Data Structure System Needs Enhanced Paradigm https://github.com/hunterhogan/mapFolding/issues/9
6
+
7
+ NumPyIntegerType = TypeVar('NumPyIntegerType', bound=integer[Any], covariant=True)
8
+
9
+ DatatypeLeavesTotal: TypeAlias = int
10
+ NumPyLeavesTotal: TypeAlias = numpy_int64
11
+
12
+ DatatypeElephino: TypeAlias = int
13
+ NumPyElephino: TypeAlias = numpy_int64
14
+
15
+ DatatypeFoldsTotal: TypeAlias = int
16
+ NumPyFoldsTotal: TypeAlias = numpy_int64
17
+
18
+ Array3D: TypeAlias = ndarray[tuple[int, int, int], dtype[NumPyLeavesTotal]]
19
+ Array1DLeavesTotal: TypeAlias = ndarray[tuple[int], dtype[NumPyLeavesTotal]]
20
+ Array1DElephino: TypeAlias = ndarray[tuple[int], dtype[NumPyElephino]]
21
+ Array1DFoldsTotal: TypeAlias = ndarray[tuple[int], dtype[NumPyFoldsTotal]]
mapFolding/oeis.py CHANGED
@@ -20,7 +20,7 @@ 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 writeStringToHere, The
23
+ from mapFolding import countFolds, The, writeStringToHere
24
24
  from pathlib import Path
25
25
  from typing import Any, Final, TYPE_CHECKING
26
26
  import argparse
@@ -401,7 +401,6 @@ def oeisIDfor_n(oeisID: str, n: int | Any) -> int:
401
401
  raise ArithmeticError(f"OEIS sequence {oeisID} is not defined at {n = }.")
402
402
  foldsTotal: int = settingsOEIS[oeisID]['valuesKnown'][n]
403
403
  return foldsTotal
404
- from mapFolding.basecamp import countFolds
405
404
  return countFolds(mapShape)
406
405
 
407
406
  def OEIS_for_n() -> None: