mapFolding 0.16.4__py3-none-any.whl → 0.17.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.
- easyRun/A000682.py +2 -2
- easyRun/NOTcountingFolds.py +16 -9
- easyRun/countFolds.py +10 -3
- easyRun/meanders.py +3 -3
- mapFolding/algorithms/A000136constraintPropagation.py +95 -0
- mapFolding/algorithms/A000136elimination.py +163 -0
- mapFolding/algorithms/A000136eliminationParallel.py +77 -0
- mapFolding/algorithms/matrixMeanders.py +59 -18
- mapFolding/algorithms/matrixMeandersNumPyndas.py +841 -0
- mapFolding/algorithms/symmetricFolds.py +24 -25
- mapFolding/basecamp.py +30 -14
- mapFolding/dataBaskets.py +30 -71
- mapFolding/reference/irvineJavaPort.py +3 -3
- mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +1 -1
- mapFolding/someAssemblyRequired/A007822/_asynchronousAnnex.py +1 -1
- mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +5 -3
- mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +22 -6
- mapFolding/someAssemblyRequired/RecipeJob.py +14 -24
- mapFolding/someAssemblyRequired/__init__.py +1 -0
- mapFolding/someAssemblyRequired/_toolkitContainers.py +6 -4
- mapFolding/someAssemblyRequired/infoBooth.py +2 -1
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +75 -20
- mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +9 -10
- mapFolding/someAssemblyRequired/makingModules_count.py +20 -22
- mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +9 -9
- mapFolding/someAssemblyRequired/mapFoldingModules/makeMapFoldingModules.py +6 -5
- mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +6 -6
- mapFolding/someAssemblyRequired/toolkitMakeModules.py +3 -29
- mapFolding/someAssemblyRequired/toolkitNumba.py +2 -1
- mapFolding/someAssemblyRequired/transformationTools.py +2 -3
- mapFolding/syntheticModules/A007822/algorithm.py +8 -8
- mapFolding/syntheticModules/A007822/asynchronous.py +12 -13
- mapFolding/syntheticModules/A007822/initializeState.py +10 -8
- mapFolding/syntheticModules/A007822/theorem2.py +10 -8
- mapFolding/syntheticModules/A007822/theorem2Numba.py +20 -16
- mapFolding/syntheticModules/A007822/theorem2Trimmed.py +10 -8
- mapFolding/syntheticModules/countParallelNumba.py +5 -2
- mapFolding/syntheticModules/daoOfMapFoldingNumba.py +4 -2
- mapFolding/syntheticModules/initializeState.py +1 -1
- mapFolding/syntheticModules/meanders/bigInt.py +52 -15
- mapFolding/syntheticModules/theorem2.py +1 -1
- mapFolding/syntheticModules/theorem2Numba.py +4 -2
- mapFolding/syntheticModules/theorem2Trimmed.py +1 -1
- mapFolding/tests/test_computations.py +28 -2
- {mapfolding-0.16.4.dist-info → mapfolding-0.17.0.dist-info}/METADATA +9 -9
- {mapfolding-0.16.4.dist-info → mapfolding-0.17.0.dist-info}/RECORD +50 -49
- mapFolding/algorithms/matrixMeandersBeDry.py +0 -182
- mapFolding/algorithms/matrixMeandersNumPy.py +0 -333
- mapFolding/algorithms/matrixMeandersPandas.py +0 -334
- {mapfolding-0.16.4.dist-info → mapfolding-0.17.0.dist-info}/WHEEL +0 -0
- {mapfolding-0.16.4.dist-info → mapfolding-0.17.0.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.16.4.dist-info → mapfolding-0.17.0.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.16.4.dist-info → mapfolding-0.17.0.dist-info}/top_level.txt +0 -0
|
@@ -3,34 +3,33 @@
|
|
|
3
3
|
Notes
|
|
4
4
|
-----
|
|
5
5
|
- About constructing `leafComparison`:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- Therefore, the first iteration of the loop is hardcoded to save processing time.
|
|
9
|
-
- I _feel_ there must be a more efficient way to do this.
|
|
6
|
+
- The first iteration of the loop is hardcoded to save processing time.
|
|
7
|
+
- I _feel_ there must be a more efficient way to do this.
|
|
10
8
|
- Some implementation details are based on Numba compatibility. Incompatible:
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
- `numpy.take(..., out=...)`
|
|
10
|
+
- `numpy.all(..., axis=...)`
|
|
13
11
|
"""
|
|
14
12
|
from mapFolding.dataBaskets import SymmetricFoldsState
|
|
15
|
-
import numpy
|
|
16
13
|
|
|
17
14
|
def filterAsymmetricFolds(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
15
|
+
state.indexLeaf = 1
|
|
16
|
+
state.leafComparison[0] = 1
|
|
17
|
+
state.leafConnectee = 1
|
|
18
|
+
|
|
19
|
+
while state.leafConnectee < state.leavesTotal + 1:
|
|
20
|
+
state.indexMiniGap = state.leafBelow[state.indexLeaf]
|
|
21
|
+
state.leafComparison[state.leafConnectee] = (state.indexMiniGap - state.indexLeaf + state.leavesTotal) % state.leavesTotal
|
|
22
|
+
state.indexLeaf = state.indexMiniGap
|
|
23
|
+
|
|
24
|
+
state.leafConnectee += 1
|
|
25
|
+
|
|
26
|
+
for listTuples in state.indices:
|
|
27
|
+
state.leafConnectee = 1
|
|
28
|
+
for indexLeft, indexRight in listTuples:
|
|
29
|
+
if state.leafComparison[indexLeft] != state.leafComparison[indexRight]:
|
|
30
|
+
state.leafConnectee = 0
|
|
31
|
+
break
|
|
32
|
+
state.symmetricFolds += state.leafConnectee
|
|
33
|
+
|
|
34
|
+
return state
|
|
36
35
|
|
mapFolding/basecamp.py
CHANGED
|
@@ -174,13 +174,15 @@ def countFolds(listDimensions: Sequence[int] | None = None
|
|
|
174
174
|
|
|
175
175
|
# ruff: noqa: E701
|
|
176
176
|
else:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
177
|
+
if all(dimension < 3 for dimension in mapShape):
|
|
178
|
+
from mapFolding.algorithms.daoOfMapFolding import doTheNeedful
|
|
179
|
+
else:
|
|
180
|
+
match flow:
|
|
181
|
+
case 'numba': from mapFolding.syntheticModules.daoOfMapFoldingNumba import doTheNeedful
|
|
182
|
+
case 'theorem2': from mapFolding.syntheticModules.theorem2 import doTheNeedful
|
|
183
|
+
case 'theorem2Numba': from mapFolding.syntheticModules.theorem2Numba import doTheNeedful
|
|
184
|
+
case 'theorem2Trimmed': from mapFolding.syntheticModules.theorem2Trimmed import doTheNeedful
|
|
185
|
+
case 'daoOfMapFolding' | _: from mapFolding.algorithms.daoOfMapFolding import doTheNeedful
|
|
184
186
|
|
|
185
187
|
from mapFolding.dataBaskets import MapFoldingState
|
|
186
188
|
mapFoldingState: MapFoldingState = MapFoldingState(mapShape)
|
|
@@ -203,7 +205,6 @@ def NOTcountingFolds(oeisID: str, oeis_n: int, flow: str | None = None
|
|
|
203
205
|
matched_oeisID: bool = True
|
|
204
206
|
|
|
205
207
|
match oeisID:
|
|
206
|
-
case 'A000136': from mapFolding.algorithms.oeisIDbyFormula import A000136 as doTheNeedful
|
|
207
208
|
case 'A000560': from mapFolding.algorithms.oeisIDbyFormula import A000560 as doTheNeedful
|
|
208
209
|
case 'A001010': from mapFolding.algorithms.oeisIDbyFormula import A001010 as doTheNeedful
|
|
209
210
|
case 'A001011': from mapFolding.algorithms.oeisIDbyFormula import A001011 as doTheNeedful
|
|
@@ -222,15 +223,30 @@ def NOTcountingFolds(oeisID: str, oeis_n: int, flow: str | None = None
|
|
|
222
223
|
else:
|
|
223
224
|
matched_oeisID = True
|
|
224
225
|
match oeisID:
|
|
226
|
+
case 'A000136':
|
|
227
|
+
from mapFolding import setProcessorLimit
|
|
228
|
+
concurrencyLimit: int = setProcessorLimit(CPUlimit)
|
|
229
|
+
match flow:
|
|
230
|
+
case 'elimination':
|
|
231
|
+
from mapFolding.algorithms.A000136elimination import doTheNeedful
|
|
232
|
+
countTotal = doTheNeedful(oeis_n)
|
|
233
|
+
case 'eliminationParallel':
|
|
234
|
+
from mapFolding.algorithms.A000136eliminationParallel import doTheNeedful
|
|
235
|
+
countTotal = doTheNeedful(oeis_n, concurrencyLimit)
|
|
236
|
+
case 'constraintPropagation':
|
|
237
|
+
from mapFolding.algorithms.A000136constraintPropagation import doTheNeedful
|
|
238
|
+
countTotal = doTheNeedful(oeis_n, concurrencyLimit)
|
|
239
|
+
case _:
|
|
240
|
+
from mapFolding.algorithms.oeisIDbyFormula import A000136 as doTheNeedful
|
|
241
|
+
countTotal = doTheNeedful(oeis_n)
|
|
225
242
|
case 'A000682' | 'A005316':
|
|
226
243
|
match flow:
|
|
227
244
|
case 'matrixNumPy':
|
|
228
|
-
from mapFolding.algorithms.
|
|
229
|
-
from mapFolding.dataBaskets import MatrixMeandersNumPyState as State
|
|
245
|
+
from mapFolding.algorithms.matrixMeandersNumPyndas import doTheNeedful, MatrixMeandersNumPyState as State
|
|
230
246
|
case 'matrixPandas':
|
|
231
|
-
from mapFolding.algorithms.
|
|
232
|
-
|
|
233
|
-
case _:
|
|
247
|
+
from mapFolding.algorithms.matrixMeandersNumPyndas import (
|
|
248
|
+
doTheNeedfulPandas as doTheNeedful, MatrixMeandersNumPyState as State)
|
|
249
|
+
case 'matrixMeanders' | _:
|
|
234
250
|
from mapFolding.algorithms.matrixMeanders import doTheNeedful
|
|
235
251
|
from mapFolding.dataBaskets import MatrixMeandersState as State
|
|
236
252
|
|
|
@@ -291,7 +307,7 @@ def NOTcountingFolds(oeisID: str, oeis_n: int, flow: str | None = None
|
|
|
291
307
|
from mapFolding.syntheticModules.A007822.algorithm import doTheNeedful
|
|
292
308
|
symmetricState = doTheNeedful(symmetricState)
|
|
293
309
|
|
|
294
|
-
countTotal = symmetricState.
|
|
310
|
+
countTotal = symmetricState.symmetricFolds
|
|
295
311
|
case _:
|
|
296
312
|
matched_oeisID = False
|
|
297
313
|
|
mapFolding/dataBaskets.py
CHANGED
|
@@ -21,12 +21,9 @@ integrity throughout the recursive analysis while providing the structured data
|
|
|
21
21
|
access patterns that enable efficient result persistence and retrieval.
|
|
22
22
|
"""
|
|
23
23
|
from mapFolding import (
|
|
24
|
-
Array1DElephino, Array1DLeavesTotal,
|
|
25
|
-
|
|
26
|
-
from numpy.typing import NDArray
|
|
27
|
-
from typing import TypeAlias
|
|
24
|
+
Array1DElephino, Array1DLeavesTotal, Array3DLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal,
|
|
25
|
+
getConnectionGraph, getLeavesTotal, makeDataContainer)
|
|
28
26
|
import dataclasses
|
|
29
|
-
import numpy
|
|
30
27
|
|
|
31
28
|
@dataclasses.dataclass(slots=True)
|
|
32
29
|
class MapFoldingState:
|
|
@@ -203,7 +200,7 @@ class SymmetricFoldsState:
|
|
|
203
200
|
mapShape: tuple[DatatypeLeavesTotal, ...] = dataclasses.field(init=True, metadata={'elementConstructor': 'DatatypeLeavesTotal'})
|
|
204
201
|
"""Dimensions of the map being analyzed for folding patterns."""
|
|
205
202
|
|
|
206
|
-
|
|
203
|
+
symmetricFolds: DatatypeFoldsTotal = dataclasses.field(default=DatatypeFoldsTotal(0), metadata={'theCountingIdentifier': True})
|
|
207
204
|
"""Current count of symmetric folds."""
|
|
208
205
|
|
|
209
206
|
gap1ndex: DatatypeElephino = DatatypeElephino(0) # noqa: RUF009
|
|
@@ -237,12 +234,12 @@ class SymmetricFoldsState:
|
|
|
237
234
|
leafComparison: Array1DLeavesTotal = dataclasses.field(default=None, init=True, metadata={'dtype': Array1DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportAssignmentType, reportAttributeAccessIssue, reportUnknownMemberType]
|
|
238
235
|
"""Array for finding symmetric folds."""
|
|
239
236
|
|
|
240
|
-
arrayGroupOfFolds: Array2DLeavesTotal = dataclasses.field(init=False, metadata={'dtype': Array2DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
|
|
241
237
|
connectionGraph: Array3DLeavesTotal = dataclasses.field(init=False, metadata={'dtype': Array3DLeavesTotal.__args__[1].__args__[0]}) # pyright: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
|
|
242
238
|
"""Unchanging array representing connections between all leaves."""
|
|
243
239
|
dimensionsTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
|
|
244
240
|
"""Unchanging total number of dimensions in the map."""
|
|
245
|
-
|
|
241
|
+
indices: list[list[tuple[int, int]]] = dataclasses.field(init=False)
|
|
242
|
+
"""Precomputed index pairs for symmetric fold checking."""
|
|
246
243
|
leavesTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
|
|
247
244
|
"""Unchanging total number of leaves in the map."""
|
|
248
245
|
|
|
@@ -259,12 +256,9 @@ class SymmetricFoldsState:
|
|
|
259
256
|
self.leavesTotal = DatatypeLeavesTotal(getLeavesTotal(self.mapShape))
|
|
260
257
|
|
|
261
258
|
leavesTotalAsInt = int(self.leavesTotal)
|
|
262
|
-
|
|
263
259
|
self.connectionGraph = getConnectionGraph(self.mapShape, leavesTotalAsInt, self.__dataclass_fields__['connectionGraph'].metadata['dtype'])
|
|
264
260
|
|
|
265
|
-
self.
|
|
266
|
-
self.indicesArrayGroupOfFolds[..., leavesTotalAsInt // 2:None] = self.indicesArrayGroupOfFolds[..., leavesTotalAsInt - 1: leavesTotalAsInt - leavesTotalAsInt // 2 - 1: -1]
|
|
267
|
-
self.arrayGroupOfFolds = numpy.zeros_like(self.indicesArrayGroupOfFolds)
|
|
261
|
+
self.indices = [[((index + folding) % (self.leavesTotal+1), (-2-index + folding) % (self.leavesTotal+1)) for index in range(self.leavesTotal//2)] for folding in range(self.leavesTotal + 1)]
|
|
268
262
|
|
|
269
263
|
if self.dimensionsUnconstrained is None: self.dimensionsUnconstrained = DatatypeLeavesTotal(int(self.dimensionsTotal)) # pyright: ignore[reportUnnecessaryComparison] # noqa: E701
|
|
270
264
|
if self.gapsWhere is None: self.gapsWhere = makeDataContainer(leavesTotalAsInt * leavesTotalAsInt + 1, self.__dataclass_fields__['gapsWhere'].metadata['dtype']) # pyright: ignore[reportUnnecessaryComparison] # noqa: E701
|
|
@@ -398,6 +392,7 @@ class MatrixMeandersState:
|
|
|
398
392
|
"""The index of the meanders problem being solved."""
|
|
399
393
|
oeisID: str
|
|
400
394
|
"""'A000682', semi-meanders, or 'A005316', meanders."""
|
|
395
|
+
|
|
401
396
|
boundary: int
|
|
402
397
|
"""The algorithm analyzes `n` boundaries starting at `boundary = n - 1`."""
|
|
403
398
|
dictionaryMeanders: dict[int, int]
|
|
@@ -408,14 +403,19 @@ class MatrixMeandersState:
|
|
|
408
403
|
bitWidth: int = 0
|
|
409
404
|
"""At the start of an iteration enumerated by `boundary`, the number of bits of the largest value `arcCode`. The
|
|
410
405
|
`dataclass` computes a `property` from `bitWidth`."""
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
406
|
+
bitsLocator: int = 0
|
|
407
|
+
"""An odd-parity bit-mask with `bitWidth` bits."""
|
|
408
|
+
MAXIMUMarcCode: int = 0
|
|
409
|
+
"""The maximum value of `arcCode` for the current iteration of the transfer matrix."""
|
|
410
|
+
|
|
411
|
+
def reduceBoundary(self) -> None:
|
|
412
|
+
"""Prepare for the next iteration of the transfer matrix algorithm by reducing `boundary` by 1 and updating related fields."""
|
|
413
|
+
self.boundary -= 1
|
|
414
|
+
self.setBitWidth()
|
|
415
|
+
self.setBitsLocator()
|
|
416
|
+
self.setMAXIMUMarcCode()
|
|
417
|
+
|
|
418
|
+
def setBitsLocator(self) -> None:
|
|
419
419
|
"""Compute an odd-parity bit-mask with `bitWidth` bits.
|
|
420
420
|
|
|
421
421
|
Notes
|
|
@@ -429,60 +429,19 @@ class MatrixMeandersState:
|
|
|
429
429
|
odd numbers from even numbers, so I avoid using "odd" and "even" in the names of these bit-masks.
|
|
430
430
|
|
|
431
431
|
"""
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
@dataclasses.dataclass(slots=True)
|
|
435
|
-
class MatrixMeandersNumPyState(MatrixMeandersState):
|
|
436
|
-
"""Hold the state of a meanders transfer matrix algorithm computation."""
|
|
432
|
+
self.bitsLocator = sum(1 << one for one in range(0, self.bitWidth, 2))
|
|
437
433
|
|
|
438
|
-
|
|
439
|
-
|
|
434
|
+
def setBitWidth(self) -> None:
|
|
435
|
+
"""Set `bitWidth` from the current `dictionaryMeanders`."""
|
|
436
|
+
self.bitWidth = max(self.dictionaryMeanders.keys()).bit_length()
|
|
440
437
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
datatypeArcCode: TypeAlias = numpy.uint64 # noqa: UP040
|
|
445
|
-
"""The fixed-size integer type used to store `arcCode`."""
|
|
446
|
-
datatypeCrossings: TypeAlias = numpy.uint64 # noqa: UP040
|
|
447
|
-
"""The fixed-size integer type used to store `crossings`."""
|
|
448
|
-
|
|
449
|
-
indexTarget: int = 0
|
|
450
|
-
"""What is being indexed depends on the algorithm flavor."""
|
|
438
|
+
def setMAXIMUMarcCode(self) -> None:
|
|
439
|
+
"""Compute the maximum value of `arcCode` for the current iteration of the transfer matrix."""
|
|
440
|
+
self.MAXIMUMarcCode = 1 << (2 * self.boundary + 4)
|
|
451
441
|
|
|
452
442
|
def __post_init__(self) -> None:
|
|
453
443
|
"""Post init."""
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
_offsetNecessary: int = 3 # For example, `bitsZulu << 3`.
|
|
458
|
-
_offsetSafety: int = 1 # I don't have mathematical proof of how many extra bits I need.
|
|
459
|
-
_offset: int = _offsetNecessary + _offsetSafety
|
|
460
|
-
|
|
461
|
-
self.bitWidthLimitArcCode = _bitWidthOfFixedSizeInteger - _offset
|
|
462
|
-
|
|
463
|
-
del _bitWidthOfFixedSizeInteger, _offsetNecessary, _offsetSafety, _offset
|
|
464
|
-
|
|
465
|
-
if self.bitWidthLimitCrossings is None:
|
|
466
|
-
_bitWidthOfFixedSizeInteger: int = numpy.dtype(self.datatypeCrossings).itemsize * 8 # bits
|
|
467
|
-
|
|
468
|
-
_offsetNecessary: int = 0 # I don't know of any.
|
|
469
|
-
_offsetEstimation: int = 3 # See reference directory.
|
|
470
|
-
_offsetSafety: int = 1
|
|
471
|
-
_offset: int = _offsetNecessary + _offsetEstimation + _offsetSafety
|
|
472
|
-
|
|
473
|
-
self.bitWidthLimitCrossings = _bitWidthOfFixedSizeInteger - _offset
|
|
474
|
-
|
|
475
|
-
del _bitWidthOfFixedSizeInteger, _offsetNecessary, _offsetEstimation, _offsetSafety, _offset
|
|
476
|
-
|
|
477
|
-
def makeDictionary(self) -> None:
|
|
478
|
-
"""Convert from NumPy `ndarray` (*Num*erical *Py*thon *n-d*imensional array) to Python `dict` (*dict*ionary)."""
|
|
479
|
-
self.dictionaryMeanders = {int(key): int(value) for key, value in zip(self.arrayArcCodes, self.arrayCrossings, strict=True)}
|
|
480
|
-
self.arrayArcCodes = numpy.empty((0,), dtype=self.datatypeArcCode)
|
|
481
|
-
self.arrayCrossings = numpy.empty((0,), dtype=self.datatypeCrossings)
|
|
444
|
+
self.setBitWidth()
|
|
445
|
+
self.setBitsLocator()
|
|
446
|
+
self.setMAXIMUMarcCode()
|
|
482
447
|
|
|
483
|
-
def makeArray(self) -> None:
|
|
484
|
-
"""Convert from Python `dict` (*dict*ionary) to NumPy `ndarray` (*Num*erical *Py*thon *n-d*imensional array)."""
|
|
485
|
-
self.arrayArcCodes = numpy.array(list(self.dictionaryMeanders.keys()), dtype=self.datatypeArcCode)
|
|
486
|
-
self.arrayCrossings = numpy.array(list(self.dictionaryMeanders.values()), dtype=self.datatypeCrossings)
|
|
487
|
-
self.bitWidth = int(self.arrayArcCodes.max()).bit_length()
|
|
488
|
-
self.dictionaryMeanders = {}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
1
|
+
"""Ported from the Java version by Sean A. Irvine.
|
|
2
|
+
|
|
3
3
|
https://github.com/archmageirvine/joeis/blob/80e3e844b11f149704acbab520bc3a3a25ac34ff/src/irvine/oeis/a001/A001415.java
|
|
4
4
|
|
|
5
5
|
This implementation is a Python version of a Java implementation of Lunnon's algorithm by Sean A. Irvine.
|
|
@@ -9,7 +9,7 @@ Key characteristics:
|
|
|
9
9
|
- A procedural paradigm more similar to Lunnon and unlike Irvine's object-oriented implementation.
|
|
10
10
|
- Only primitive Python data structures.
|
|
11
11
|
|
|
12
|
-
Citation: https://github.com/hunterhogan/mapFolding/blob/134f2e6ecdf59fb6f6829c775475544a6aaaa800/citations/jOEIS.
|
|
12
|
+
Citation: https://github.com/hunterhogan/mapFolding/blob/134f2e6ecdf59fb6f6829c775475544a6aaaa800/citations/jOEIS.bib
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
def foldings(p: list[int], res: int = 0, mod: int = 0) -> int:
|
|
@@ -360,7 +360,7 @@ def doTheNeedful(n: int, dictionaryCurveLocations: dict[int, int]) -> int:
|
|
|
360
360
|
--------------
|
|
361
361
|
|
|
362
362
|
As first computed by Iwan Jensen in 2000, A000682(41) = 6664356253639465480.
|
|
363
|
-
Citation: https://github.com/hunterhogan/mapFolding/blob/main/citations/Jensen.
|
|
363
|
+
Citation: https://github.com/hunterhogan/mapFolding/blob/main/citations/Jensen.bib
|
|
364
364
|
See also https://oeis.org/A000682
|
|
365
365
|
|
|
366
366
|
I'm sure you instantly observed that A000682(41) = (6664356253639465480).bit_length() = 63 bits. And A005316(44) =
|
|
@@ -34,7 +34,7 @@ def _threadDoesSomething() -> None:
|
|
|
34
34
|
break
|
|
35
35
|
state = _filterAsymmetricFolds(state)
|
|
36
36
|
with LOCKsymmetricFoldsTotal:
|
|
37
|
-
symmetricFoldsTotal += state.
|
|
37
|
+
symmetricFoldsTotal += state.symmetricFolds
|
|
38
38
|
|
|
39
39
|
def _filterAsymmetricFolds(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
40
40
|
"""Add real function during generation; the signature is here to preview its interactions with the module."""
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"""addSymmetryCheckAsynchronous."""
|
|
2
|
-
from astToolkit import Be, Grab, identifierDotAttribute,
|
|
2
|
+
from astToolkit import Be, Grab, identifierDotAttribute, Make, NodeChanger, NodeTourist, Then
|
|
3
|
+
from astToolkit.containers import LedgerOfImports
|
|
4
|
+
from astToolkit.transformationTools import write_astModule
|
|
3
5
|
from hunterMakesPy import raiseIfNone
|
|
4
6
|
from mapFolding import packageSettings
|
|
5
7
|
from mapFolding.someAssemblyRequired import defaultA007822, IfThis
|
|
6
8
|
from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import ExprCallFilterAsymmetricFoldsState
|
|
7
|
-
from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename
|
|
9
|
+
from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename
|
|
8
10
|
from pathlib import PurePath
|
|
9
11
|
import ast
|
|
10
12
|
|
|
@@ -85,7 +87,7 @@ def addSymmetryCheckAsynchronous(astModule: ast.Module, identifierModule: str, i
|
|
|
85
87
|
|
|
86
88
|
pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule)
|
|
87
89
|
|
|
88
|
-
write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
|
|
90
|
+
write_astModule(astModule, pathFilename, identifierPackage=packageSettings.identifierPackage)
|
|
89
91
|
|
|
90
92
|
return pathFilename
|
|
91
93
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""addSymmetryCheck."""
|
|
2
2
|
from astToolkit import (
|
|
3
|
-
Be, Grab, identifierDotAttribute,
|
|
3
|
+
Be, Grab, identifierDotAttribute, Make, NodeChanger, NodeTourist, parsePathFilename2astModule, Then)
|
|
4
|
+
from astToolkit.containers import LedgerOfImports
|
|
5
|
+
from astToolkit.transformationTools import write_astModule
|
|
4
6
|
from hunterMakesPy import raiseIfNone
|
|
5
7
|
from mapFolding import packageSettings
|
|
6
8
|
from mapFolding.someAssemblyRequired import default, defaultA007822, IfThis
|
|
@@ -8,7 +10,7 @@ from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import (
|
|
|
8
10
|
A007822adjustFoldsTotal, A007822incrementCount, FunctionDef_filterAsymmetricFolds)
|
|
9
11
|
from mapFolding.someAssemblyRequired.makingModules_count import makeTheorem2, numbaOnTheorem2, trimTheorem2
|
|
10
12
|
from mapFolding.someAssemblyRequired.makingModules_doTheNeedful import makeInitializeState
|
|
11
|
-
from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename
|
|
13
|
+
from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename
|
|
12
14
|
from pathlib import PurePath
|
|
13
15
|
import ast
|
|
14
16
|
|
|
@@ -43,7 +45,21 @@ def addSymmetryCheck(astModule: ast.Module, identifierModule: str, identifierCal
|
|
|
43
45
|
|
|
44
46
|
pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule)
|
|
45
47
|
|
|
46
|
-
write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
|
|
48
|
+
write_astModule(astModule, pathFilename, identifierPackage=packageSettings.identifierPackage)
|
|
49
|
+
|
|
50
|
+
return pathFilename
|
|
51
|
+
|
|
52
|
+
def _numbaOnTheorem2(astModule: ast.Module, identifierModule: str, identifierCallable: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
|
|
53
|
+
pathFilename: PurePath = numbaOnTheorem2(astModule, identifierModule, identifierCallable, logicalPathInfix, sourceCallableDispatcher)
|
|
54
|
+
astModule = parsePathFilename2astModule(pathFilename)
|
|
55
|
+
|
|
56
|
+
NodeChanger(Be.AnnAssign.valueIs(IfThis.isAttributeNamespaceIdentifier(defaultA007822['variable']['stateInstance'], 'indices'))
|
|
57
|
+
, lambda node: Grab.valueAttribute(Then.replaceWith(Make.Call(Make.Name('List'), [raiseIfNone(node.value)])))(node)
|
|
58
|
+
).visit(astModule)
|
|
59
|
+
|
|
60
|
+
astModule.body.insert(0, Make.ImportFrom('numba.typed', [Make.alias('List')]))
|
|
61
|
+
|
|
62
|
+
write_astModule(astModule, pathFilename, identifierPackage=packageSettings.identifierPackage)
|
|
47
63
|
|
|
48
64
|
return pathFilename
|
|
49
65
|
|
|
@@ -55,18 +71,18 @@ def makeA007822Modules() -> None:
|
|
|
55
71
|
|
|
56
72
|
astModule = getModule(logicalPathInfix=defaultA007822['logicalPath']['synthetic'], identifierModule=defaultA007822['module']['algorithm'])
|
|
57
73
|
makeInitializeState(astModule, defaultA007822['module']['initializeState']
|
|
58
|
-
, defaultA007822['function']['initializeState'], defaultA007822['logicalPath']['synthetic'], None)
|
|
74
|
+
, defaultA007822['function']['initializeState'], defaultA007822['logicalPath']['synthetic'], None, identifiers=defaultA007822)
|
|
59
75
|
|
|
60
76
|
astModule = getModule(logicalPathInfix=defaultA007822['logicalPath']['synthetic'], identifierModule=defaultA007822['module']['algorithm'])
|
|
61
77
|
pathFilename = makeTheorem2(astModule, 'theorem2', defaultA007822['function']['counting']
|
|
62
|
-
, defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
|
|
78
|
+
, defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'], identifiers=defaultA007822)
|
|
63
79
|
|
|
64
80
|
astModule = parsePathFilename2astModule(pathFilename)
|
|
65
81
|
pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', defaultA007822['function']['counting']
|
|
66
82
|
, defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
|
|
67
83
|
|
|
68
84
|
astModule = parsePathFilename2astModule(pathFilename)
|
|
69
|
-
pathFilename =
|
|
85
|
+
pathFilename = _numbaOnTheorem2(astModule, 'theorem2Numba', defaultA007822['function']['counting']
|
|
70
86
|
, defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
|
|
71
87
|
|
|
72
88
|
if __name__ == '__main__':
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"""Configuration by dataclass."""
|
|
2
2
|
|
|
3
|
-
from astToolkit import identifierDotAttribute,
|
|
3
|
+
from astToolkit import identifierDotAttribute, parseLogicalPath2astModule
|
|
4
|
+
from astToolkit.containers import IngredientsFunction, IngredientsModule, LedgerOfImports
|
|
4
5
|
from astToolkit.transformationTools import pythonCode2ast_expr
|
|
5
6
|
from hunterMakesPy import autoDecodingRLE
|
|
6
|
-
# TODO '
|
|
7
|
+
# TODO 'The____' identifiers are a vestigial semiotic system. Do I still need to import `asname`? If so, would different
|
|
7
8
|
# identifiers better integrate into the current semiotics?
|
|
8
9
|
from mapFolding import (
|
|
9
10
|
DatatypeElephino as TheDatatypeElephino, DatatypeFoldsTotal as TheDatatypeFoldsTotal,
|
|
10
11
|
DatatypeLeavesTotal as TheDatatypeLeavesTotal, getPathFilenameFoldsTotal, getPathRootJobDEFAULT, packageSettings)
|
|
11
|
-
from mapFolding.dataBaskets import MapFoldingState
|
|
12
|
-
from mapFolding.someAssemblyRequired import DatatypeConfiguration, default
|
|
13
|
-
from mapFolding.someAssemblyRequired._toolkitContainers import ShatteredDataclass
|
|
12
|
+
from mapFolding.dataBaskets import MapFoldingState, SymmetricFoldsState
|
|
13
|
+
from mapFolding.someAssemblyRequired import DatatypeConfiguration, default, ShatteredDataclass
|
|
14
14
|
from mapFolding.someAssemblyRequired.transformationTools import shatter_dataclassesDOTdataclass
|
|
15
15
|
from pathlib import Path, PurePosixPath
|
|
16
16
|
from typing import cast
|
|
@@ -22,18 +22,8 @@ class RecipeJobTheorem2:
|
|
|
22
22
|
"""Configuration recipe for generating map folding computation jobs.
|
|
23
23
|
|
|
24
24
|
This dataclass serves as the central configuration hub for the code transformation
|
|
25
|
-
assembly line that converts generic map folding algorithms into
|
|
26
|
-
specialized
|
|
27
|
-
for source code analysis, target file generation, datatype mapping, and compilation
|
|
28
|
-
optimization settings.
|
|
29
|
-
|
|
30
|
-
The transformation process operates by extracting functions from source modules,
|
|
31
|
-
embedding concrete parameter values, eliminating dead code paths, and generating
|
|
32
|
-
standalone Python modules optimized for specific map dimensions.
|
|
33
|
-
|
|
34
|
-
The recipe maintains both source configuration (where to find the generic algorithm)
|
|
35
|
-
and target configuration (where to write the optimized module), along with the
|
|
36
|
-
computational state that provides concrete values for the transformation process.
|
|
25
|
+
assembly line that converts generic map folding algorithms into optimized,
|
|
26
|
+
specialized modules.
|
|
37
27
|
|
|
38
28
|
Attributes
|
|
39
29
|
----------
|
|
@@ -87,7 +77,7 @@ class RecipeJobTheorem2:
|
|
|
87
77
|
Type alias for leaf count datatype.
|
|
88
78
|
"""
|
|
89
79
|
|
|
90
|
-
state: MapFoldingState
|
|
80
|
+
state: MapFoldingState | SymmetricFoldsState
|
|
91
81
|
"""The map folding computation state containing dimensions and initial values."""
|
|
92
82
|
foldsTotalEstimated: int = 0
|
|
93
83
|
"""Estimated total number of folds for progress tracking."""
|
|
@@ -129,7 +119,7 @@ class RecipeJobTheorem2:
|
|
|
129
119
|
"""Logical path root; probably corresponds to physical filesystem directory."""
|
|
130
120
|
moduleIdentifier: str = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
|
|
131
121
|
"""Target module identifier."""
|
|
132
|
-
|
|
122
|
+
identifierCallable: str = identifierCallableSource
|
|
133
123
|
"""Name of the counting function in generated module."""
|
|
134
124
|
identifierDataclass: str | None = sourceDataclassIdentifier
|
|
135
125
|
"""Target dataclass identifier."""
|
|
@@ -211,12 +201,12 @@ class RecipeJobTheorem2:
|
|
|
211
201
|
"""
|
|
212
202
|
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(self.state.mapShape))
|
|
213
203
|
|
|
214
|
-
if self.moduleIdentifier is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
215
|
-
self.moduleIdentifier = pathFilenameFoldsTotal.stem
|
|
216
|
-
|
|
217
204
|
if self.pathFilenameFoldsTotal is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
218
205
|
self.pathFilenameFoldsTotal = pathFilenameFoldsTotal
|
|
219
206
|
|
|
207
|
+
if self.moduleIdentifier is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
208
|
+
self.moduleIdentifier = self.pathFilenameFoldsTotal.stem
|
|
209
|
+
|
|
220
210
|
if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.identifierDataclass and self.identifierDataclassInstance: # pyright: ignore[reportUnnecessaryComparison]
|
|
221
211
|
self.shatteredDataclass = shatter_dataclassesDOTdataclass(self.logicalPathModuleDataclass, self.identifierDataclass, self.identifierDataclassInstance)
|
|
222
212
|
|
|
@@ -245,11 +235,11 @@ def moveShatteredDataclass_arg2body(identifier: str, job: RecipeJobTheorem2) ->
|
|
|
245
235
|
Ima___Assign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[identifier]
|
|
246
236
|
match elementConstructor:
|
|
247
237
|
case 'scalar':
|
|
248
|
-
cast(
|
|
238
|
+
cast(ast.Constant, cast(ast.Call, Ima___Assign.value).args[0]).value = int(eval(f"job.state.{identifier}")) # noqa: S307
|
|
249
239
|
case 'array':
|
|
250
240
|
dataAsStrRLE: str = autoDecodingRLE(eval(f"job.state.{identifier}"), assumeAddSpaces=True) # noqa: S307
|
|
251
241
|
dataAs_ast_expr: ast.expr = pythonCode2ast_expr(dataAsStrRLE)
|
|
252
|
-
cast(
|
|
242
|
+
cast(ast.Call, Ima___Assign.value).args = [dataAs_ast_expr]
|
|
253
243
|
case _:
|
|
254
244
|
pass
|
|
255
245
|
return Ima___Assign
|
|
@@ -74,6 +74,7 @@ calculations through the strategic application of compiler optimization techniqu
|
|
|
74
74
|
|
|
75
75
|
from mapFolding.someAssemblyRequired.infoBooth import (
|
|
76
76
|
default as default,
|
|
77
|
+
Default as Default,
|
|
77
78
|
defaultA007822 as defaultA007822,
|
|
78
79
|
dictionaryEstimatesMapFolding as dictionaryEstimatesMapFolding,
|
|
79
80
|
)
|
|
@@ -25,7 +25,8 @@ to low-level optimized functions while maintaining semantic equivalence and type
|
|
|
25
25
|
the compilation process.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
from astToolkit import Be, DOT, identifierDotAttribute,
|
|
28
|
+
from astToolkit import Be, DOT, identifierDotAttribute, Make, NodeTourist, Then
|
|
29
|
+
from astToolkit.containers import LedgerOfImports
|
|
29
30
|
from collections.abc import Callable
|
|
30
31
|
from copy import deepcopy
|
|
31
32
|
from hunterMakesPy import raiseIfNone
|
|
@@ -220,7 +221,7 @@ class DeReConstructField2ast: # slots?
|
|
|
220
221
|
self.ast_keyword_field__field = Make.keyword(self.name, self.astName)
|
|
221
222
|
self.ast_nameDOTname = Make.Attribute(Make.Name(dataclassesDOTdataclassInstanceIdentifier), self.name)
|
|
222
223
|
|
|
223
|
-
self.astAnnotation = cast(
|
|
224
|
+
self.astAnnotation = cast(ast.Name, raiseIfNone(NodeTourist(
|
|
224
225
|
findThis = Be.AnnAssign.targetIs(IfThis.isNameIdentifier(self.name))
|
|
225
226
|
, doThat = Then.extractIt(DOT.annotation)
|
|
226
227
|
).captureLastMatch(dataclassClassDef)))
|
|
@@ -251,8 +252,9 @@ class DeReConstructField2ast: # slots?
|
|
|
251
252
|
self.astAnnAssignConstructor = Make.AnnAssign(self.astName, self.astAnnotation, Make.Call(self.astAnnotation, [Make.Constant(-1)]))
|
|
252
253
|
self.Z0Z_hack = (self.astAnnAssignConstructor, 'scalar')
|
|
253
254
|
elif isinstance(self.astAnnotation, ast.Subscript):
|
|
254
|
-
elementConstructor: str = self.metadata
|
|
255
|
-
|
|
255
|
+
elementConstructor: str = self.metadata.get('elementConstructor', 'generic')
|
|
256
|
+
if elementConstructor != 'generic':
|
|
257
|
+
self.ledger.addImportFrom_asStr(dataclassesDOTdataclassLogicalPathModule, elementConstructor)
|
|
256
258
|
takeTheTuple = deepcopy(self.astAnnotation.slice)
|
|
257
259
|
self.astAnnAssignConstructor = Make.AnnAssign(self.astName, self.astAnnotation, takeTheTuple)
|
|
258
260
|
self.Z0Z_hack = (self.astAnnAssignConstructor, elementConstructor)
|
|
@@ -44,6 +44,7 @@ default = Default(
|
|
|
44
44
|
},
|
|
45
45
|
module = {
|
|
46
46
|
'algorithm': 'daoOfMapFolding',
|
|
47
|
+
'dataBasket': 'dataBaskets',
|
|
47
48
|
'initializeState': 'initializeState',
|
|
48
49
|
},
|
|
49
50
|
variable = {
|
|
@@ -62,5 +63,5 @@ defaultA007822['logicalPath']['assembly'] = 'someAssemblyRequired.A007822'
|
|
|
62
63
|
defaultA007822['logicalPath']['synthetic'] += '.A007822'
|
|
63
64
|
defaultA007822['module']['algorithm'] = 'algorithm'
|
|
64
65
|
defaultA007822['module']['asynchronous'] = 'asynchronous'
|
|
65
|
-
|
|
66
|
+
defaultA007822['variable']['counting'] = 'symmetricFolds'
|
|
66
67
|
defaultA007822['variable']['stateDataclass'] = 'SymmetricFoldsState'
|