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.
- mapFolding/Z0Z_flowControl.py +117 -0
- mapFolding/__init__.py +28 -26
- mapFolding/basecamp.py +1 -1
- mapFolding/beDRY.py +1 -2
- mapFolding/daoOfMapFolding.py +142 -0
- mapFolding/dataBaskets.py +49 -0
- mapFolding/datatypes.py +21 -0
- mapFolding/oeis.py +1 -2
- mapFolding/someAssemblyRequired/Z0Z_makeSomeModules.py +226 -0
- mapFolding/someAssemblyRequired/__init__.py +12 -2
- mapFolding/someAssemblyRequired/_theTypes.py +11 -5
- mapFolding/someAssemblyRequired/_tool_Make.py +8 -0
- mapFolding/someAssemblyRequired/_tool_Then.py +44 -1
- mapFolding/someAssemblyRequired/_toolboxAST.py +57 -0
- mapFolding/someAssemblyRequired/_toolboxAntecedents.py +95 -29
- mapFolding/someAssemblyRequired/_toolboxContainers.py +59 -53
- mapFolding/someAssemblyRequired/_toolboxPython.py +52 -50
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +10 -9
- mapFolding/someAssemblyRequired/toolboxNumba.py +1 -1
- mapFolding/someAssemblyRequired/transformationTools.py +40 -58
- mapFolding/syntheticModules/dataPacking.py +25 -0
- mapFolding/syntheticModules/initializeCount.py +49 -0
- mapFolding/syntheticModules/theorem2.py +49 -0
- mapFolding/syntheticModules/theorem2Numba.py +51 -0
- mapFolding/theSSOT.py +13 -21
- {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/METADATA +4 -3
- mapfolding-0.9.4.dist-info/RECORD +57 -0
- {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/WHEEL +1 -1
- tests/__init__.py +2 -2
- tests/conftest.py +7 -7
- tests/test_computations.py +17 -13
- tests/test_tasks.py +2 -2
- mapfolding-0.9.2.dist-info/RECORD +0 -47
- {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.9.2.dist-info → mapfolding-0.9.4.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
|
6
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
- The system converts readable code into high-performance implementations through
|
|
24
|
-
|
|
25
|
-
- Provides tools to "shatter" complex dataclasses into primitive components,
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
46
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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]
|
mapFolding/datatypes.py
ADDED
|
@@ -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
|
|
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:
|