mapFolding 0.3.12__py3-none-any.whl → 0.4.0__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 +40 -38
- mapFolding/basecamp.py +50 -50
- mapFolding/beDRY.py +336 -336
- mapFolding/oeis.py +262 -262
- mapFolding/reference/flattened.py +294 -293
- mapFolding/reference/hunterNumba.py +126 -126
- mapFolding/reference/irvineJavaPort.py +99 -99
- mapFolding/reference/jax.py +153 -153
- mapFolding/reference/lunnan.py +148 -148
- mapFolding/reference/lunnanNumpy.py +115 -115
- mapFolding/reference/lunnanWhile.py +114 -114
- mapFolding/reference/rotatedEntryPoint.py +183 -183
- mapFolding/reference/total_countPlus1vsPlusN.py +203 -203
- mapFolding/someAssemblyRequired/__init__.py +2 -1
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +12 -12
- mapFolding/someAssemblyRequired/makeJob.py +48 -48
- mapFolding/someAssemblyRequired/synthesizeModuleJAX.py +17 -17
- mapFolding/someAssemblyRequired/synthesizeNumba.py +343 -633
- mapFolding/someAssemblyRequired/synthesizeNumbaGeneralized.py +371 -0
- mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +150 -0
- mapFolding/someAssemblyRequired/synthesizeNumbaModules.py +75 -0
- mapFolding/syntheticModules/__init__.py +0 -0
- mapFolding/syntheticModules/numba_countInitialize.py +3 -3
- mapFolding/syntheticModules/numba_countParallel.py +3 -3
- mapFolding/syntheticModules/numba_countSequential.py +3 -3
- mapFolding/syntheticModules/numba_doTheNeedful.py +6 -6
- mapFolding/theDao.py +165 -165
- mapFolding/theSSOT.py +176 -172
- mapFolding/theSSOTnumba.py +90 -74
- mapFolding-0.4.0.dist-info/METADATA +122 -0
- mapFolding-0.4.0.dist-info/RECORD +41 -0
- tests/conftest.py +238 -128
- tests/test_oeis.py +80 -80
- tests/test_other.py +137 -224
- tests/test_tasks.py +21 -21
- tests/test_types.py +2 -2
- mapFolding/someAssemblyRequired/synthesizeNumbaHardcoding.py +0 -188
- mapFolding-0.3.12.dist-info/METADATA +0 -155
- mapFolding-0.3.12.dist-info/RECORD +0 -40
- tests/conftest_tmpRegistry.py +0 -62
- tests/conftest_uniformTests.py +0 -53
- {mapFolding-0.3.12.dist-info → mapFolding-0.4.0.dist-info}/LICENSE +0 -0
- {mapFolding-0.3.12.dist-info → mapFolding-0.4.0.dist-info}/WHEEL +0 -0
- {mapFolding-0.3.12.dist-info → mapFolding-0.4.0.dist-info}/entry_points.txt +0 -0
- {mapFolding-0.3.12.dist-info → mapFolding-0.4.0.dist-info}/top_level.txt +0 -0
mapFolding/oeis.py
CHANGED
|
@@ -13,9 +13,9 @@ import urllib.response
|
|
|
13
13
|
import warnings
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
|
-
|
|
16
|
+
from typing import TypedDict
|
|
17
17
|
else:
|
|
18
|
-
|
|
18
|
+
TypedDict = dict
|
|
19
19
|
|
|
20
20
|
"""
|
|
21
21
|
Section: make `settingsOEIS`"""
|
|
@@ -23,217 +23,217 @@ Section: make `settingsOEIS`"""
|
|
|
23
23
|
_pathCache = getPathPackage() / ".cache"
|
|
24
24
|
|
|
25
25
|
class SettingsOEIS(TypedDict):
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
description: str
|
|
27
|
+
offset: int
|
|
28
|
+
getMapShape: Callable[[int], List[int]]
|
|
29
|
+
valuesBenchmark: List[int]
|
|
30
|
+
valuesKnown: Dict[int, int]
|
|
31
|
+
valuesTestParallelization: List[int]
|
|
32
|
+
valuesTestValidation: List[int]
|
|
33
|
+
valueUnknown: int
|
|
34
34
|
|
|
35
35
|
settingsOEIShardcodedValues: Dict[str, Dict[str, Any]] = {
|
|
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
|
-
|
|
36
|
+
'A001415': {
|
|
37
|
+
'getMapShape': lambda n: sorted([2, n]),
|
|
38
|
+
'valuesBenchmark': [14],
|
|
39
|
+
'valuesTestParallelization': [*range(3, 7)],
|
|
40
|
+
'valuesTestValidation': [0, 1, random.randint(2, 9)],
|
|
41
|
+
},
|
|
42
|
+
'A001416': {
|
|
43
|
+
'getMapShape': lambda n: sorted([3, n]),
|
|
44
|
+
'valuesBenchmark': [9],
|
|
45
|
+
'valuesTestParallelization': [*range(3, 5)],
|
|
46
|
+
'valuesTestValidation': [0, 1, random.randint(2, 6)],
|
|
47
|
+
},
|
|
48
|
+
'A001417': {
|
|
49
|
+
'getMapShape': lambda n: [2] * n,
|
|
50
|
+
'valuesBenchmark': [6],
|
|
51
|
+
'valuesTestParallelization': [*range(2, 4)],
|
|
52
|
+
'valuesTestValidation': [0, 1, random.randint(2, 4)],
|
|
53
|
+
},
|
|
54
|
+
'A195646': {
|
|
55
|
+
'getMapShape': lambda n: [3] * n,
|
|
56
|
+
'valuesBenchmark': [3],
|
|
57
|
+
'valuesTestParallelization': [*range(2, 3)],
|
|
58
|
+
'valuesTestValidation': [0, 1, 2],
|
|
59
|
+
},
|
|
60
|
+
'A001418': {
|
|
61
|
+
'getMapShape': lambda n: [n, n],
|
|
62
|
+
'valuesBenchmark': [5],
|
|
63
|
+
'valuesTestParallelization': [*range(2, 4)],
|
|
64
|
+
'valuesTestValidation': [1, random.randint(2, 4)],
|
|
65
|
+
},
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
oeisIDsImplemented: Final[List[str]] = sorted([oeisID.upper().strip() for oeisID in settingsOEIShardcodedValues.keys()])
|
|
69
69
|
"""Directly implemented OEIS IDs; standardized, e.g., 'A001415'."""
|
|
70
70
|
|
|
71
71
|
def _validateOEISid(oeisIDcandidate: str) -> str:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
72
|
+
"""
|
|
73
|
+
Validates an OEIS sequence ID against implemented sequences.
|
|
74
|
+
|
|
75
|
+
If the provided ID is recognized within the application's implemented
|
|
76
|
+
OEIS sequences, the function returns the verified ID in uppercase.
|
|
77
|
+
Otherwise, a KeyError is raised indicating that the sequence is not
|
|
78
|
+
directly supported.
|
|
79
|
+
|
|
80
|
+
Parameters:
|
|
81
|
+
oeisIDcandidate: The OEIS sequence identifier to validate.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
oeisID: The validated and possibly modified OEIS sequence ID, if recognized.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
KeyError: If the provided sequence ID is not directly implemented.
|
|
88
|
+
"""
|
|
89
|
+
if oeisIDcandidate in oeisIDsImplemented:
|
|
90
|
+
return oeisIDcandidate
|
|
91
|
+
else:
|
|
92
|
+
oeisIDcleaned = str(oeisIDcandidate).upper().strip()
|
|
93
|
+
if oeisIDcleaned in oeisIDsImplemented:
|
|
94
|
+
return oeisIDcleaned
|
|
95
|
+
else:
|
|
96
|
+
raise KeyError(
|
|
97
|
+
f"OEIS ID {oeisIDcandidate} is not directly implemented.\n"
|
|
98
|
+
f"Available sequences:\n{_formatOEISsequenceInfo()}"
|
|
99
|
+
)
|
|
100
100
|
|
|
101
101
|
def _getFilenameOEISbFile(oeisID: str) -> str:
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
oeisID = _validateOEISid(oeisID)
|
|
103
|
+
return f"b{oeisID[1:]}.txt"
|
|
104
104
|
|
|
105
105
|
def _parseBFileOEIS(OEISbFile: str, oeisID: str) -> Dict[int, int]:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
106
|
+
"""
|
|
107
|
+
Parses the content of an OEIS b-file for a given sequence ID.
|
|
108
|
+
This function processes a multiline string representing an OEIS b-file and
|
|
109
|
+
creates a dictionary mapping integer indices to their corresponding sequence
|
|
110
|
+
values. The first line of the b-file is expected to contain a comment that
|
|
111
|
+
matches the given sequence ID. If it does not match, a ValueError is raised.
|
|
112
|
+
|
|
113
|
+
Parameters:
|
|
114
|
+
OEISbFile: A multiline string representing an OEIS b-file.
|
|
115
|
+
oeisID: The expected OEIS sequence identifier.
|
|
116
|
+
Returns:
|
|
117
|
+
OEISsequence: A dictionary where each key is an integer index `n` and
|
|
118
|
+
each value is the sequence value `a(n)` corresponding to that index.
|
|
119
|
+
Raises:
|
|
120
|
+
ValueError: If the first line of the file does not indicate the expected
|
|
121
|
+
sequence ID or if the content format is invalid.
|
|
122
|
+
"""
|
|
123
|
+
bFileLines = OEISbFile.strip().splitlines()
|
|
124
|
+
if not bFileLines.pop(0).startswith(f"# {oeisID}"):
|
|
125
|
+
warnings.warn(f"Content does not match sequence {oeisID}")
|
|
126
|
+
return {-1: -1}
|
|
127
|
+
|
|
128
|
+
OEISsequence = {}
|
|
129
|
+
for line in bFileLines:
|
|
130
|
+
if line.startswith('#'):
|
|
131
|
+
continue
|
|
132
|
+
n, aOFn = map(int, line.split())
|
|
133
|
+
OEISsequence[n] = aOFn
|
|
134
|
+
return OEISsequence
|
|
135
135
|
|
|
136
136
|
def _getOEISofficial(pathFilenameCache: pathlib.Path, url: str) -> None | str:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
137
|
+
cacheDays = 7
|
|
138
|
+
tryCache = False
|
|
139
|
+
if pathFilenameCache.exists():
|
|
140
|
+
fileAge = datetime.now() - datetime.fromtimestamp(pathFilenameCache.stat().st_mtime)
|
|
141
|
+
tryCache = fileAge < timedelta(days=cacheDays)
|
|
142
|
+
|
|
143
|
+
oeisInformation = None
|
|
144
|
+
if tryCache:
|
|
145
|
+
try:
|
|
146
|
+
oeisInformation = pathFilenameCache.read_text()
|
|
147
|
+
except IOError:
|
|
148
|
+
tryCache = False
|
|
149
|
+
|
|
150
|
+
if not tryCache:
|
|
151
|
+
httpResponse: urllib.response.addinfourl = urllib.request.urlopen(url)
|
|
152
|
+
oeisInformation = httpResponse.read().decode('utf-8')
|
|
153
|
+
pathFilenameCache.parent.mkdir(parents=True, exist_ok=True)
|
|
154
|
+
pathFilenameCache.write_text(oeisInformation)
|
|
155
|
+
|
|
156
|
+
if not oeisInformation:
|
|
157
|
+
warnings.warn(f"Failed to retrieve OEIS sequence information for {pathFilenameCache.stem}.")
|
|
158
|
+
|
|
159
|
+
return oeisInformation
|
|
160
160
|
|
|
161
161
|
def _getOEISidValues(oeisID: str) -> Dict[int, int]:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
162
|
+
"""
|
|
163
|
+
Retrieves the specified OEIS sequence as a dictionary mapping integer indices
|
|
164
|
+
to their corresponding values.
|
|
165
|
+
This function checks for a cached local copy of the sequence data, using it if
|
|
166
|
+
it has not expired. Otherwise, it fetches the sequence data from the OEIS
|
|
167
|
+
website and writes it to the cache. The parsed data is returned as a dictionary
|
|
168
|
+
mapping each index to its sequence value.
|
|
169
|
+
|
|
170
|
+
Parameters:
|
|
171
|
+
oeisID: The identifier of the OEIS sequence to retrieve.
|
|
172
|
+
Returns:
|
|
173
|
+
OEISsequence: A dictionary where each key is an integer index, `n`, and each
|
|
174
|
+
value is the corresponding "a(n)" from the OEIS entry.
|
|
175
|
+
Raises:
|
|
176
|
+
ValueError: If the cached or downloaded file format is invalid.
|
|
177
|
+
IOError: If there is an error reading from or writing to the local cache.
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
pathFilenameCache = _pathCache / _getFilenameOEISbFile(oeisID)
|
|
181
|
+
url = f"https://oeis.org/{oeisID}/{_getFilenameOEISbFile(oeisID)}"
|
|
182
|
+
|
|
183
|
+
oeisInformation = _getOEISofficial(pathFilenameCache, url)
|
|
184
|
+
|
|
185
|
+
if oeisInformation:
|
|
186
|
+
return _parseBFileOEIS(oeisInformation, oeisID)
|
|
187
|
+
return {-1: -1}
|
|
188
188
|
|
|
189
189
|
def _getOEISidInformation(oeisID: str) -> Tuple[str, int]:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
190
|
+
oeisID = _validateOEISid(oeisID)
|
|
191
|
+
pathFilenameCache = _pathCache / f"{oeisID}.txt"
|
|
192
|
+
url = f"https://oeis.org/search?q=id:{oeisID}&fmt=text"
|
|
193
|
+
|
|
194
|
+
oeisInformation = _getOEISofficial(pathFilenameCache, url)
|
|
195
|
+
|
|
196
|
+
if not oeisInformation:
|
|
197
|
+
return "Not found", -1
|
|
198
|
+
|
|
199
|
+
description_parts = []
|
|
200
|
+
offset = None
|
|
201
|
+
for line in oeisInformation.splitlines():
|
|
202
|
+
if line.startswith('%N'):
|
|
203
|
+
parts = line.split()
|
|
204
|
+
if parts[1] == oeisID:
|
|
205
|
+
desc_part = ' '.join(parts[2:])
|
|
206
|
+
description_parts.append(desc_part)
|
|
207
|
+
elif line.startswith('%O'):
|
|
208
|
+
parts = line.split()
|
|
209
|
+
if parts[1] == oeisID:
|
|
210
|
+
offset_str = parts[2].split(',')[0]
|
|
211
|
+
offset = int(offset_str)
|
|
212
|
+
if not description_parts:
|
|
213
|
+
warnings.warn(f"No description found for {oeisID}")
|
|
214
|
+
description_parts.append("No description found")
|
|
215
|
+
if offset is None:
|
|
216
|
+
warnings.warn(f"No offset found for {oeisID}")
|
|
217
|
+
offset = -1
|
|
218
|
+
description = ' '.join(description_parts)
|
|
219
|
+
return description, offset
|
|
220
220
|
|
|
221
221
|
def makeSettingsOEIS() -> Dict[str, SettingsOEIS]:
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
222
|
+
settingsTarget = {}
|
|
223
|
+
for oeisID in oeisIDsImplemented:
|
|
224
|
+
valuesKnownSherpa = _getOEISidValues(oeisID)
|
|
225
|
+
descriptionSherpa, offsetSherpa = _getOEISidInformation(oeisID)
|
|
226
|
+
settingsTarget[oeisID] = SettingsOEIS(
|
|
227
|
+
description=descriptionSherpa,
|
|
228
|
+
offset=offsetSherpa,
|
|
229
|
+
getMapShape=settingsOEIShardcodedValues[oeisID]['getMapShape'],
|
|
230
|
+
valuesBenchmark=settingsOEIShardcodedValues[oeisID]['valuesBenchmark'],
|
|
231
|
+
valuesTestParallelization=settingsOEIShardcodedValues[oeisID]['valuesTestParallelization'],
|
|
232
|
+
valuesTestValidation=settingsOEIShardcodedValues[oeisID]['valuesTestValidation'],
|
|
233
|
+
valuesKnown=valuesKnownSherpa,
|
|
234
|
+
valueUnknown=max(valuesKnownSherpa.keys(), default=0) + 1
|
|
235
|
+
)
|
|
236
|
+
return settingsTarget
|
|
237
237
|
|
|
238
238
|
settingsOEIS: Dict[str, SettingsOEIS] = makeSettingsOEIS()
|
|
239
239
|
"""All values and settings for `oeisIDsImplemented`."""
|
|
@@ -242,98 +242,98 @@ settingsOEIS: Dict[str, SettingsOEIS] = makeSettingsOEIS()
|
|
|
242
242
|
Section: private functions"""
|
|
243
243
|
|
|
244
244
|
def _formatHelpText() -> str:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
245
|
+
"""Format standardized help text for both CLI and interactive use."""
|
|
246
|
+
exampleOEISid = oeisIDsImplemented[0]
|
|
247
|
+
exampleN = settingsOEIS[exampleOEISid]['valuesTestValidation'][-1]
|
|
248
|
+
|
|
249
|
+
return (
|
|
250
|
+
"\nAvailable OEIS sequences:\n"
|
|
251
|
+
f"{_formatOEISsequenceInfo()}\n"
|
|
252
|
+
"\nUsage examples:\n"
|
|
253
|
+
" Command line:\n"
|
|
254
|
+
f" OEIS_for_n {exampleOEISid} {exampleN}\n"
|
|
255
|
+
" Python:\n"
|
|
256
|
+
" from mapFolding import oeisIDfor_n\n"
|
|
257
|
+
f" foldsTotal = oeisIDfor_n('{exampleOEISid}', {exampleN})"
|
|
258
|
+
)
|
|
259
259
|
|
|
260
260
|
def _formatOEISsequenceInfo() -> str:
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
"""Format information about available OEIS sequences for display or error messages."""
|
|
262
|
+
return "\n".join(
|
|
263
|
+
f" {oeisID}: {settingsOEIS[oeisID]['description']}"
|
|
264
|
+
for oeisID in oeisIDsImplemented
|
|
265
|
+
)
|
|
266
266
|
|
|
267
267
|
"""
|
|
268
268
|
Section: public functions"""
|
|
269
269
|
|
|
270
270
|
def oeisIDfor_n(oeisID: str, n: int) -> int:
|
|
271
|
-
|
|
272
|
-
|
|
271
|
+
"""
|
|
272
|
+
Calculate a(n) of a sequence from "The On-Line Encyclopedia of Integer Sequences" (OEIS).
|
|
273
273
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
274
|
+
Parameters:
|
|
275
|
+
oeisID: The ID of the OEIS sequence.
|
|
276
|
+
n: A non-negative integer for which to calculate the sequence value.
|
|
277
277
|
|
|
278
|
-
|
|
279
|
-
|
|
278
|
+
Returns:
|
|
279
|
+
sequenceValue: a(n) of the OEIS sequence.
|
|
280
280
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
281
|
+
Raises:
|
|
282
|
+
ValueError: If n is negative.
|
|
283
|
+
KeyError: If the OEIS sequence ID is not directly implemented.
|
|
284
|
+
"""
|
|
285
|
+
oeisID = _validateOEISid(oeisID)
|
|
286
286
|
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
if not isinstance(n, int) or n < 0:
|
|
288
|
+
raise ValueError("`n` must be non-negative integer.")
|
|
289
289
|
|
|
290
|
-
|
|
290
|
+
listDimensions = settingsOEIS[oeisID]['getMapShape'](n)
|
|
291
291
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
if n <= 1 or len(listDimensions) < 2:
|
|
293
|
+
offset = settingsOEIS[oeisID]['offset']
|
|
294
|
+
if n < offset:
|
|
295
|
+
raise ArithmeticError(f"OEIS sequence {oeisID} is not defined at n={n}.")
|
|
296
|
+
foldsTotal = settingsOEIS[oeisID]['valuesKnown'][n]
|
|
297
|
+
return foldsTotal
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
return countFolds(listDimensions)
|
|
300
300
|
|
|
301
301
|
def OEIS_for_n() -> None:
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
302
|
+
"""Command-line interface for oeisIDfor_n."""
|
|
303
|
+
parserCLI = argparse.ArgumentParser(
|
|
304
|
+
description="Calculate a(n) for an OEIS sequence.",
|
|
305
|
+
epilog=_formatHelpText(),
|
|
306
|
+
formatter_class=argparse.RawDescriptionHelpFormatter
|
|
307
|
+
)
|
|
308
|
+
parserCLI.add_argument('oeisID', help="OEIS sequence identifier")
|
|
309
|
+
parserCLI.add_argument('n', type=int, help="Calculate a(n) for this n")
|
|
310
310
|
|
|
311
|
-
|
|
311
|
+
argumentsCLI = parserCLI.parse_args()
|
|
312
312
|
|
|
313
|
-
|
|
313
|
+
timeStart = time.perf_counter()
|
|
314
314
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
315
|
+
try:
|
|
316
|
+
print(oeisIDfor_n(argumentsCLI.oeisID, argumentsCLI.n), "distinct folding patterns.")
|
|
317
|
+
except (KeyError, ValueError, ArithmeticError) as ERRORmessage:
|
|
318
|
+
print(f"Error: {ERRORmessage}", file=sys.stderr)
|
|
319
|
+
sys.exit(1)
|
|
320
320
|
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
timeElapsed = time.perf_counter() - timeStart
|
|
322
|
+
print(f"Time elapsed: {timeElapsed:.3f} seconds")
|
|
323
323
|
|
|
324
324
|
def clearOEIScache() -> None:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
325
|
+
"""Delete all cached OEIS sequence files."""
|
|
326
|
+
if not _pathCache.exists():
|
|
327
|
+
print(f"Cache directory, {_pathCache}, not found - nothing to clear.")
|
|
328
|
+
return
|
|
329
|
+
for oeisID in settingsOEIS:
|
|
330
|
+
( _pathCache / f"{oeisID}.txt" ).unlink(missing_ok=True)
|
|
331
|
+
( _pathCache / _getFilenameOEISbFile(oeisID) ).unlink(missing_ok=True)
|
|
332
|
+
print(f"Cache cleared from {_pathCache}")
|
|
333
333
|
|
|
334
334
|
def getOEISids() -> None:
|
|
335
|
-
|
|
336
|
-
|
|
335
|
+
"""Print all available OEIS sequence IDs that are directly implemented."""
|
|
336
|
+
print(_formatHelpText())
|
|
337
337
|
|
|
338
338
|
if __name__ == "__main__":
|
|
339
|
-
|
|
339
|
+
getOEISids()
|