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.
Files changed (77) hide show
  1. easyRun/A000682.py +25 -0
  2. easyRun/A005316.py +20 -0
  3. easyRun/NOTcountingFolds.py +36 -0
  4. easyRun/__init__.py +0 -0
  5. easyRun/countFolds.py +41 -0
  6. easyRun/meanders.py +69 -0
  7. mapFolding/__init__.py +8 -51
  8. mapFolding/_dataPacking.py +68 -0
  9. mapFolding/_theSSOT.py +33 -37
  10. mapFolding/_theTypes.py +21 -4
  11. mapFolding/algorithms/matrixMeanders.py +86 -517
  12. mapFolding/algorithms/matrixMeandersBeDry.py +182 -0
  13. mapFolding/algorithms/matrixMeandersNumPy.py +333 -0
  14. mapFolding/algorithms/matrixMeandersPandas.py +334 -0
  15. mapFolding/algorithms/oeisIDbyFormula.py +50 -29
  16. mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +51 -29
  17. mapFolding/basecamp.py +167 -206
  18. mapFolding/beDRY.py +2 -30
  19. mapFolding/dataBaskets.py +75 -49
  20. mapFolding/oeis.py +11 -32
  21. mapFolding/reference/A000682facts.py +787 -652
  22. mapFolding/reference/A005316facts.py +961 -3
  23. mapFolding/reference/matrixMeandersAnalysis/prefixNotationNotes.py +15 -0
  24. mapFolding/reference/matrixMeandersAnalysis/signatures.py +2030 -0
  25. mapFolding/reference/meandersDumpingGround/A005316JavaPort.py +1 -1
  26. mapFolding/reference/meandersDumpingGround/A005316imperative.py +1 -1
  27. mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +424 -0
  28. mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +3 -4
  29. mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +103 -29
  30. mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +18 -14
  31. mapFolding/someAssemblyRequired/RecipeJob.py +2 -2
  32. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +7 -6
  33. mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +3 -4
  34. mapFolding/someAssemblyRequired/makingModules_count.py +88 -87
  35. mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +10 -9
  36. mapFolding/someAssemblyRequired/mapFolding/makeMapFoldingModules.py +3 -3
  37. mapFolding/someAssemblyRequired/meanders/__init__.py +0 -0
  38. mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +63 -0
  39. mapFolding/someAssemblyRequired/toolkitMakeModules.py +37 -37
  40. mapFolding/someAssemblyRequired/transformationTools.py +8 -8
  41. mapFolding/syntheticModules/A007822/algorithm.py +3 -3
  42. mapFolding/syntheticModules/A007822/algorithmNumba.py +1 -2
  43. mapFolding/syntheticModules/A007822/asynchronous.py +6 -4
  44. mapFolding/syntheticModules/A007822/asynchronousAnnex.py +5 -7
  45. mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +70 -0
  46. mapFolding/syntheticModules/A007822/asynchronousNumba.py +79 -0
  47. mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +15 -3
  48. mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +12 -3
  49. mapFolding/syntheticModules/A007822/initializeState.py +1 -2
  50. mapFolding/syntheticModules/A007822/theorem2.py +7 -2
  51. mapFolding/syntheticModules/A007822/theorem2Numba.py +31 -4
  52. mapFolding/syntheticModules/A007822/theorem2Trimmed.py +8 -3
  53. mapFolding/syntheticModules/countParallelNumba.py +5 -2
  54. mapFolding/syntheticModules/dataPacking.py +1 -1
  55. mapFolding/syntheticModules/dataPackingA007822.py +92 -26
  56. mapFolding/syntheticModules/meanders/__init__.py +1 -0
  57. mapFolding/syntheticModules/meanders/bigInt.py +52 -0
  58. mapFolding/syntheticModules/theorem2.py +6 -0
  59. mapFolding/syntheticModules/theorem2Numba.py +8 -2
  60. mapFolding/syntheticModules/theorem2Trimmed.py +6 -0
  61. mapFolding/tests/conftest.py +28 -13
  62. mapFolding/tests/test_computations.py +68 -61
  63. mapFolding/tests/test_oeis.py +6 -6
  64. mapFolding/zCuzDocStoopid/__init__.py +4 -1
  65. mapFolding/zCuzDocStoopid/makeDocstrings.py +35 -28
  66. mapfolding-0.16.2.dist-info/METADATA +99 -0
  67. mapfolding-0.16.2.dist-info/RECORD +115 -0
  68. {mapfolding-0.16.0.dist-info → mapfolding-0.16.2.dist-info}/top_level.txt +1 -0
  69. mapFolding/algorithms/getBucketsTotal.py +0 -137
  70. mapFolding/reference/matrixMeandersAnalysis/evenEven.py +0 -144
  71. mapFolding/reference/matrixMeandersAnalysis/oddEven.py +0 -54
  72. mapFolding/trim_memory.py +0 -62
  73. mapfolding-0.16.0.dist-info/METADATA +0 -85
  74. mapfolding-0.16.0.dist-info/RECORD +0 -100
  75. {mapfolding-0.16.0.dist-info → mapfolding-0.16.2.dist-info}/WHEEL +0 -0
  76. {mapfolding-0.16.0.dist-info → mapfolding-0.16.2.dist-info}/entry_points.txt +0 -0
  77. {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())