mapFolding 0.8.0__py3-none-any.whl → 0.8.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.
- mapFolding/__init__.py +33 -4
- mapFolding/basecamp.py +16 -2
- mapFolding/beDRY.py +40 -32
- mapFolding/filesystem.py +124 -90
- mapFolding/noHomeYet.py +12 -0
- mapFolding/oeis.py +18 -3
- mapFolding/reference/__init__.py +38 -0
- mapFolding/reference/flattened.py +66 -47
- mapFolding/reference/hunterNumba.py +28 -4
- mapFolding/reference/irvineJavaPort.py +13 -1
- mapFolding/reference/{jax.py → jaxCount.py} +46 -27
- mapFolding/reference/lunnanNumpy.py +19 -5
- mapFolding/reference/lunnanWhile.py +19 -7
- mapFolding/reference/rotatedEntryPoint.py +20 -3
- mapFolding/reference/total_countPlus1vsPlusN.py +226 -203
- mapFolding/someAssemblyRequired/__init__.py +29 -0
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +32 -14
- mapFolding/someAssemblyRequired/ingredientsNumba.py +22 -1
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +193 -0
- mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +3 -4
- mapFolding/someAssemblyRequired/transformDataStructures.py +168 -0
- mapFolding/someAssemblyRequired/transformationTools.py +233 -225
- mapFolding/theDao.py +19 -5
- mapFolding/theSSOT.py +89 -122
- mapfolding-0.8.2.dist-info/METADATA +187 -0
- mapfolding-0.8.2.dist-info/RECORD +39 -0
- {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/WHEEL +1 -1
- tests/conftest.py +43 -33
- tests/test_computations.py +7 -7
- tests/test_other.py +2 -2
- mapFolding/reference/lunnan.py +0 -153
- mapFolding/someAssemblyRequired/Z0Z_workbench.py +0 -350
- mapFolding/someAssemblyRequired/synthesizeDataConverters.py +0 -117
- mapFolding/syntheticModules/numbaCountHistoricalExample.py +0 -158
- mapFolding/syntheticModules/numba_doTheNeedfulHistoricalExample.py +0 -13
- mapfolding-0.8.0.dist-info/METADATA +0 -157
- mapfolding-0.8.0.dist-info/RECORD +0 -41
- {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info/licenses}/LICENSE +0 -0
- {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/top_level.txt +0 -0
mapFolding/__init__.py
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Map folding enumeration and counting algorithms with optimization capabilities.
|
|
3
|
+
|
|
4
|
+
This package implements algorithms to count and enumerate the various 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 low-level algorithmic optimizations and code
|
|
8
|
+
transformation tools.
|
|
9
|
+
|
|
10
|
+
Core modules:
|
|
11
|
+
- basecamp: Public API with simplified interfaces for end users
|
|
12
|
+
- theDao: Core computational algorithm using a functional state-transformation approach
|
|
13
|
+
- beDRY: Utility functions for common operations and parameter management
|
|
14
|
+
- theSSOT: Single Source of Truth for configuration, types, and state management
|
|
15
|
+
- oeis: Interface to the Online Encyclopedia of Integer Sequences for known results
|
|
16
|
+
|
|
17
|
+
Extended functionality:
|
|
18
|
+
- someAssemblyRequired: Code transformation framework that optimizes the core algorithm
|
|
19
|
+
through AST manipulation, dataclass transformation, and compilation techniques
|
|
20
|
+
|
|
21
|
+
Special directories:
|
|
22
|
+
- .cache/: Stores cached data from external sources like OEIS to improve performance
|
|
23
|
+
- syntheticModules/: Contains dynamically generated, optimized implementations of the
|
|
24
|
+
core algorithm created by the code transformation framework
|
|
25
|
+
|
|
26
|
+
This package strives to balance algorithm readability and understandability with
|
|
27
|
+
high-performance computation capabilities, allowing users to compute map folding
|
|
28
|
+
totals for larger dimensions than previously feasible.
|
|
29
|
+
"""
|
|
1
30
|
from mapFolding.basecamp import countFolds as countFolds
|
|
2
31
|
from mapFolding.oeis import clearOEIScache, getOEISids, OEIS_for_n
|
|
3
32
|
|
|
4
33
|
__all__ = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
34
|
+
'clearOEIScache',
|
|
35
|
+
'countFolds',
|
|
36
|
+
'getOEISids',
|
|
37
|
+
'OEIS_for_n',
|
|
9
38
|
]
|
mapFolding/basecamp.py
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Public API for the map folding algorithm with simplified interface.
|
|
3
|
+
|
|
4
|
+
This module provides the main entry point for users of the mapFolding package,
|
|
5
|
+
abstracting away the complexities of the computational algorithm. It offers
|
|
6
|
+
a high-level interface to count the total number of possible ways to fold
|
|
7
|
+
a rectangular map of specified dimensions, with options for customizing the
|
|
8
|
+
computation process and saving results.
|
|
9
|
+
|
|
10
|
+
The primary function is countFolds, which handles parameter validation,
|
|
11
|
+
computation state management, dispatching to the appropriate algorithm
|
|
12
|
+
implementation, and optional persistence of results.
|
|
13
|
+
"""
|
|
14
|
+
|
|
1
15
|
from collections.abc import Sequence
|
|
2
16
|
from mapFolding.beDRY import outfitCountFolds, setCPUlimit, validateListDimensions
|
|
3
17
|
from mapFolding.filesystem import getPathFilenameFoldsTotal, saveFoldsTotal
|
|
4
|
-
from mapFolding.theSSOT import ComputationState, getPackageDispatcher
|
|
18
|
+
from mapFolding.theSSOT import ComputationState, getPackageDispatcher, The
|
|
5
19
|
from os import PathLike
|
|
6
20
|
from pathlib import Path
|
|
7
21
|
|
|
@@ -40,7 +54,7 @@ def countFolds(listDimensions: Sequence[int]
|
|
|
40
54
|
If you want to compute a large `foldsTotal`, dividing the computation into tasks is usually a bad idea. Dividing the algorithm into tasks is inherently inefficient: efficient division into tasks means there would be no overlap in the work performed by each task. When dividing this algorithm, the amount of overlap is between 50% and 90% by all tasks: at least 50% of the work done by every task must be done by _all_ tasks. If you improve the computation time, it will only change by -10 to -50% depending on (at the very least) the ratio of the map dimensions and the number of leaves. If an undivided computation would take 10 hours on your computer, for example, the computation will still take at least 5 hours but you might reduce the time to 9 hours. Most of the time, however, you will increase the computation time. If logicalCores >= leavesTotal, it will probably be faster. If logicalCores <= 2 * leavesTotal, it will almost certainly be slower for all map dimensions.
|
|
41
55
|
"""
|
|
42
56
|
mapShape: tuple[int, ...] = validateListDimensions(listDimensions)
|
|
43
|
-
concurrencyLimit: int = setCPUlimit(CPUlimit)
|
|
57
|
+
concurrencyLimit: int = setCPUlimit(CPUlimit, The.concurrencyPackage)
|
|
44
58
|
computationStateInitialized: ComputationState = outfitCountFolds(mapShape, computationDivisions, concurrencyLimit)
|
|
45
59
|
|
|
46
60
|
dispatcherCallableProxy = getPackageDispatcher()
|
mapFolding/beDRY.py
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for maintaining DRY (Don't Repeat Yourself) principles in the mapFolding package.
|
|
3
|
+
|
|
4
|
+
This module provides a collection of helper functions that abstract common operations needed
|
|
5
|
+
throughout the package, preventing code duplication and ensuring consistency. The functions
|
|
6
|
+
manage core aspects of the computation process, including:
|
|
7
|
+
|
|
8
|
+
1. Resource allocation and system limits management
|
|
9
|
+
2. Data structure initialization and manipulation
|
|
10
|
+
3. Parameter validation and interpretation
|
|
11
|
+
4. Construction of specialized arrays and matrices for the folding algorithm
|
|
12
|
+
|
|
13
|
+
The functions in this module serve as a relatively stable API for other modules to use,
|
|
14
|
+
particularly for initializing computation state, validating inputs, and creating data
|
|
15
|
+
structures needed by the folding algorithms.
|
|
16
|
+
"""
|
|
2
17
|
from collections.abc import Sequence
|
|
3
|
-
from mapFolding.theSSOT import
|
|
18
|
+
from mapFolding.theSSOT import ComputationState
|
|
19
|
+
from numpy import dtype as numpy_dtype, integer, ndarray
|
|
4
20
|
from sys import maxsize as sysMaxsize
|
|
5
|
-
from typing import Any
|
|
21
|
+
from typing import Any, TypeVar
|
|
6
22
|
from Z0Z_tools import defineConcurrencyLimit, intInnit, oopsieKwargsie
|
|
7
23
|
import numpy
|
|
8
24
|
|
|
25
|
+
numpyIntegerType = TypeVar('numpyIntegerType', bound=integer[Any])
|
|
26
|
+
|
|
9
27
|
def getLeavesTotal(mapShape: tuple[int, ...]) -> int:
|
|
10
28
|
productDimensions = 1
|
|
11
29
|
for dimension in mapShape:
|
|
@@ -66,25 +84,16 @@ def getTaskDivisions(computationDivisions: int | str | None, concurrencyLimit: i
|
|
|
66
84
|
raise ValueError(f"Problem: `taskDivisions`, ({taskDivisions}), is greater than `leavesTotal`, ({leavesTotal}), which will cause duplicate counting of the folds.\n\nChallenge: you cannot directly set `taskDivisions` or `leavesTotal`. They are derived from parameters that may or may not still be named `computationDivisions`, `CPUlimit` , and `listDimensions` and from dubious-quality Python code.")
|
|
67
85
|
return int(max(0, taskDivisions))
|
|
68
86
|
|
|
69
|
-
def
|
|
70
|
-
"""An imperfect way to reduce code duplication."""
|
|
71
|
-
if 'numpy' == getDatatypePackage():
|
|
72
|
-
numpyDtype = datatype or getNumpyDtypeDefault()
|
|
73
|
-
else:
|
|
74
|
-
raise NotImplementedError("Somebody done broke it.")
|
|
75
|
-
return numpyDtype
|
|
76
|
-
|
|
77
|
-
def makeConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: type[numpy.signedinteger[Any]] | None = None) -> Array3D:
|
|
78
|
-
numpyDtype = interpretParameter_datatype(datatype)
|
|
87
|
+
def makeConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: type[numpyIntegerType]) -> ndarray[tuple[int, int, int], numpy_dtype[numpyIntegerType]]:
|
|
79
88
|
dimensionsTotal = len(mapShape)
|
|
80
|
-
cumulativeProduct = numpy.multiply.accumulate([1] + list(mapShape), dtype=
|
|
81
|
-
arrayDimensions = numpy.array(mapShape, dtype=
|
|
82
|
-
coordinateSystem = numpy.zeros((dimensionsTotal, leavesTotal + 1), dtype=
|
|
89
|
+
cumulativeProduct = numpy.multiply.accumulate([1] + list(mapShape), dtype=datatype)
|
|
90
|
+
arrayDimensions = numpy.array(mapShape, dtype=datatype)
|
|
91
|
+
coordinateSystem = numpy.zeros((dimensionsTotal, leavesTotal + 1), dtype=datatype)
|
|
83
92
|
for indexDimension in range(dimensionsTotal):
|
|
84
93
|
for leaf1ndex in range(1, leavesTotal + 1):
|
|
85
94
|
coordinateSystem[indexDimension, leaf1ndex] = (((leaf1ndex - 1) // cumulativeProduct[indexDimension]) % arrayDimensions[indexDimension] + 1)
|
|
86
95
|
|
|
87
|
-
connectionGraph = numpy.zeros((dimensionsTotal, leavesTotal + 1, leavesTotal + 1), dtype=
|
|
96
|
+
connectionGraph = numpy.zeros((dimensionsTotal, leavesTotal + 1, leavesTotal + 1), dtype=datatype)
|
|
88
97
|
for indexDimension in range(dimensionsTotal):
|
|
89
98
|
for activeLeaf1ndex in range(1, leavesTotal + 1):
|
|
90
99
|
for connectee1ndex in range(1, activeLeaf1ndex + 1):
|
|
@@ -101,9 +110,8 @@ def makeConnectionGraph(mapShape: tuple[int, ...], leavesTotal: int, datatype: t
|
|
|
101
110
|
connectionGraph[indexDimension, activeLeaf1ndex, connectee1ndex] = connectee1ndex + cumulativeProduct[indexDimension]
|
|
102
111
|
return connectionGraph
|
|
103
112
|
|
|
104
|
-
def makeDataContainer(shape: int | tuple[int, ...], datatype: type[
|
|
105
|
-
|
|
106
|
-
return numpy.zeros(shape, dtype=numpyDtype)
|
|
113
|
+
def makeDataContainer(shape: int | tuple[int, ...], datatype: type[numpyIntegerType]) -> ndarray[Any, numpy_dtype[numpyIntegerType]]:
|
|
114
|
+
return numpy.zeros(shape, dtype=datatype)
|
|
107
115
|
|
|
108
116
|
def outfitCountFolds(mapShape: tuple[int, ...], computationDivisions: int | str | None = None, concurrencyLimit: int = 1) -> ComputationState:
|
|
109
117
|
leavesTotal = getLeavesTotal(mapShape)
|
|
@@ -111,7 +119,7 @@ def outfitCountFolds(mapShape: tuple[int, ...], computationDivisions: int | str
|
|
|
111
119
|
computationStateInitialized = ComputationState(mapShape, leavesTotal, taskDivisions, concurrencyLimit)
|
|
112
120
|
return computationStateInitialized
|
|
113
121
|
|
|
114
|
-
def setCPUlimit(CPUlimit: Any | None) -> int:
|
|
122
|
+
def setCPUlimit(CPUlimit: Any | None, concurrencyPackage: str | None = None) -> int:
|
|
115
123
|
"""Sets CPU limit for concurrent operations.
|
|
116
124
|
|
|
117
125
|
If the concurrency is managed by `numba`, the maximum number of CPUs is retrieved from `numba.get_num_threads()` and not by polling the hardware. Therefore, if there are
|
|
@@ -139,17 +147,17 @@ def setCPUlimit(CPUlimit: Any | None) -> int:
|
|
|
139
147
|
if not (CPUlimit is None or isinstance(CPUlimit, (bool, int, float))):
|
|
140
148
|
CPUlimit = oopsieKwargsie(CPUlimit)
|
|
141
149
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
match concurrencyPackage:
|
|
151
|
+
case 'multiprocessing' | None:
|
|
152
|
+
# When to use multiprocessing.set_start_method https://github.com/hunterhogan/mapFolding/issues/6
|
|
153
|
+
concurrencyLimit: int = defineConcurrencyLimit(CPUlimit)
|
|
154
|
+
case 'numba':
|
|
155
|
+
from numba import get_num_threads, set_num_threads
|
|
156
|
+
concurrencyLimit = defineConcurrencyLimit(CPUlimit, get_num_threads())
|
|
157
|
+
set_num_threads(concurrencyLimit)
|
|
158
|
+
concurrencyLimit = get_num_threads()
|
|
159
|
+
case _:
|
|
160
|
+
raise NotImplementedError(f"I received {concurrencyPackage=} but I don't know what to do with that.")
|
|
153
161
|
return concurrencyLimit
|
|
154
162
|
|
|
155
163
|
def validateListDimensions(listDimensions: Sequence[int]) -> tuple[int, ...]:
|
mapFolding/filesystem.py
CHANGED
|
@@ -1,95 +1,129 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Filesystem utilities for managing map folding computation results.
|
|
3
|
+
|
|
4
|
+
This module provides functions for standardized handling of files related to the mapFolding
|
|
5
|
+
package, with a focus on saving, retrieving, and naming computation results. It implements
|
|
6
|
+
consistent naming conventions and path resolution strategies to ensure that:
|
|
7
|
+
|
|
8
|
+
1. Computation results are stored in a predictable location
|
|
9
|
+
2. Filenames follow a consistent pattern based on map dimensions
|
|
10
|
+
3. Results can be reliably retrieved for future reference
|
|
11
|
+
4. The system handles file operations safely with appropriate error handling
|
|
12
|
+
|
|
13
|
+
The module serves as the interface between the computational components of the package
|
|
14
|
+
and the filesystem, abstracting away the details of file operations and path management.
|
|
15
|
+
"""
|
|
2
16
|
from pathlib import Path, PurePath
|
|
3
17
|
from typing import Any
|
|
18
|
+
from os import PathLike
|
|
4
19
|
import os
|
|
5
20
|
|
|
6
21
|
def getFilenameFoldsTotal(mapShape: tuple[int, ...]) -> str:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
22
|
+
"""
|
|
23
|
+
Create a standardized filename for a computed `foldsTotal` value.
|
|
24
|
+
|
|
25
|
+
This function generates a consistent, filesystem-safe filename based on map dimensions.
|
|
26
|
+
Standardizing filenames ensures that results can be reliably stored and retrieved,
|
|
27
|
+
avoiding potential filesystem incompatibilities or Python naming restrictions.
|
|
28
|
+
|
|
29
|
+
Parameters:
|
|
30
|
+
mapShape: A sequence of integers representing the dimensions of the map.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
filenameFoldsTotal: A filename string in format 'pMxN.foldsTotal' where M,N are sorted dimensions.
|
|
34
|
+
|
|
35
|
+
Notes:
|
|
36
|
+
The filename format ensures:
|
|
37
|
+
- No spaces in the filename
|
|
38
|
+
- Safe filesystem characters
|
|
39
|
+
- Unique extension (.foldsTotal)
|
|
40
|
+
- Python-safe strings (no starting with numbers, no reserved words)
|
|
41
|
+
- The 'p' prefix preserves compatibility with Lunnan's original code.
|
|
42
|
+
"""
|
|
43
|
+
return 'p' + 'x'.join(str(dimension) for dimension in sorted(mapShape)) + '.foldsTotal'
|
|
44
|
+
|
|
45
|
+
def getPathFilenameFoldsTotal(mapShape: tuple[int, ...], pathLikeWriteFoldsTotal: str | PathLike[str] | None = None) -> Path:
|
|
46
|
+
"""
|
|
47
|
+
Get a standardized path and filename for the computed foldsTotal value.
|
|
48
|
+
|
|
49
|
+
This function resolves paths for storing computation results, handling different
|
|
50
|
+
input types including directories, absolute paths, or relative paths. It ensures
|
|
51
|
+
that all parent directories exist in the resulting path.
|
|
52
|
+
|
|
53
|
+
Parameters:
|
|
54
|
+
mapShape: List of dimensions for the map folding problem.
|
|
55
|
+
pathLikeWriteFoldsTotal (getPathJobRootDEFAULT): Path, filename, or relative path and filename.
|
|
56
|
+
If None, uses default path. If a directory, appends standardized filename.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
pathFilenameFoldsTotal: Absolute path and filename for storing the foldsTotal value.
|
|
60
|
+
|
|
61
|
+
Notes:
|
|
62
|
+
The function creates any necessary directories in the path if they don't exist.
|
|
63
|
+
"""
|
|
64
|
+
from mapFolding.theSSOT import getPathJobRootDEFAULT
|
|
65
|
+
|
|
66
|
+
if pathLikeWriteFoldsTotal is None:
|
|
67
|
+
pathFilenameFoldsTotal = getPathJobRootDEFAULT() / getFilenameFoldsTotal(mapShape)
|
|
68
|
+
else:
|
|
69
|
+
pathLikeSherpa = Path(pathLikeWriteFoldsTotal)
|
|
70
|
+
if pathLikeSherpa.is_dir():
|
|
71
|
+
pathFilenameFoldsTotal = pathLikeSherpa / getFilenameFoldsTotal(mapShape)
|
|
72
|
+
elif pathLikeSherpa.is_file() and pathLikeSherpa.is_absolute():
|
|
73
|
+
pathFilenameFoldsTotal = pathLikeSherpa
|
|
74
|
+
else:
|
|
75
|
+
pathFilenameFoldsTotal = getPathJobRootDEFAULT() / pathLikeSherpa
|
|
76
|
+
|
|
77
|
+
pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
|
|
78
|
+
return pathFilenameFoldsTotal
|
|
79
|
+
|
|
80
|
+
def saveFoldsTotal(pathFilename: str | PathLike[str], foldsTotal: int) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Save `foldsTotal` value to disk with multiple fallback mechanisms.
|
|
83
|
+
|
|
84
|
+
This function attempts to save the computed `foldsTotal` value to the specified
|
|
85
|
+
location, with backup strategies in case the primary save attempt fails.
|
|
86
|
+
The robustness is critical since these computations may take days to complete.
|
|
87
|
+
|
|
88
|
+
Parameters:
|
|
89
|
+
pathFilename: Target save location for the `foldsTotal` value
|
|
90
|
+
foldsTotal: The computed value to save
|
|
91
|
+
|
|
92
|
+
Notes:
|
|
93
|
+
If the primary save fails, the function will attempt alternative save methods:
|
|
94
|
+
1. Print the value prominently to stdout
|
|
95
|
+
2. Create a fallback file in the current working directory
|
|
96
|
+
3. As a last resort, simply print the value
|
|
97
|
+
"""
|
|
98
|
+
try:
|
|
99
|
+
pathFilenameFoldsTotal = Path(pathFilename)
|
|
100
|
+
pathFilenameFoldsTotal.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
pathFilenameFoldsTotal.write_text(str(foldsTotal))
|
|
102
|
+
except Exception as ERRORmessage:
|
|
103
|
+
try:
|
|
104
|
+
print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
|
|
105
|
+
print(ERRORmessage)
|
|
106
|
+
print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n")
|
|
107
|
+
randomnessPlanB = (int(str(foldsTotal).strip()[-1]) + 1) * ['YO_']
|
|
108
|
+
filenameInfixUnique = ''.join(randomnessPlanB)
|
|
109
|
+
pathFilenamePlanB = os.path.join(os.getcwd(), 'foldsTotal' + filenameInfixUnique + '.txt')
|
|
110
|
+
writeStreamFallback = open(pathFilenamePlanB, 'w')
|
|
111
|
+
writeStreamFallback.write(str(foldsTotal))
|
|
112
|
+
writeStreamFallback.close()
|
|
113
|
+
print(str(pathFilenamePlanB))
|
|
114
|
+
except Exception:
|
|
115
|
+
print(foldsTotal)
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
def writeStringToHere(this: str, pathFilename: str | PathLike[Any] | PurePath) -> None:
|
|
119
|
+
"""
|
|
120
|
+
Write a string to a file, creating parent directories if needed.
|
|
121
|
+
|
|
122
|
+
Parameters:
|
|
123
|
+
this: The string content to write to the file
|
|
124
|
+
pathFilename: The target file path where the string should be written
|
|
125
|
+
"""
|
|
126
|
+
pathFilename = Path(pathFilename)
|
|
127
|
+
pathFilename.parent.mkdir(parents=True, exist_ok=True)
|
|
128
|
+
pathFilename.write_text(str(this))
|
|
129
|
+
return None
|
mapFolding/noHomeYet.py
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Interface for retrieving known map folding totals from OEIS (Online Encyclopedia of Integer Sequences).
|
|
3
|
+
|
|
4
|
+
This module provides utilities for accessing pre-computed map folding totals that are known
|
|
5
|
+
from mathematical literature and stored in the OEIS. The functions cache results for
|
|
6
|
+
performance and provide lookups based on map dimensions.
|
|
7
|
+
|
|
8
|
+
The main functions are:
|
|
9
|
+
- makeDictionaryFoldsTotalKnown: Creates a dictionary of known folding totals indexed by map dimensions
|
|
10
|
+
- getFoldsTotalKnown: Retrieves the folding total for a specific map shape, returning -1 if unknown
|
|
11
|
+
"""
|
|
12
|
+
|
|
1
13
|
from functools import cache
|
|
2
14
|
from mapFolding.oeis import settingsOEIS
|
|
3
15
|
|
mapFolding/oeis.py
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Interface to The Online Encyclopedia of Integer Sequences (OEIS) for map folding sequences.
|
|
3
|
+
|
|
4
|
+
This module provides a comprehensive interface for accessing and utilizing integer sequences
|
|
5
|
+
from the OEIS that relate to map folding problems. It implements functionality to:
|
|
6
|
+
|
|
7
|
+
1. Retrieve sequence data from OEIS with local caching for performance
|
|
8
|
+
2. Map sequence indices to corresponding map shapes based on sequence definitions
|
|
9
|
+
3. Provide a command-line interface for sequence lookups
|
|
10
|
+
4. Execute map folding computations for sequence terms not available in OEIS
|
|
11
|
+
|
|
12
|
+
The module maintains a registry of implemented OEIS sequences (A001415-A001418, A195646)
|
|
13
|
+
with their metadata, known values, and functions to convert between sequence indices and
|
|
14
|
+
map dimensions. This allows the package to validate results against established mathematical
|
|
15
|
+
literature and extend sequences beyond their currently known terms.
|
|
16
|
+
"""
|
|
2
17
|
from collections.abc import Callable
|
|
3
18
|
from datetime import datetime, timedelta
|
|
4
|
-
from mapFolding.theSSOT import
|
|
19
|
+
from mapFolding.theSSOT import The
|
|
5
20
|
from pathlib import Path
|
|
6
21
|
from typing import Any, Final, TYPE_CHECKING
|
|
7
22
|
import argparse
|
|
@@ -23,7 +38,7 @@ cacheDays = 7
|
|
|
23
38
|
"""
|
|
24
39
|
Section: make `settingsOEIS`"""
|
|
25
40
|
|
|
26
|
-
pathCache: Path =
|
|
41
|
+
pathCache: Path = The.pathPackage / ".cache"
|
|
27
42
|
|
|
28
43
|
class SettingsOEIS(TypedDict):
|
|
29
44
|
description: str
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Historical and reference implementations of map-folding algorithms.
|
|
3
|
+
|
|
4
|
+
This directory contains various implementations of the map-folding algorithm,
|
|
5
|
+
serving both as historical references and as benchmarks for performance comparison.
|
|
6
|
+
These implementations range from direct translations of Lunnon's original 1971 code
|
|
7
|
+
to highly specialized versions using modern optimization techniques.
|
|
8
|
+
|
|
9
|
+
Categories of reference implementations:
|
|
10
|
+
|
|
11
|
+
1. Historical transcripts:
|
|
12
|
+
- foldings.txt - Original algorithm from Lunnon's 1971 paper
|
|
13
|
+
- foldings.AA - Reconstructed Atlas Autocode version with corrections
|
|
14
|
+
|
|
15
|
+
2. Direct translations:
|
|
16
|
+
- lunnanWhile.py - Python translation using while loops
|
|
17
|
+
- lunnanNumpy.py - NumPy-based translation with array operations
|
|
18
|
+
|
|
19
|
+
3. Alternative implementations:
|
|
20
|
+
- irvineJavaPort.py - Port from Sean A. Irvine's Java implementation
|
|
21
|
+
- hunterNumba.py - Numba-optimized implementation
|
|
22
|
+
- jaxCount.py - JAX implementation for GPU acceleration
|
|
23
|
+
- flattened.py - Semantically decomposed version with operation grouping
|
|
24
|
+
|
|
25
|
+
4. Specialized variants:
|
|
26
|
+
- total_countPlus1vsPlusN.py - Optimized counting with different increment strategies
|
|
27
|
+
- rotatedEntryPoint.py - Alternative entry point implementation (demonstration)
|
|
28
|
+
|
|
29
|
+
These reference implementations are valuable for:
|
|
30
|
+
- Understanding the algorithm's historical development
|
|
31
|
+
- Comparing performance characteristics across implementation strategies
|
|
32
|
+
- Studying optimization techniques and their effects
|
|
33
|
+
- Verifying the correctness of the core algorithm against known solutions
|
|
34
|
+
|
|
35
|
+
Note: These implementations are for reference only and not used in the production
|
|
36
|
+
code path of the package. The active implementation resides in theDao.py with
|
|
37
|
+
optimized variants generated by the someAssemblyRequired framework.
|
|
38
|
+
"""
|