mapFolding 0.16.0__py3-none-any.whl → 0.16.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.
- easyRun/A000682.py +25 -0
- easyRun/A005316.py +20 -0
- easyRun/NOTcountingFolds.py +36 -0
- easyRun/__init__.py +0 -0
- easyRun/countFolds.py +41 -0
- easyRun/meanders.py +69 -0
- mapFolding/__init__.py +8 -51
- mapFolding/_dataPacking.py +68 -0
- mapFolding/_theSSOT.py +33 -37
- mapFolding/_theTypes.py +21 -4
- mapFolding/algorithms/matrixMeanders.py +86 -517
- mapFolding/algorithms/matrixMeandersBeDry.py +182 -0
- mapFolding/algorithms/matrixMeandersNumPy.py +333 -0
- mapFolding/algorithms/matrixMeandersPandas.py +334 -0
- mapFolding/algorithms/oeisIDbyFormula.py +50 -29
- mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +51 -29
- mapFolding/basecamp.py +167 -206
- mapFolding/beDRY.py +2 -30
- mapFolding/dataBaskets.py +75 -49
- mapFolding/oeis.py +11 -32
- mapFolding/reference/A000682facts.py +787 -652
- mapFolding/reference/A005316facts.py +961 -3
- mapFolding/reference/matrixMeandersAnalysis/prefixNotationNotes.py +15 -0
- mapFolding/reference/matrixMeandersAnalysis/signatures.py +2030 -0
- mapFolding/reference/meandersDumpingGround/A005316JavaPort.py +1 -1
- mapFolding/reference/meandersDumpingGround/A005316imperative.py +1 -1
- mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +424 -0
- mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +3 -4
- mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +103 -29
- mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +18 -14
- mapFolding/someAssemblyRequired/RecipeJob.py +2 -2
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +7 -6
- mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +3 -4
- mapFolding/someAssemblyRequired/makingModules_count.py +88 -87
- mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +10 -9
- mapFolding/someAssemblyRequired/mapFolding/makeMapFoldingModules.py +3 -3
- mapFolding/someAssemblyRequired/meanders/__init__.py +0 -0
- mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +63 -0
- mapFolding/someAssemblyRequired/toolkitMakeModules.py +37 -37
- mapFolding/someAssemblyRequired/transformationTools.py +8 -8
- mapFolding/syntheticModules/A007822/algorithm.py +3 -3
- mapFolding/syntheticModules/A007822/algorithmNumba.py +1 -2
- mapFolding/syntheticModules/A007822/asynchronous.py +6 -4
- mapFolding/syntheticModules/A007822/asynchronousAnnex.py +5 -7
- mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +70 -0
- mapFolding/syntheticModules/A007822/asynchronousNumba.py +79 -0
- mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +15 -3
- mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +12 -3
- mapFolding/syntheticModules/A007822/initializeState.py +1 -2
- mapFolding/syntheticModules/A007822/theorem2.py +7 -2
- mapFolding/syntheticModules/A007822/theorem2Numba.py +31 -4
- mapFolding/syntheticModules/A007822/theorem2Trimmed.py +8 -3
- mapFolding/syntheticModules/countParallelNumba.py +5 -2
- mapFolding/syntheticModules/dataPacking.py +1 -1
- mapFolding/syntheticModules/dataPackingA007822.py +92 -26
- mapFolding/syntheticModules/meanders/__init__.py +1 -0
- mapFolding/syntheticModules/meanders/bigInt.py +52 -0
- mapFolding/syntheticModules/theorem2.py +6 -0
- mapFolding/syntheticModules/theorem2Numba.py +8 -2
- mapFolding/syntheticModules/theorem2Trimmed.py +6 -0
- mapFolding/tests/conftest.py +28 -13
- mapFolding/tests/test_computations.py +68 -61
- mapFolding/tests/test_oeis.py +6 -6
- mapFolding/zCuzDocStoopid/__init__.py +4 -1
- mapFolding/zCuzDocStoopid/makeDocstrings.py +35 -28
- mapfolding-0.16.2.dist-info/METADATA +99 -0
- mapfolding-0.16.2.dist-info/RECORD +115 -0
- {mapfolding-0.16.0.dist-info → mapfolding-0.16.2.dist-info}/top_level.txt +1 -0
- mapFolding/algorithms/getBucketsTotal.py +0 -137
- mapFolding/reference/matrixMeandersAnalysis/evenEven.py +0 -144
- mapFolding/reference/matrixMeandersAnalysis/oddEven.py +0 -54
- mapFolding/trim_memory.py +0 -62
- mapfolding-0.16.0.dist-info/METADATA +0 -85
- mapfolding-0.16.0.dist-info/RECORD +0 -100
- {mapfolding-0.16.0.dist-info → mapfolding-0.16.2.dist-info}/WHEEL +0 -0
- {mapfolding-0.16.0.dist-info → mapfolding-0.16.2.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.16.0.dist-info → mapfolding-0.16.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Be DRY."""
|
|
2
|
+
from functools import cache
|
|
3
|
+
from hunterMakesPy import raiseIfNone
|
|
4
|
+
from mapFolding.dataBaskets import MatrixMeandersNumPyState
|
|
5
|
+
from mapFolding.reference.A000682facts import A000682_n_boundary_buckets
|
|
6
|
+
from mapFolding.reference.A005316facts import A005316_n_boundary_buckets
|
|
7
|
+
import numpy
|
|
8
|
+
import pandas
|
|
9
|
+
|
|
10
|
+
"""Goals:
|
|
11
|
+
- Extreme abstraction.
|
|
12
|
+
- Find operations with latent intermediate arrays and make the intermediate array explicit.
|
|
13
|
+
- Reduce or eliminate intermediate arrays and selector arrays.
|
|
14
|
+
- Write formulas in prefix notation.
|
|
15
|
+
- For each formula, find an equivalent prefix notation formula that never uses the same variable as input more than once: that
|
|
16
|
+
would allow the evaluation of the expression with only a single stack, which saves memory.
|
|
17
|
+
- Standardize code as much as possible to create duplicate code.
|
|
18
|
+
- Convert duplicate code to procedures.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def areIntegersWide(state: MatrixMeandersNumPyState, *, dataframe: pandas.DataFrame | None = None, fixedSizeMAXIMUMarcCode: bool = False) -> bool:
|
|
22
|
+
"""Check if the largest values are wider than the maximum limits.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
state : MatrixMeandersState
|
|
27
|
+
The current state of the computation, including `dictionaryMeanders`.
|
|
28
|
+
dataframe : pandas.DataFrame | None = None
|
|
29
|
+
Optional DataFrame containing 'analyzed' and 'crossings' columns. If provided, use this instead of `state.dictionaryMeanders`.
|
|
30
|
+
fixedSizeMAXIMUMarcCode : bool = False
|
|
31
|
+
Set this to `True` if you cast `state.MAXIMUMarcCode` to the same fixed size integer type as `state.datatypeArcCode`.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
wider : bool
|
|
36
|
+
True if at least one integer is too wide.
|
|
37
|
+
|
|
38
|
+
Notes
|
|
39
|
+
-----
|
|
40
|
+
Casting `state.MAXIMUMarcCode` to a fixed-size 64-bit unsigned integer might cause the flow to be a little more
|
|
41
|
+
complicated because `MAXIMUMarcCode` is usually 1-bit larger than the `max(arcCode)` value.
|
|
42
|
+
|
|
43
|
+
If you start the algorithm with very large `arcCode` in your `dictionaryMeanders` (*i.e.,* A000682), then the
|
|
44
|
+
flow will go to a function that does not use fixed size integers. When the integers are below the limits (*e.g.,*
|
|
45
|
+
`bitWidthArcCodeMaximum`), the flow will go to a function with fixed size integers. In that case, casting
|
|
46
|
+
`MAXIMUMarcCode` to a fixed size merely delays the transition from one function to the other by one iteration.
|
|
47
|
+
|
|
48
|
+
If you start with small values in `dictionaryMeanders`, however, then the flow goes to the function with fixed size
|
|
49
|
+
integers and usually stays there until `crossings` is huge, which is near the end of the computation. If you cast
|
|
50
|
+
`MAXIMUMarcCode` into a 64-bit unsigned integer, however, then around `state.boundary == 28`, the bit width of
|
|
51
|
+
`MAXIMUMarcCode` might exceed the limit. That will cause the flow to go to the function that does not have fixed size
|
|
52
|
+
integers for a few iterations before returning to the function with fixed size integers.
|
|
53
|
+
"""
|
|
54
|
+
if dataframe is not None:
|
|
55
|
+
arcCodeWidest = int(dataframe['analyzed'].max()).bit_length()
|
|
56
|
+
crossingsWidest = int(dataframe['crossings'].max()).bit_length()
|
|
57
|
+
elif not state.dictionaryMeanders:
|
|
58
|
+
arcCodeWidest = int(state.arrayArcCodes.max()).bit_length()
|
|
59
|
+
crossingsWidest = int(state.arrayCrossings.max()).bit_length()
|
|
60
|
+
else:
|
|
61
|
+
arcCodeWidest: int = max(state.dictionaryMeanders.keys()).bit_length()
|
|
62
|
+
crossingsWidest: int = max(state.dictionaryMeanders.values()).bit_length()
|
|
63
|
+
|
|
64
|
+
MAXIMUMarcCode: int = 0
|
|
65
|
+
if fixedSizeMAXIMUMarcCode:
|
|
66
|
+
MAXIMUMarcCode = state.MAXIMUMarcCode
|
|
67
|
+
|
|
68
|
+
return (arcCodeWidest > raiseIfNone(state.bitWidthLimitArcCode)
|
|
69
|
+
or crossingsWidest > raiseIfNone(state.bitWidthLimitCrossings)
|
|
70
|
+
or MAXIMUMarcCode > raiseIfNone(state.bitWidthLimitArcCode)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
@cache
|
|
74
|
+
def _flipTheExtra_0b1(intWithExtra_0b1: numpy.uint64) -> numpy.uint64:
|
|
75
|
+
return numpy.uint64(intWithExtra_0b1 ^ walkDyckPath(int(intWithExtra_0b1)))
|
|
76
|
+
|
|
77
|
+
flipTheExtra_0b1AsUfunc = numpy.frompyfunc(_flipTheExtra_0b1, 1, 1)
|
|
78
|
+
"""Flip a bit based on Dyck path: element-wise ufunc (*u*niversal *func*tion) for a NumPy `ndarray` (*Num*erical *Py*thon *n-d*imensional array).
|
|
79
|
+
|
|
80
|
+
Warning
|
|
81
|
+
-------
|
|
82
|
+
The function will loop infinitely if an element does not have a bit that needs flipping.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
arrayTarget : numpy.ndarray[tuple[int], numpy.dtype[numpy.unsignedinteger[Any]]]
|
|
87
|
+
An array with one axis of unsigned integers and unbalanced closures.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
arrayFlipped : numpy.ndarray[tuple[int], numpy.dtype[numpy.unsignedinteger[Any]]]
|
|
92
|
+
An array with the same shape as `arrayTarget` but with one bit flipped in each element.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def getBucketsTotal(state: MatrixMeandersNumPyState, safetyMultiplicand: float = 1.2) -> int: # noqa: ARG001
|
|
96
|
+
"""Under renovation: Estimate the total number of non-unique arcCode that will be computed from the existing arcCode.
|
|
97
|
+
|
|
98
|
+
Warning
|
|
99
|
+
-------
|
|
100
|
+
Because `matrixMeandersPandas` does not store anything in `state.arrayArcCodes`, if `matrixMeandersPandas` requests
|
|
101
|
+
bucketsTotal for a value not in the dictionary, the returned value will be 0. But `matrixMeandersPandas` should have a safety
|
|
102
|
+
check that will allocate more space.
|
|
103
|
+
|
|
104
|
+
Notes
|
|
105
|
+
-----
|
|
106
|
+
TODO remake this function from scratch.
|
|
107
|
+
|
|
108
|
+
Factors:
|
|
109
|
+
- The starting quantity of `arcCode`.
|
|
110
|
+
- The value(s) of the starting `arcCode`.
|
|
111
|
+
- n
|
|
112
|
+
- boundary
|
|
113
|
+
- Whether this bucketsTotal is increasing, as compared to all of the prior bucketsTotal.
|
|
114
|
+
- If increasing, is it exponential or logarithmic?
|
|
115
|
+
- The maximum value.
|
|
116
|
+
- If decreasing, I don't really know the factors.
|
|
117
|
+
- If I know the actual value or if I must estimate it.
|
|
118
|
+
|
|
119
|
+
Figure out an intelligent flow for so many factors.
|
|
120
|
+
"""
|
|
121
|
+
theDictionary: dict[str, dict[int, dict[int, int]]] = {'A005316': A005316_n_boundary_buckets, 'A000682': A000682_n_boundary_buckets}
|
|
122
|
+
bucketsTotal: int = theDictionary.get(state.oeisID, {}).get(state.n, {}).get(state.boundary, 0)
|
|
123
|
+
if bucketsTotal <= 0:
|
|
124
|
+
bucketsTotal = int(3.55 * len(state.arrayArcCodes))
|
|
125
|
+
|
|
126
|
+
return bucketsTotal
|
|
127
|
+
|
|
128
|
+
def getSignaturesTotal(state: MatrixMeandersNumPyState) -> int:
|
|
129
|
+
"""Get the total number of signatures for the current `n` and `boundary`.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
state : MatrixMeandersState
|
|
134
|
+
The current state of the computation.
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
signaturesTotal : int
|
|
139
|
+
The total number of signatures for the current `n` and `boundary`.
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
from mapFolding.reference.matrixMeandersAnalysis.signatures import signatures # noqa: PLC0415
|
|
143
|
+
return signatures[state.oeisID].get(state.n, {}).get(state.boundary, int(3.55 * len(state.arrayArcCodes)))
|
|
144
|
+
|
|
145
|
+
@cache
|
|
146
|
+
def walkDyckPath(intWithExtra_0b1: int) -> int:
|
|
147
|
+
"""Find the bit position for flipping paired curve endpoints in meander transfer matrices.
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
intWithExtra_0b1 : int
|
|
152
|
+
Binary representation of curve locations with an extra bit encoding parity information.
|
|
153
|
+
|
|
154
|
+
Returns
|
|
155
|
+
-------
|
|
156
|
+
flipExtra_0b1_Here : int
|
|
157
|
+
Bit mask indicating the position where the balance condition fails, formatted as 2^(2k).
|
|
158
|
+
|
|
159
|
+
3L33T H@X0R
|
|
160
|
+
------------
|
|
161
|
+
Binary search for first negative balance in shifted bit pairs. Returns 2^(2k) mask for
|
|
162
|
+
bit position k where cumulative balance counter transitions from non-negative to negative.
|
|
163
|
+
|
|
164
|
+
Mathematics
|
|
165
|
+
-----------
|
|
166
|
+
Implements the Dyck path balance verification algorithm from Jensen's transfer matrix
|
|
167
|
+
enumeration. Computes the position where ∑(i=0 to k) (-1)^b_i < 0 for the first time,
|
|
168
|
+
where b_i are the bits of the input at positions 2i.
|
|
169
|
+
|
|
170
|
+
"""
|
|
171
|
+
findTheExtra_0b1: int = 0
|
|
172
|
+
flipExtra_0b1_Here: int = 1
|
|
173
|
+
while True:
|
|
174
|
+
flipExtra_0b1_Here <<= 2
|
|
175
|
+
if intWithExtra_0b1 & flipExtra_0b1_Here == 0:
|
|
176
|
+
findTheExtra_0b1 += 1
|
|
177
|
+
else:
|
|
178
|
+
findTheExtra_0b1 -= 1
|
|
179
|
+
if findTheExtra_0b1 < 0:
|
|
180
|
+
break
|
|
181
|
+
return flipExtra_0b1_Here
|
|
182
|
+
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
from gc import collect as goByeBye
|
|
2
|
+
from mapFolding import ShapeArray, ShapeSlicer
|
|
3
|
+
from mapFolding.algorithms.matrixMeandersBeDry import areIntegersWide, flipTheExtra_0b1AsUfunc, getBucketsTotal
|
|
4
|
+
from mapFolding.dataBaskets import MatrixMeandersNumPyState
|
|
5
|
+
from mapFolding.syntheticModules.meanders.bigInt import countBigInt
|
|
6
|
+
from numpy import (
|
|
7
|
+
bitwise_and, bitwise_left_shift, bitwise_or, bitwise_right_shift, bitwise_xor, greater, less_equal, multiply, subtract)
|
|
8
|
+
from numpy.typing import NDArray
|
|
9
|
+
from typing import Any, TYPE_CHECKING
|
|
10
|
+
import numpy
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from numpy.lib._arraysetops_impl import UniqueInverseResult
|
|
14
|
+
|
|
15
|
+
"""More ideas for memory efficiency:
|
|
16
|
+
- In `recordAnalysis`, use `numpy.unique_inverse` on the newly added `arcCode`.
|
|
17
|
+
- In `recordAnalysis`, use `numpy.unique_inverse` on `arrayAnalyzed` after adding new `arcCode`.
|
|
18
|
+
- By deduplicating more often, I can decrease the allocated size of `arrayAnalyzed`. However, that may reduce the usefulness of `makeStorage`.
|
|
19
|
+
- I suspect that `makeStorage(numpy.flatnonzero(prepArea)...` contains a latent array.
|
|
20
|
+
- In every case (or almost every case) I use a selector, I _feel_ like there is more memory efficient way I don't know about.
|
|
21
|
+
- It's not clear to me whether or not I am instructing numpy to release _all_ memory I no longer need.
|
|
22
|
+
- Hypothetically, `arcCode` might be compressible, but IDK no nothing.
|
|
23
|
+
- `numpy.unique_inverse` uses a ton of memory, but I've failed to find a better way. BUT I might be able to improve
|
|
24
|
+
`aggregateAnalyzed` now that `arrayArcCodes` is a single axis.
|
|
25
|
+
- For analyzeBitsAlpha and analyzeBitsZulu, find an equivalent formula that does not require a secondary stack.
|
|
26
|
+
- analyzeAligned requires a ton of memory. By analyzing it before the other three analyses (therefore `arrayAnalyzed` is empty)
|
|
27
|
+
and using `makeStorage`, I've offset much of the usage, but I don't have confidence it's a good flow.
|
|
28
|
+
|
|
29
|
+
To mitigate memory problems:
|
|
30
|
+
- Put `arrayAnalyzed` in a `numpy.memmap`.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
indicesPrepArea: int = 1
|
|
34
|
+
indexAnalysis = 0
|
|
35
|
+
slicerAnalysis: ShapeSlicer = ShapeSlicer(length=..., indices=indexAnalysis)
|
|
36
|
+
|
|
37
|
+
indicesAnalyzed: int = 2
|
|
38
|
+
indexArcCode, indexCrossings = range(indicesAnalyzed)
|
|
39
|
+
slicerArcCode: ShapeSlicer = ShapeSlicer(length=..., indices=indexArcCode)
|
|
40
|
+
slicerCrossings: ShapeSlicer = ShapeSlicer(length=..., indices=indexCrossings)
|
|
41
|
+
|
|
42
|
+
def countNumPy(state: MatrixMeandersNumPyState) -> MatrixMeandersNumPyState:
|
|
43
|
+
"""Count crossings with transfer matrix algorithm implemented in NumPy (*Num*erical *Py*thon).
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
state : MatrixMeandersState
|
|
48
|
+
The algorithm state.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
state : MatrixMeandersState
|
|
53
|
+
Updated state including `boundary` and `arrayMeanders`.
|
|
54
|
+
"""
|
|
55
|
+
while state.boundary > 0 and not areIntegersWide(state):
|
|
56
|
+
def aggregateAnalyzed(arrayAnalyzed: NDArray[numpy.uint64], state: MatrixMeandersNumPyState) -> MatrixMeandersNumPyState:
|
|
57
|
+
"""Create new `arrayMeanders` by deduplicating `arcCode` and summing `crossings`."""
|
|
58
|
+
unique: UniqueInverseResult[numpy.uint64] = numpy.unique_inverse(arrayAnalyzed[slicerArcCode])
|
|
59
|
+
|
|
60
|
+
state.arrayArcCodes = unique.values
|
|
61
|
+
state.arrayCrossings = numpy.zeros_like(state.arrayArcCodes, dtype=state.datatypeCrossings)
|
|
62
|
+
numpy.add.at(state.arrayCrossings, unique.inverse_indices, arrayAnalyzed[slicerCrossings])
|
|
63
|
+
del unique
|
|
64
|
+
|
|
65
|
+
return state
|
|
66
|
+
|
|
67
|
+
def makeStorage[个: numpy.integer[Any]](dataTarget: NDArray[个], state: MatrixMeandersNumPyState, storageTarget: NDArray[numpy.uint64], indexAssignment: int = indexArcCode) -> NDArray[个]:
|
|
68
|
+
"""Store `dataTarget` in `storageTarget` on `indexAssignment` if there is enough space, otherwise allocate a new array."""
|
|
69
|
+
lengthStorageTarget: int = len(storageTarget)
|
|
70
|
+
storageAvailable: int = lengthStorageTarget - state.indexTarget
|
|
71
|
+
lengthDataTarget: int = len(dataTarget)
|
|
72
|
+
|
|
73
|
+
if storageAvailable >= lengthDataTarget:
|
|
74
|
+
indexStart: int = lengthStorageTarget - lengthDataTarget
|
|
75
|
+
sliceStorage: slice = slice(indexStart, lengthStorageTarget)
|
|
76
|
+
del indexStart
|
|
77
|
+
slicerStorageAtIndex: ShapeSlicer = ShapeSlicer(length=sliceStorage, indices=indexAssignment)
|
|
78
|
+
del sliceStorage
|
|
79
|
+
storageTarget[slicerStorageAtIndex] = dataTarget.copy()
|
|
80
|
+
arrayStorage = storageTarget[slicerStorageAtIndex].view() # pyright: ignore[reportAssignmentType]
|
|
81
|
+
del slicerStorageAtIndex
|
|
82
|
+
else:
|
|
83
|
+
arrayStorage: NDArray[个] = dataTarget.copy()
|
|
84
|
+
|
|
85
|
+
del storageAvailable, lengthDataTarget, lengthStorageTarget
|
|
86
|
+
|
|
87
|
+
return arrayStorage
|
|
88
|
+
|
|
89
|
+
def recordAnalysis(arrayAnalyzed: NDArray[numpy.uint64], state: MatrixMeandersNumPyState, arcCode: NDArray[numpy.uint64]) -> MatrixMeandersNumPyState:
|
|
90
|
+
"""Record valid `arcCode` and corresponding `crossings` in `arrayAnalyzed`."""
|
|
91
|
+
selectorOverLimit = arcCode > state.MAXIMUMarcCode
|
|
92
|
+
arcCode[selectorOverLimit] = 0
|
|
93
|
+
del selectorOverLimit
|
|
94
|
+
|
|
95
|
+
selectorAnalysis: NDArray[numpy.intp] = numpy.flatnonzero(arcCode)
|
|
96
|
+
|
|
97
|
+
indexStop: int = state.indexTarget + len(selectorAnalysis)
|
|
98
|
+
sliceAnalysis: slice = slice(state.indexTarget, indexStop)
|
|
99
|
+
state.indexTarget = indexStop
|
|
100
|
+
del indexStop
|
|
101
|
+
|
|
102
|
+
slicerArcCodeAnalysis = ShapeSlicer(length=sliceAnalysis, indices=indexArcCode)
|
|
103
|
+
slicerCrossingsAnalysis = ShapeSlicer(length=sliceAnalysis, indices=indexCrossings)
|
|
104
|
+
del sliceAnalysis
|
|
105
|
+
|
|
106
|
+
arrayAnalyzed[slicerArcCodeAnalysis] = arcCode[selectorAnalysis]
|
|
107
|
+
del slicerArcCodeAnalysis
|
|
108
|
+
|
|
109
|
+
arrayAnalyzed[slicerCrossingsAnalysis] = state.arrayCrossings[selectorAnalysis]
|
|
110
|
+
del slicerCrossingsAnalysis, selectorAnalysis
|
|
111
|
+
goByeBye()
|
|
112
|
+
return state
|
|
113
|
+
|
|
114
|
+
state.bitWidth = int(state.arrayArcCodes.max()).bit_length()
|
|
115
|
+
|
|
116
|
+
lengthArrayAnalyzed: int = getBucketsTotal(state, 1.2)
|
|
117
|
+
shape = ShapeArray(length=lengthArrayAnalyzed, indices=indicesAnalyzed)
|
|
118
|
+
del lengthArrayAnalyzed
|
|
119
|
+
goByeBye()
|
|
120
|
+
|
|
121
|
+
arrayAnalyzed: NDArray[numpy.uint64] = numpy.zeros(shape, dtype=state.datatypeArcCode)
|
|
122
|
+
del shape
|
|
123
|
+
|
|
124
|
+
shape = ShapeArray(length=len(state.arrayArcCodes), indices=indicesPrepArea)
|
|
125
|
+
arrayPrepArea: NDArray[numpy.uint64] = numpy.zeros(shape, dtype=state.datatypeArcCode)
|
|
126
|
+
del shape
|
|
127
|
+
|
|
128
|
+
prepArea: NDArray[numpy.uint64] = arrayPrepArea[slicerAnalysis].view()
|
|
129
|
+
|
|
130
|
+
state.indexTarget = 0
|
|
131
|
+
|
|
132
|
+
state.boundary -= 1
|
|
133
|
+
|
|
134
|
+
# =============== analyze aligned ===== if bitsAlpha > 1 and bitsZulu > 1 =============================================
|
|
135
|
+
arrayBitsAlpha: NDArray[numpy.uint64] = bitwise_and(state.arrayArcCodes, state.locatorBits) # NOTE extra array
|
|
136
|
+
# ======= > * > bitsAlpha 1 bitsZulu 1 ====================
|
|
137
|
+
greater(arrayBitsAlpha, 1, out=prepArea)
|
|
138
|
+
bitsZuluStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexCrossings)
|
|
139
|
+
bitwise_right_shift(bitsZuluStack, 1, out=bitsZuluStack) # O indexArcCode X indexCrossings
|
|
140
|
+
bitwise_and(bitsZuluStack, state.locatorBits, out=bitsZuluStack)
|
|
141
|
+
multiply(bitsZuluStack, prepArea, out=prepArea)
|
|
142
|
+
greater(prepArea, 1, out=prepArea)
|
|
143
|
+
selectorGreaterThan1: NDArray[numpy.uint64] = makeStorage(prepArea, state, arrayAnalyzed, indexArcCode)
|
|
144
|
+
# X indexArcCode X indexCrossings
|
|
145
|
+
# ======= if bitsAlphaAtEven and not bitsZuluAtEven =======
|
|
146
|
+
# ======= ^ & | ^ & bitsZulu 1 1 bitsAlpha 1 1 ============
|
|
147
|
+
bitwise_and(bitsZuluStack, 1, out=prepArea)
|
|
148
|
+
del bitsZuluStack # X indexArcCode O indexCrossings
|
|
149
|
+
bitwise_xor(prepArea, 1, out=prepArea)
|
|
150
|
+
bitwise_or(arrayBitsAlpha, prepArea, out=prepArea)
|
|
151
|
+
bitwise_and(prepArea, 1, out=prepArea)
|
|
152
|
+
bitwise_xor(prepArea, 1, out=prepArea)
|
|
153
|
+
|
|
154
|
+
bitwise_and(selectorGreaterThan1, prepArea, out=prepArea)
|
|
155
|
+
selectorAlignAlpha: NDArray[numpy.intp] = makeStorage(numpy.flatnonzero(prepArea), state, arrayAnalyzed, indexCrossings)
|
|
156
|
+
# X indexArcCode X indexCrossings
|
|
157
|
+
arrayBitsAlpha[selectorAlignAlpha] = flipTheExtra_0b1AsUfunc(arrayBitsAlpha[selectorAlignAlpha])
|
|
158
|
+
del selectorAlignAlpha # X indexArcCode O indexCrossings
|
|
159
|
+
|
|
160
|
+
# ======= if bitsZuluAtEven and not bitsAlphaAtEven =======
|
|
161
|
+
# ======= ^ & | ^ & bitsAlpha 1 1 bitsZulu 1 1 ============
|
|
162
|
+
bitsAlphaStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexCrossings)
|
|
163
|
+
bitwise_and(bitsAlphaStack, state.locatorBits, out=bitsAlphaStack)
|
|
164
|
+
bitwise_and(bitsAlphaStack, 1, out=prepArea)
|
|
165
|
+
del bitsAlphaStack # X indexArcCode O indexCrossings
|
|
166
|
+
bitwise_xor(prepArea, 1, out=prepArea)
|
|
167
|
+
bitsZuluStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexCrossings)
|
|
168
|
+
bitwise_right_shift(bitsZuluStack, 1, out=bitsZuluStack)
|
|
169
|
+
bitwise_and(bitsZuluStack, state.locatorBits, out=bitsZuluStack)
|
|
170
|
+
bitwise_or(bitsZuluStack, prepArea, out=prepArea)
|
|
171
|
+
del bitsZuluStack # X indexArcCode O indexCrossings
|
|
172
|
+
bitwise_and(prepArea, 1, out=prepArea)
|
|
173
|
+
bitwise_xor(prepArea, 1, out=prepArea)
|
|
174
|
+
|
|
175
|
+
bitwise_and(selectorGreaterThan1, prepArea, out=prepArea)
|
|
176
|
+
selectorAlignZulu: NDArray[numpy.intp] = makeStorage(numpy.flatnonzero(prepArea), state, arrayAnalyzed, indexCrossings)
|
|
177
|
+
# X indexArcCode X indexCrossings
|
|
178
|
+
# ======= bitsAlphaAtEven or bitsZuluAtEven ===============
|
|
179
|
+
bitwise_and(state.arrayArcCodes, state.locatorBits, out=prepArea)
|
|
180
|
+
# ======= ^ & & bitsAlpha 1 bitsZulu 1 ====================
|
|
181
|
+
bitwise_and(prepArea, 1, out=prepArea)
|
|
182
|
+
sherpaBitsZulu: NDArray[numpy.uint64] = bitwise_right_shift(state.arrayArcCodes, 1) # NOTE 2° extra array
|
|
183
|
+
bitwise_and(sherpaBitsZulu, state.locatorBits, out=sherpaBitsZulu)
|
|
184
|
+
bitwise_and(sherpaBitsZulu, prepArea, out=prepArea)
|
|
185
|
+
del sherpaBitsZulu # NOTE del 2° extra array
|
|
186
|
+
bitwise_xor(prepArea, 1, out=prepArea)
|
|
187
|
+
|
|
188
|
+
bitwise_and(selectorGreaterThan1, prepArea, out=prepArea) # selectorBitsAtEven
|
|
189
|
+
del selectorGreaterThan1 # O indexArcCode X indexCrossings
|
|
190
|
+
bitwise_xor(prepArea, 1, out=prepArea)
|
|
191
|
+
selectorDisqualified: NDArray[numpy.intp] = makeStorage(numpy.flatnonzero(prepArea), state, arrayAnalyzed, indexArcCode)
|
|
192
|
+
# X indexArcCode X indexCrossings
|
|
193
|
+
bitwise_right_shift(state.arrayArcCodes, 1, out=prepArea)
|
|
194
|
+
bitwise_and(prepArea, state.locatorBits, out=prepArea)
|
|
195
|
+
|
|
196
|
+
prepArea[selectorAlignZulu] = flipTheExtra_0b1AsUfunc(prepArea[selectorAlignZulu])
|
|
197
|
+
del selectorAlignZulu # X indexArcCode O indexCrossings
|
|
198
|
+
|
|
199
|
+
bitsZuluStack: NDArray[numpy.uint64] = makeStorage(prepArea, state, arrayAnalyzed, indexCrossings)
|
|
200
|
+
|
|
201
|
+
# ======= (((bitsZulu >> 2) << 3) | bitsAlpha) >> 2 =======
|
|
202
|
+
# ======= >> | << >> bitsZulu 2 3 bitsAlpha 2 =============
|
|
203
|
+
bitwise_right_shift(bitsZuluStack, 2, out=prepArea)
|
|
204
|
+
del bitsZuluStack # X indexArcCode O indexCrossings
|
|
205
|
+
bitwise_left_shift(prepArea, 3, out=prepArea)
|
|
206
|
+
bitwise_or(arrayBitsAlpha, prepArea, out=prepArea)
|
|
207
|
+
del arrayBitsAlpha # NOTE del extra array
|
|
208
|
+
bitwise_right_shift(prepArea, 2, out=prepArea)
|
|
209
|
+
|
|
210
|
+
prepArea[selectorDisqualified] = 0
|
|
211
|
+
del selectorDisqualified # O indexArcCode O indexCrossings
|
|
212
|
+
|
|
213
|
+
state = recordAnalysis(arrayAnalyzed, state, prepArea)
|
|
214
|
+
|
|
215
|
+
# ----------------- analyze bitsAlpha ------- (bitsAlpha >> 2) | (bitsZulu << 3) | ((1 - (bitsAlpha & 1)) << 1) ---------
|
|
216
|
+
bitsAlphaStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexArcCode)
|
|
217
|
+
bitwise_and(bitsAlphaStack, state.locatorBits, out=bitsAlphaStack) # X indexArcCode O indexCrossings
|
|
218
|
+
# ------- >> | << | (<< - 1 & bitsAlpha 1 1) << bitsZulu 3 2 bitsAlpha 2 ----------
|
|
219
|
+
bitwise_and(bitsAlphaStack, 1, out=bitsAlphaStack)
|
|
220
|
+
subtract(1, bitsAlphaStack, out=bitsAlphaStack)
|
|
221
|
+
bitwise_left_shift(bitsAlphaStack, 1, out=bitsAlphaStack)
|
|
222
|
+
bitsZuluStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexCrossings)
|
|
223
|
+
bitwise_right_shift(bitsZuluStack, 1, out=bitsZuluStack)
|
|
224
|
+
bitwise_and(bitsZuluStack, state.locatorBits, out=bitsZuluStack)
|
|
225
|
+
bitwise_left_shift(bitsZuluStack, 3, out=prepArea)
|
|
226
|
+
del bitsZuluStack # X indexArcCode O indexCrossings
|
|
227
|
+
bitwise_or(bitsAlphaStack, prepArea, out=prepArea)
|
|
228
|
+
del bitsAlphaStack # O indexArcCode O indexCrossings
|
|
229
|
+
bitwise_left_shift(prepArea, 2, out=prepArea)
|
|
230
|
+
bitsAlphaStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexCrossings)
|
|
231
|
+
bitwise_and(bitsAlphaStack, state.locatorBits, out=bitsAlphaStack) # O indexArcCode X indexCrossings
|
|
232
|
+
bitwise_or(bitsAlphaStack, prepArea, out=prepArea)
|
|
233
|
+
bitwise_right_shift(prepArea, 2, out=prepArea)
|
|
234
|
+
|
|
235
|
+
# ------- if bitsAlpha > 1 ------------ > bitsAlpha 1 -----
|
|
236
|
+
less_equal(bitsAlphaStack, 1, out=bitsAlphaStack)
|
|
237
|
+
selectorUnderLimit: NDArray[numpy.intp] = makeStorage(numpy.flatnonzero(bitsAlphaStack), state, arrayAnalyzed, indexArcCode)
|
|
238
|
+
del bitsAlphaStack # X indexArcCode O indexCrossings
|
|
239
|
+
prepArea[selectorUnderLimit] = 0
|
|
240
|
+
del selectorUnderLimit # O indexArcCode O indexCrossings
|
|
241
|
+
|
|
242
|
+
state = recordAnalysis(arrayAnalyzed, state, prepArea)
|
|
243
|
+
|
|
244
|
+
# ----------------- analyze bitsZulu ---------- (bitsZulu >> 1) | (bitsAlpha << 2) | (1 - (bitsZulu & 1)) -------------
|
|
245
|
+
arrayBitsZulu: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexCrossings)
|
|
246
|
+
arrayBitsZulu = bitwise_right_shift(arrayBitsZulu, 1) # O indexArcCode X indexCrossings
|
|
247
|
+
arrayBitsZulu = bitwise_and(arrayBitsZulu, state.locatorBits)
|
|
248
|
+
# ------- >> | << | (- 1 & bitsZulu 1) << bitsAlpha 2 1 bitsZulu 1 ----------
|
|
249
|
+
bitwise_and(arrayBitsZulu, 1, out=arrayBitsZulu)
|
|
250
|
+
subtract(1, arrayBitsZulu, out=arrayBitsZulu)
|
|
251
|
+
bitsAlphaStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexArcCode)
|
|
252
|
+
bitwise_and(bitsAlphaStack, state.locatorBits, out=bitsAlphaStack) # X indexArcCode X indexCrossings
|
|
253
|
+
bitwise_left_shift(bitsAlphaStack, 2, out=prepArea)
|
|
254
|
+
del bitsAlphaStack # O indexArcCode X indexCrossings
|
|
255
|
+
bitwise_or(arrayBitsZulu, prepArea, out=prepArea)
|
|
256
|
+
del arrayBitsZulu # O indexArcCode O indexCrossings
|
|
257
|
+
bitwise_left_shift(prepArea, 1, out=prepArea)
|
|
258
|
+
bitsZuluStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexCrossings)
|
|
259
|
+
bitwise_right_shift(bitsZuluStack, 1, out=bitsZuluStack) # O indexArcCode X indexCrossings
|
|
260
|
+
bitwise_and(bitsZuluStack, state.locatorBits, out=bitsZuluStack)
|
|
261
|
+
bitwise_or(bitsZuluStack, prepArea, out=prepArea)
|
|
262
|
+
bitwise_right_shift(prepArea, 1, out=prepArea)
|
|
263
|
+
|
|
264
|
+
# ------- if bitsZulu > 1 ------------- > bitsZulu 1 ------
|
|
265
|
+
less_equal(bitsZuluStack, 1, out=bitsZuluStack)
|
|
266
|
+
selectorUnderLimit = makeStorage(numpy.flatnonzero(bitsZuluStack), state, arrayAnalyzed, indexArcCode)
|
|
267
|
+
del bitsZuluStack # X indexArcCode O indexCrossings
|
|
268
|
+
prepArea[selectorUnderLimit] = 0
|
|
269
|
+
del selectorUnderLimit # O indexArcCode O indexCrossings
|
|
270
|
+
|
|
271
|
+
state = recordAnalysis(arrayAnalyzed, state, prepArea)
|
|
272
|
+
|
|
273
|
+
# ----------------- analyze simple ------------------------ ((bitsAlpha | (bitsZulu << 1)) << 2) | 3 ------------------
|
|
274
|
+
bitsZuluStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexCrossings)
|
|
275
|
+
bitwise_right_shift(bitsZuluStack, 1, out=bitsZuluStack) # O indexArcCode X indexCrossings
|
|
276
|
+
bitwise_and(bitsZuluStack, state.locatorBits, out=bitsZuluStack)
|
|
277
|
+
# ------- | << | bitsAlpha << bitsZulu 1 2 3 --------------
|
|
278
|
+
bitwise_left_shift(bitsZuluStack, 1, out=prepArea)
|
|
279
|
+
del bitsZuluStack # O indexArcCode O indexCrossings
|
|
280
|
+
bitsAlphaStack: NDArray[numpy.uint64] = makeStorage(state.arrayArcCodes, state, arrayAnalyzed, indexArcCode)
|
|
281
|
+
bitwise_and(bitsAlphaStack, state.locatorBits, out=bitsAlphaStack) # X indexArcCode O indexCrossings
|
|
282
|
+
bitwise_or(bitsAlphaStack, prepArea, out=prepArea)
|
|
283
|
+
del bitsAlphaStack # O indexArcCode O indexCrossings
|
|
284
|
+
bitwise_left_shift(prepArea, 2, out=prepArea)
|
|
285
|
+
bitwise_or(prepArea, 3, out=prepArea)
|
|
286
|
+
|
|
287
|
+
state = recordAnalysis(arrayAnalyzed, state, prepArea)
|
|
288
|
+
|
|
289
|
+
del prepArea, arrayPrepArea
|
|
290
|
+
# ----------------------------------------------- aggregation ---------------------------------------------------------
|
|
291
|
+
state.arrayArcCodes = numpy.zeros((0,), dtype=state.datatypeArcCode)
|
|
292
|
+
arrayAnalyzed.resize((state.indexTarget, indicesAnalyzed))
|
|
293
|
+
|
|
294
|
+
goByeBye()
|
|
295
|
+
state = aggregateAnalyzed(arrayAnalyzed, state)
|
|
296
|
+
|
|
297
|
+
del arrayAnalyzed
|
|
298
|
+
|
|
299
|
+
if state.n >= 45:
|
|
300
|
+
# oeisID,n,boundary,buckets,arcCodes,arcCodeBitWidth,crossingsBitWidth
|
|
301
|
+
print(state.oeisID, state.n, state.boundary+1, state.indexTarget, len(state.arrayArcCodes), int(state.arrayArcCodes.max()).bit_length(), int(state.arrayCrossings.max()).bit_length(), sep=',') # noqa: T201
|
|
302
|
+
return state
|
|
303
|
+
|
|
304
|
+
def doTheNeedful(state: MatrixMeandersNumPyState) -> int:
|
|
305
|
+
"""Compute `crossings` with a transfer matrix algorithm implemented in NumPy.
|
|
306
|
+
|
|
307
|
+
Parameters
|
|
308
|
+
----------
|
|
309
|
+
state : MatrixMeandersState
|
|
310
|
+
The algorithm state.
|
|
311
|
+
|
|
312
|
+
Returns
|
|
313
|
+
-------
|
|
314
|
+
crossings : int
|
|
315
|
+
The computed value of `crossings`.
|
|
316
|
+
|
|
317
|
+
Notes
|
|
318
|
+
-----
|
|
319
|
+
Citation: https://github.com/hunterhogan/mapFolding/blob/main/citations/Jensen.bibtex
|
|
320
|
+
|
|
321
|
+
See Also
|
|
322
|
+
--------
|
|
323
|
+
https://oeis.org/A000682
|
|
324
|
+
https://oeis.org/A005316
|
|
325
|
+
"""
|
|
326
|
+
while state.boundary > 0:
|
|
327
|
+
if areIntegersWide(state):
|
|
328
|
+
state = countBigInt(state)
|
|
329
|
+
else:
|
|
330
|
+
state.makeArray()
|
|
331
|
+
state = countNumPy(state)
|
|
332
|
+
state.makeDictionary()
|
|
333
|
+
return sum(state.dictionaryMeanders.values())
|