mapFolding 0.15.4__py3-none-any.whl → 0.16.1__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 (83) hide show
  1. easyRun/A000682.py +25 -0
  2. easyRun/A005316.py +21 -0
  3. easyRun/NOTcountingFolds.py +36 -0
  4. easyRun/__init__.py +0 -0
  5. easyRun/countFolds.py +41 -0
  6. easyRun/meanders.py +71 -0
  7. mapFolding/__init__.py +10 -55
  8. mapFolding/_dataPacking.py +68 -0
  9. mapFolding/_theSSOT.py +33 -36
  10. mapFolding/_theTypes.py +21 -4
  11. mapFolding/algorithms/daoOfMapFolding.py +1 -2
  12. mapFolding/algorithms/matrixMeanders.py +101 -348
  13. mapFolding/algorithms/matrixMeandersBeDry.py +264 -0
  14. mapFolding/algorithms/matrixMeandersNumPy.py +286 -0
  15. mapFolding/algorithms/matrixMeandersPandas.py +351 -0
  16. mapFolding/algorithms/oeisIDbyFormula.py +320 -76
  17. mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +92 -0
  18. mapFolding/basecamp.py +261 -113
  19. mapFolding/beDRY.py +2 -30
  20. mapFolding/dataBaskets.py +120 -4
  21. mapFolding/oeis.py +13 -33
  22. mapFolding/reference/A000682facts.py +1276 -0
  23. mapFolding/reference/A005316facts.py +985 -0
  24. mapFolding/reference/matrixMeandersAnalysis/__init__.py +1 -0
  25. mapFolding/reference/matrixMeandersAnalysis/prefixNotationNotes.py +15 -0
  26. mapFolding/reference/meandersDumpingGround/A005316JavaPort.py +1 -1
  27. mapFolding/reference/meandersDumpingGround/A005316imperative.py +1 -1
  28. mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +424 -0
  29. mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +54 -0
  30. mapFolding/someAssemblyRequired/A007822/__init__.py +0 -0
  31. mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +197 -0
  32. mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +74 -0
  33. mapFolding/someAssemblyRequired/RecipeJob.py +4 -4
  34. mapFolding/someAssemblyRequired/__init__.py +9 -2
  35. mapFolding/someAssemblyRequired/_toolIfThis.py +4 -3
  36. mapFolding/someAssemblyRequired/_toolkitContainers.py +8 -8
  37. mapFolding/someAssemblyRequired/infoBooth.py +27 -30
  38. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +6 -5
  39. mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +6 -4
  40. mapFolding/someAssemblyRequired/makingModules_count.py +294 -0
  41. mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +117 -0
  42. mapFolding/someAssemblyRequired/mapFolding/__init__.py +0 -0
  43. mapFolding/someAssemblyRequired/mapFolding/makeMapFoldingModules.py +220 -0
  44. mapFolding/someAssemblyRequired/meanders/__init__.py +0 -0
  45. mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +64 -0
  46. mapFolding/someAssemblyRequired/toolkitMakeModules.py +152 -0
  47. mapFolding/someAssemblyRequired/toolkitNumba.py +1 -1
  48. mapFolding/someAssemblyRequired/transformationTools.py +1 -0
  49. mapFolding/syntheticModules/A007822/__init__.py +1 -0
  50. mapFolding/syntheticModules/{algorithmA007822.py → A007822/algorithm.py} +2 -3
  51. mapFolding/syntheticModules/{algorithmA007822Numba.py → A007822/algorithmNumba.py} +3 -6
  52. mapFolding/syntheticModules/A007822/asynchronous.py +148 -0
  53. mapFolding/syntheticModules/A007822/asynchronousAnnex.py +66 -0
  54. mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +85 -0
  55. mapFolding/syntheticModules/A007822/asynchronousNumba.py +52 -0
  56. mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +53 -0
  57. mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +47 -0
  58. mapFolding/syntheticModules/{initializeStateA007822.py → A007822/initializeState.py} +1 -2
  59. mapFolding/syntheticModules/{theorem2A007822.py → A007822/theorem2.py} +1 -2
  60. mapFolding/syntheticModules/{theorem2A007822Numba.py → A007822/theorem2Numba.py} +6 -4
  61. mapFolding/syntheticModules/{theorem2A007822Trimmed.py → A007822/theorem2Trimmed.py} +1 -2
  62. mapFolding/syntheticModules/countParallelNumba.py +5 -2
  63. mapFolding/syntheticModules/daoOfMapFoldingNumba.py +4 -2
  64. mapFolding/syntheticModules/dataPacking.py +4 -2
  65. mapFolding/syntheticModules/dataPackingA007822.py +92 -26
  66. mapFolding/syntheticModules/meanders/__init__.py +1 -0
  67. mapFolding/syntheticModules/meanders/bigInt.py +62 -0
  68. mapFolding/syntheticModules/theorem2Numba.py +3 -2
  69. mapFolding/tests/conftest.py +28 -13
  70. mapFolding/tests/test_computations.py +69 -62
  71. mapFolding/tests/test_oeis.py +6 -6
  72. mapFolding/zCuzDocStoopid/__init__.py +4 -0
  73. mapFolding/zCuzDocStoopid/makeDocstrings.py +68 -0
  74. mapfolding-0.16.1.dist-info/METADATA +99 -0
  75. mapfolding-0.16.1.dist-info/RECORD +114 -0
  76. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/top_level.txt +1 -0
  77. mapFolding/someAssemblyRequired/A007822rawMaterials.py +0 -46
  78. mapFolding/someAssemblyRequired/makeAllModules.py +0 -764
  79. mapfolding-0.15.4.dist-info/METADATA +0 -78
  80. mapfolding-0.15.4.dist-info/RECORD +0 -78
  81. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/WHEEL +0 -0
  82. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/entry_points.txt +0 -0
  83. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,348 +1,101 @@
1
- # ruff: noqa: D100 D103
2
- from functools import cache
3
- from gc import collect as goByeBye, set_threshold
4
- from typing import Any, Literal
5
- import gc
6
- import numpy
7
-
8
- # DEVELOPMENT INSTRUCTIONS FOR THIS MODULE
9
- #
10
- # Avoid early-return guard clauses, short-circuit returns, and multiple exit points. This codebase enforces a
11
- # single-return-per-function pattern with stable shapes/dtypes due to AST transforms. An empty input is a problem, so allow it to
12
- # fail early.
13
- #
14
- # If an algorithm has potential for infinite loops, fix the root cause: do NOT add artificial safety limits (e.g., maxIterations
15
- # counters) to prevent infinite loops.
16
- #
17
- # Always use semantic column, index, or slice identifiers: Never hardcode the locations.
18
-
19
- # TODO `set_threshold`: I know 0 means disabled, but I don't even understand if 1 means "as frequently as possible" or "almost never".
20
- set_threshold(1, 1, 1)
21
- Z0Z_bit_lengthSafetyLimit: int = 61
22
-
23
- type DataArray1D = numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.uint64 | numpy.signedinteger[Any]]]
24
- type DataArray2columns = numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.uint64]]
25
- type DataArray3columns = numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.uint64]]
26
- type SelectorBoolean = numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.bool_]]
27
- type SelectorIndices = numpy.ndarray[tuple[int, ...], numpy.dtype[numpy.intp]]
28
-
29
- # NOTE This code blocks enables semantic references to your data.
30
- columnsArrayCurveGroups = columnsArrayTotal = 3
31
- columnΩ: int = (columnsArrayTotal - columnsArrayTotal) - 1 # Something _feels_ right about this instead of `= -1`.
32
- columnDistinctCrossings = columnΩ = columnΩ + 1
33
- columnGroupAlpha = columnΩ = columnΩ + 1
34
- columnGroupZulu = columnΩ = columnΩ + 1
35
- if columnΩ != columnsArrayTotal - 1:
36
- message = f"Please inspect the code above this `if` check. '{columnsArrayTotal = }', therefore '{columnΩ = }' must be '{columnsArrayTotal - 1 = }' due to 'zero-indexing.'"
37
- raise ValueError(message)
38
- del columnsArrayTotal, columnΩ
39
-
40
- columnsArrayCurveLocations = columnsArrayTotal = 2
41
- columnΩ: int = (columnsArrayTotal - columnsArrayTotal) - 1
42
- columnDistinctCrossings = columnΩ = columnΩ + 1
43
- columnCurveLocations = columnΩ = columnΩ + 1
44
- if columnΩ != columnsArrayTotal - 1:
45
- message = f"Please inspect the code above this `if` check. '{columnsArrayTotal = }', therefore '{columnΩ = }' must be '{columnsArrayTotal - 1 = }' due to 'zero-indexing.'"
46
- raise ValueError(message)
47
- del columnsArrayTotal, columnΩ
48
-
49
- groupAlphaLocator: int = 0x55555555555555555555555555555555
50
- groupAlphaLocator64: int = 0x5555555555555555
51
- groupZuluLocator: int = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
52
- groupZuluLocator64: int = 0xaaaaaaaaaaaaaaaa
53
-
54
- def convertDictionaryCurveLocations2CurveGroups(dictionaryCurveLocations: dict[int, int]) -> dict[tuple[int, int], int]:
55
- return {(curveLocations & groupAlphaLocator, (curveLocations & groupZuluLocator) >> 1): distinctCrossings
56
- for curveLocations, distinctCrossings in dictionaryCurveLocations.items()}
57
-
58
- def count(bridges: int, dictionaryCurveGroups: dict[tuple[int, int], int], bridgesMinimum: int = 0) -> tuple[int, dict[tuple[int, int], int]]:
59
-
60
- dictionaryCurveLocations: dict[int, int] = {}
61
- while bridges > bridgesMinimum:
62
- bridges -= 1
63
-
64
- curveLocationsMAXIMUM: int = 1 << (2 * bridges + 4)
65
-
66
- for (groupAlpha, groupZulu), distinctCrossings in dictionaryCurveGroups.items():
67
- groupAlphaCurves = groupAlpha != 1
68
- groupZuluCurves = groupZulu != 1
69
-
70
- # bridgesSimple
71
- curveLocationAnalysis = ((groupAlpha | (groupZulu << 1)) << 2) | 3
72
- if curveLocationAnalysis < curveLocationsMAXIMUM:
73
- dictionaryCurveLocations[curveLocationAnalysis] = dictionaryCurveLocations.get(curveLocationAnalysis, 0) + distinctCrossings
74
-
75
- if groupAlphaCurves:
76
- curveLocationAnalysis = (groupAlpha >> 2) | (groupZulu << 3) | ((groupAlphaIsEven := 1 - (groupAlpha & 0b1)) << 1)
77
- if curveLocationAnalysis < curveLocationsMAXIMUM:
78
- dictionaryCurveLocations[curveLocationAnalysis] = dictionaryCurveLocations.get(curveLocationAnalysis, 0) + distinctCrossings
79
-
80
- if groupZuluCurves:
81
- curveLocationAnalysis = (groupZulu >> 1) | (groupAlpha << 2) | (groupZuluIsEven := 1 - (groupZulu & 1))
82
- if curveLocationAnalysis < curveLocationsMAXIMUM:
83
- dictionaryCurveLocations[curveLocationAnalysis] = dictionaryCurveLocations.get(curveLocationAnalysis, 0) + distinctCrossings
84
-
85
- # bridgesAligned
86
- if groupZuluCurves and groupAlphaCurves:
87
- # One Truth-check to select a code path
88
- groupsCanBePairedTogether = (groupZuluIsEven << 1) | groupAlphaIsEven # pyright: ignore[reportPossiblyUnboundVariable]
89
-
90
- if groupsCanBePairedTogether != 0: # Case 0 (False, False)
91
- XOrHere2makePair = 0b1
92
- findUnpaired_0b1 = 0
93
-
94
- if groupsCanBePairedTogether == 1: # Case 1: (False, True)
95
- while findUnpaired_0b1 >= 0:
96
- XOrHere2makePair <<= 2
97
- findUnpaired_0b1 += 1 if (groupAlpha & XOrHere2makePair) == 0 else -1
98
- groupAlpha ^= XOrHere2makePair # noqa: PLW2901
99
- elif groupsCanBePairedTogether == 2: # Case 2: (True, False)
100
- while findUnpaired_0b1 >= 0:
101
- XOrHere2makePair <<= 2
102
- findUnpaired_0b1 += 1 if (groupZulu & XOrHere2makePair) == 0 else -1
103
- groupZulu ^= XOrHere2makePair # noqa: PLW2901
104
-
105
- # Cases 1, 2, and 3 all compute curveLocationAnalysis
106
- curveLocationAnalysis = ((groupZulu >> 2) << 1) | (groupAlpha >> 2)
107
- if curveLocationAnalysis < curveLocationsMAXIMUM:
108
- dictionaryCurveLocations[curveLocationAnalysis] = dictionaryCurveLocations.get(curveLocationAnalysis, 0) + distinctCrossings
109
-
110
- dictionaryCurveGroups = convertDictionaryCurveLocations2CurveGroups(dictionaryCurveLocations)
111
- dictionaryCurveLocations = {}
112
-
113
- return (bridges, dictionaryCurveGroups)
114
-
115
- @cache
116
- def walkDyckPath(intWithExtra_0b1: int) -> int:
117
- findTheExtra_0b1: int = 0
118
- flipExtra_0b1_Here: int = 1
119
- while True:
120
- flipExtra_0b1_Here <<= 2
121
- if (intWithExtra_0b1 & flipExtra_0b1_Here) == 0:
122
- findTheExtra_0b1 += 1
123
- else:
124
- findTheExtra_0b1 -= 1
125
- if findTheExtra_0b1 < 0:
126
- break
127
- return flipExtra_0b1_Here
128
-
129
- @cache
130
- def _flipTheExtra_0b1(avoidingLookupsInPerRowLoop: int) -> numpy.uint64:
131
- """Be a docstring."""
132
- return numpy.uint64(avoidingLookupsInPerRowLoop ^ walkDyckPath(avoidingLookupsInPerRowLoop))
133
-
134
- # TODO there is a better way to do this.
135
- flipTheExtra_0b1 = numpy.vectorize(_flipTheExtra_0b1, otypes=[numpy.uint64])
136
- """The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop."""
137
-
138
- def aggregateCurveLocations(arrayCurveLocations: DataArray2columns) -> DataArray3columns:
139
- arrayCurveGroups: DataArray3columns = numpy.tile(
140
- A=numpy.unique(arrayCurveLocations[:, columnCurveLocations])
141
- , reps=(columnsArrayCurveGroups, 1)
142
- ).T
143
- arrayCurveGroups[:, columnDistinctCrossings] = 0
144
- numpy.add.at(
145
- arrayCurveGroups[:, columnDistinctCrossings]
146
- , numpy.searchsorted(
147
- a=arrayCurveGroups[:, columnCurveLocations]
148
- , v=arrayCurveLocations[:, columnCurveLocations])
149
- , arrayCurveLocations[:, columnDistinctCrossings]
150
- )
151
- # I'm computing groupZulu from curveLocations that are physically in `arrayCurveGroups`, so I'm using `columnCurveLocations`.
152
- numpy.bitwise_and(arrayCurveGroups[:, columnCurveLocations], numpy.uint64(groupZuluLocator64), out=arrayCurveGroups[:, columnGroupZulu])
153
- numpy.right_shift(arrayCurveGroups[:, columnGroupZulu], 1, out=arrayCurveGroups[:, columnGroupZulu])
154
- # NOTE Do not alphabetize these operations. This column has curveLocations data that groupZulu needs.
155
- arrayCurveGroups[:, columnGroupAlpha] &= groupAlphaLocator64
156
- return arrayCurveGroups
157
-
158
- def convertDictionaryCurveGroups2array(dictionaryCurveGroups: dict[tuple[int, int], int]) -> DataArray3columns:
159
- arrayCurveGroups: DataArray3columns = numpy.tile(numpy.fromiter(dictionaryCurveGroups.values(), dtype=numpy.uint64), (columnsArrayCurveGroups, 1)).T
160
- arrayKeys: DataArray2columns = numpy.array(list(dictionaryCurveGroups.keys()), dtype=numpy.uint64)
161
- arrayCurveGroups[:, columnGroupAlpha] = arrayKeys[:, 0]
162
- arrayCurveGroups[:, columnGroupZulu] = arrayKeys[:, 1]
163
- return arrayCurveGroups
164
-
165
- def count64(bridges: int, arrayCurveGroups: DataArray3columns, bridgesMinimum: int = 0) -> tuple[int, DataArray3columns]:
166
-
167
- while bridges > bridgesMinimum and int(arrayCurveGroups[:, columnDistinctCrossings].max()).bit_length() < Z0Z_bit_lengthSafetyLimit:
168
- bridges -= 1
169
- curveLocationsMAXIMUM: numpy.uint64 = numpy.uint64(1 << (2 * bridges + 4))
170
-
171
- selectGroupAlphaCurves: SelectorBoolean = arrayCurveGroups[:, columnGroupAlpha] > numpy.uint64(1)
172
- curveLocationsGroupAlpha: DataArray1D = ((arrayCurveGroups[selectGroupAlphaCurves, columnGroupAlpha] >> 2)
173
- | (arrayCurveGroups[selectGroupAlphaCurves, columnGroupZulu] << 3)
174
- | ((numpy.uint64(1) - (arrayCurveGroups[selectGroupAlphaCurves, columnGroupAlpha] & 1)) << 1)
175
- )
176
- selectGroupAlphaCurvesLessThanMaximum: SelectorIndices = numpy.flatnonzero(selectGroupAlphaCurves)[numpy.flatnonzero(curveLocationsGroupAlpha < curveLocationsMAXIMUM)]
177
-
178
- selectGroupZuluCurves: SelectorBoolean = arrayCurveGroups[:, columnGroupZulu] > numpy.uint64(1)
179
- curveLocationsGroupZulu: DataArray1D = (arrayCurveGroups[selectGroupZuluCurves, columnGroupZulu] >> 1
180
- | arrayCurveGroups[selectGroupZuluCurves, columnGroupAlpha] << 2
181
- | (numpy.uint64(1) - (arrayCurveGroups[selectGroupZuluCurves, columnGroupZulu] & 1))
182
- )
183
- selectGroupZuluCurvesLessThanMaximum: SelectorIndices = numpy.flatnonzero(selectGroupZuluCurves)[numpy.flatnonzero(curveLocationsGroupZulu < curveLocationsMAXIMUM)]
184
-
185
- selectBridgesSimpleLessThanMaximum: SelectorIndices = numpy.flatnonzero(
186
- ((arrayCurveGroups[:, columnGroupAlpha] << 2) | (arrayCurveGroups[:, columnGroupZulu] << 3) | 3) < curveLocationsMAXIMUM
187
- ) # Computation, but including `< curveLocationsMAXIMUM` is ~2% of total time.
188
-
189
- # Selectors for bridgesAligned -------------------------------------------------
190
- selectGroupAlphaAtEven: SelectorBoolean = (arrayCurveGroups[:, columnGroupAlpha] & 1) == numpy.uint64(0)
191
- selectGroupZuluAtEven: SelectorBoolean = (arrayCurveGroups[:, columnGroupZulu] & 1) == numpy.uint64(0)
192
- selectBridgesAligned: SelectorBoolean = selectGroupAlphaCurves & selectGroupZuluCurves & (selectGroupAlphaAtEven | selectGroupZuluAtEven)
193
-
194
- SliceΩ: slice[int, int, Literal[1]] = slice(0,0)
195
- sliceAllocateGroupAlpha = SliceΩ = slice(SliceΩ.stop, SliceΩ.stop + selectGroupAlphaCurvesLessThanMaximum.size)
196
- sliceAllocateGroupZulu = SliceΩ = slice(SliceΩ.stop, SliceΩ.stop + selectGroupZuluCurvesLessThanMaximum.size)
197
- sliceAllocateBridgesSimple = SliceΩ = slice(SliceΩ.stop, SliceΩ.stop + selectBridgesSimpleLessThanMaximum.size)
198
- sliceAllocateBridgesAligned = SliceΩ = slice(SliceΩ.stop, SliceΩ.stop + selectBridgesAligned.size)
199
-
200
- arrayCurveLocations: DataArray2columns = numpy.zeros((SliceΩ.stop, columnsArrayCurveLocations), dtype=arrayCurveGroups.dtype)
201
-
202
- arrayCurveLocations[sliceAllocateGroupAlpha, columnCurveLocations] = curveLocationsGroupAlpha[numpy.flatnonzero(curveLocationsGroupAlpha < curveLocationsMAXIMUM)]
203
- arrayCurveLocations[sliceAllocateGroupAlpha, columnDistinctCrossings] = arrayCurveGroups[selectGroupAlphaCurvesLessThanMaximum, columnDistinctCrossings]
204
-
205
- arrayCurveLocations[sliceAllocateGroupZulu, columnCurveLocations] = curveLocationsGroupZulu[numpy.flatnonzero(curveLocationsGroupZulu < curveLocationsMAXIMUM)]
206
- arrayCurveLocations[sliceAllocateGroupZulu, columnDistinctCrossings] = arrayCurveGroups[selectGroupZuluCurvesLessThanMaximum, columnDistinctCrossings]
207
-
208
- # TODO Uh, it sure looks like I am doing this computation twice. Computation (without assignment) ~ 1.5% of total time.
209
- arrayCurveLocations[sliceAllocateBridgesSimple, columnCurveLocations] = (
210
- (arrayCurveGroups[selectBridgesSimpleLessThanMaximum, columnGroupAlpha] << 2)
211
- | (arrayCurveGroups[selectBridgesSimpleLessThanMaximum, columnGroupZulu] << 3)
212
- | 3
213
- )
214
- arrayCurveLocations[sliceAllocateBridgesSimple, columnDistinctCrossings] = arrayCurveGroups[selectBridgesSimpleLessThanMaximum, columnDistinctCrossings]
215
-
216
- curveLocationsGroupAlpha = None; del curveLocationsGroupAlpha # pyright: ignore[reportAssignmentType] # noqa: E702
217
- curveLocationsGroupZulu = None; del curveLocationsGroupZulu # pyright: ignore[reportAssignmentType] # noqa: E702
218
- selectBridgesSimpleLessThanMaximum = None; del selectBridgesSimpleLessThanMaximum # pyright: ignore[reportAssignmentType] # noqa: E702
219
- selectGroupAlphaCurvesLessThanMaximum = None; del selectGroupAlphaCurvesLessThanMaximum # pyright: ignore[reportAssignmentType] # noqa: E702
220
- selectGroupZuluCurvesLessThanMaximum = None; del selectGroupZuluCurvesLessThanMaximum # pyright: ignore[reportAssignmentType] # noqa: E702
221
- goByeBye()
222
-
223
- # NOTE this MODIFIES `arrayCurveGroups` for bridgesPairedToOdd ---------------------------------------------------------------------------------------
224
- selectBridgesGroupAlphaPairedToOdd: SelectorIndices = numpy.flatnonzero(selectBridgesAligned & selectGroupAlphaAtEven & (~selectGroupZuluAtEven))
225
- arrayCurveGroups[selectBridgesGroupAlphaPairedToOdd, columnGroupAlpha] = flipTheExtra_0b1(
226
- arrayCurveGroups[selectBridgesGroupAlphaPairedToOdd, columnGroupAlpha]
227
- )
228
-
229
- selectBridgesGroupZuluPairedToOdd: SelectorIndices = numpy.flatnonzero(selectBridgesAligned & (~selectGroupAlphaAtEven) & selectGroupZuluAtEven)
230
- arrayCurveGroups[selectBridgesGroupZuluPairedToOdd, columnGroupZulu] = flipTheExtra_0b1(
231
- arrayCurveGroups[selectBridgesGroupZuluPairedToOdd, columnGroupZulu]
232
- )
233
-
234
- selectBridgesGroupAlphaPairedToOdd = None; del selectBridgesGroupAlphaPairedToOdd # pyright: ignore[reportAssignmentType] # noqa: E702
235
- selectBridgesGroupZuluPairedToOdd = None; del selectBridgesGroupZuluPairedToOdd # pyright: ignore[reportAssignmentType] # noqa: E702
236
- selectGroupAlphaAtEven = None; del selectGroupAlphaAtEven # pyright: ignore[reportAssignmentType] # noqa: E702
237
- selectGroupAlphaCurves = None; del selectGroupAlphaCurves # pyright: ignore[reportAssignmentType] # noqa: E702
238
- selectGroupZuluAtEven = None; del selectGroupZuluAtEven # pyright: ignore[reportAssignmentType] # noqa: E702
239
- selectGroupZuluCurves = None; del selectGroupZuluCurves # pyright: ignore[reportAssignmentType] # noqa: E702
240
- goByeBye()
241
-
242
- # bridgesAligned; bridgesAlignedAtEven, bridgesGroupAlphaPairedToOdd, bridgesGroupZuluPairedToOdd ------------------------------------------------------------------
243
- curveLocationsBridgesAligned: DataArray1D = (((arrayCurveGroups[selectBridgesAligned, columnGroupZulu] >> 2) << 1)
244
- | (arrayCurveGroups[selectBridgesAligned, columnGroupAlpha] >> 2)
245
- )
246
- selectBridgesAlignedLessThanMaximum: SelectorIndices = numpy.flatnonzero(selectBridgesAligned)[numpy.flatnonzero(curveLocationsBridgesAligned < curveLocationsMAXIMUM)]
247
-
248
- sliceAllocateBridgesAligned = SliceΩ = slice(sliceAllocateBridgesAligned.start, sliceAllocateBridgesAligned.stop - selectBridgesAligned.size + selectBridgesAlignedLessThanMaximum.size)
249
- arrayCurveLocations[sliceAllocateBridgesAligned, columnDistinctCrossings] = arrayCurveGroups[selectBridgesAlignedLessThanMaximum, columnDistinctCrossings]
250
- arrayCurveLocations[sliceAllocateBridgesAligned, columnCurveLocations] = curveLocationsBridgesAligned[numpy.flatnonzero(curveLocationsBridgesAligned < curveLocationsMAXIMUM)]
251
-
252
- arrayCurveGroups = None; del arrayCurveGroups # pyright: ignore[reportAssignmentType] # noqa: E702
253
- curveLocationsBridgesAligned = None; del curveLocationsBridgesAligned # pyright: ignore[reportAssignmentType] # noqa: E702
254
- del curveLocationsMAXIMUM
255
- selectBridgesAligned = None; del selectBridgesAligned # pyright: ignore[reportAssignmentType] # noqa: E702
256
- selectBridgesAlignedLessThanMaximum = None; del selectBridgesAlignedLessThanMaximum # pyright: ignore[reportAssignmentType] # noqa: E702
257
- goByeBye()
258
-
259
- arrayCurveLocations.resize((SliceΩ.stop, columnsArrayCurveLocations))
260
- arrayCurveGroups = aggregateCurveLocations(arrayCurveLocations)
261
-
262
- arrayCurveLocations = None; del arrayCurveLocations # pyright: ignore[reportAssignmentType] # noqa: E702
263
- del sliceAllocateBridgesAligned
264
- del sliceAllocateBridgesSimple
265
- del sliceAllocateGroupAlpha
266
- del sliceAllocateGroupZulu
267
- del SliceΩ
268
- goByeBye()
269
-
270
- return (bridges, arrayCurveGroups)
271
-
272
- def convertArrayCurveGroups2dictionaryCurveGroups(arrayCurveGroups: DataArray3columns) -> dict[tuple[int, int], int]:
273
- return {(int(row[columnGroupAlpha]), int(row[columnGroupZulu])): int(row[columnDistinctCrossings]) for row in arrayCurveGroups}
274
-
275
- def doTheNeedful(n: int, dictionaryCurveLocations: dict[int, int]) -> int:
276
- """Compute a(n) meanders with the transfer matrix algorithm.
277
-
278
- Parameters
279
- ----------
280
- n : int
281
- The index in the OEIS ID sequence.
282
- dictionaryCurveLocations : dict[int, int]
283
- A dictionary mapping curve locations to their counts.
284
-
285
- Returns
286
- -------
287
- a(n) : int
288
- The computed value of a(n).
289
-
290
- Making sausage
291
- --------------
292
-
293
- As first computed by Iwan Jensen in 2000, A000682(41) = 6664356253639465480.
294
- Citation: https://github.com/hunterhogan/mapFolding/blob/main/citations/Jensen.bibtex
295
- See also https://oeis.org/A000682
296
-
297
- I'm sure you instantly observed that A000682(41) = (6664356253639465480).bit_length() = 63 bits. And A005316(44) =
298
- (18276178714484582264).bit_length() = 64 bits.
299
-
300
- If you ask NumPy 2.3, "What is your relationship with integers with more than 64 bits?"
301
- NumPy will say, "It's complicated."
302
-
303
- Therefore, to take advantage of the computational excellence of NumPy when computing A000682(n) for n > 41, I must make some
304
- adjustments at the total count approaches 64 bits.
305
-
306
- The second complication is bit-packed integers. I use a loop that starts at `bridges = n` and decrements (`bridges -= 1`)
307
- `until bridges = 0`. If `bridges > 29`, some of the bit-packed integers have more than 64 bits. "Hey NumPy, can I use
308
- bit-packed integers with more than 64 bits?" NumPy: "It's complicated." Therefore, while `bridges` is decrementing, I don't
309
- use NumPy until I believe the bit-packed integers will be less than 64 bits.
310
-
311
- A third factor that works in my favor is that peak memory usage occurs when all types of integers are well under 64-bits wide.
312
-
313
- In total, to compute a(n) for "large" n, I use three-stages.
314
- 1. I use Python primitive `int` contained in a Python primitive `dict`.
315
- 2. When the bit width of the bit-packed integers connected to `bridges` is small enough to use `numpy.uint64`, I switch to NumPy for the heavy lifting.
316
- 3. When `distinctCrossings` subtotals might exceed 64 bits, I must switch back to Python primitives.
317
- """
318
- # NOTE '29' is based on two things. 1) `bridges = 29`, groupZuluLocator = 0xaaaaaaaaaaaaaaaa.bit_length() = 64. 2) If `bridges =
319
- # 30` or a larger number, `OverflowError: int too big to convert`. Conclusion: '29' isn't necessarily correct or the best value:
320
- # it merely fits within my limited ability to assess the correct value.
321
- # NOTE the above was written when I had the `bridges >= bridgesMinimum` bug. So, apply '-1' to everything.
322
- # NOTE This default value is necessary: it prevents `count64` from returning an incomplete dictionary when that is not necessary.
323
- # TODO `count64_bridgesMaximum` might be a VERY good idea as a second safeguard against overflowing distinctCrossingsTotal. But
324
- # I'm pretty sure I should use an actual check on maximum bit-width in arrayCurveGroups[:, columnDistinctCrossings] at the start
325
- # of each while loop. Tests on A000682 showed that the max bit-width of arrayCurveGroups[:, columnDistinctCrossings] always
326
- # increased by 1 or 2 bits on each iteration: never 0 and never 3. I did not test A005316. And I do not have a mathematical proof of the limit.
327
-
328
- count64_bridgesMaximum = 28
329
- bridgesMinimum = 0
330
- distinctCrossings64bitLimitAsValueOf_n = 41
331
- distinctCrossingsSubtotal64bitLimitAsValueOf_n_WAG = distinctCrossings64bitLimitAsValueOf_n - 3
332
- distinctCrossings64bitLimitSafetyMargin = 4
333
-
334
- dictionaryCurveGroups: dict[tuple[int, int], int] = convertDictionaryCurveLocations2CurveGroups(dictionaryCurveLocations)
335
-
336
- if n >= count64_bridgesMaximum:
337
- if n >= distinctCrossingsSubtotal64bitLimitAsValueOf_n_WAG:
338
- bridgesMinimum = n - distinctCrossingsSubtotal64bitLimitAsValueOf_n_WAG + distinctCrossings64bitLimitSafetyMargin
339
- n, dictionaryCurveGroups = count(n, dictionaryCurveGroups, count64_bridgesMaximum)
340
- gc.collect()
341
- n, arrayCurveGroups = count64(n, convertDictionaryCurveGroups2array(dictionaryCurveGroups), bridgesMinimum)
342
- if n > 0:
343
- gc.collect()
344
- n, dictionaryCurveGroups = count(n, convertArrayCurveGroups2dictionaryCurveGroups(arrayCurveGroups), bridgesMinimum=0)
345
- distinctCrossingsTotal = sum(dictionaryCurveGroups.values())
346
- else:
347
- distinctCrossingsTotal = int(arrayCurveGroups[0, columnDistinctCrossings])
348
- return distinctCrossingsTotal
1
+ from mapFolding.algorithms.matrixMeandersBeDry import walkDyckPath
2
+ from mapFolding.dataBaskets import MatrixMeandersState
3
+
4
+ def outfitDictionaryBitGroups(state: MatrixMeandersState) -> dict[tuple[int, int], int]:
5
+ """Outfit `dictionaryBitGroups` so it may manage the computations for one iteration of the transfer matrix.
6
+
7
+ Parameters
8
+ ----------
9
+ state : MatrixMeandersState
10
+ The current state of the computation, including `dictionaryMeanders`.
11
+
12
+ Returns
13
+ -------
14
+ dictionaryBitGroups : dict[tuple[int, int], int]
15
+ A dictionary of `(bitsAlpha, bitsZulu)` to `crossings`.
16
+ """
17
+ state.bitWidth = max(state.dictionaryMeanders.keys()).bit_length()
18
+ return {(arcCode & state.locatorBits, (arcCode >> 1) & state.locatorBits): crossings
19
+ for arcCode, crossings in state.dictionaryMeanders.items()}
20
+
21
+ def count(state: MatrixMeandersState) -> MatrixMeandersState:
22
+ """Count meanders with matrix transfer algorithm using Python `int` (*int*eger) contained in a Python `dict` (*dict*ionary).
23
+
24
+ Parameters
25
+ ----------
26
+ state : MatrixMeandersState
27
+ The algorithm state.
28
+
29
+ Notes
30
+ -----
31
+ The matrix transfer algorithm is sophisticated, but this implementation is straightforward: compute each index one at a time,
32
+ compute each `arcCode` one at a time, and compute each type of analysis one at a time.
33
+ """
34
+ dictionaryBitGroups: dict[tuple[int, int], int] = {}
35
+
36
+ while state.kOfMatrix > 0:
37
+ state.kOfMatrix -= 1
38
+
39
+ dictionaryBitGroups = outfitDictionaryBitGroups(state)
40
+ state.dictionaryMeanders = {}
41
+
42
+ for (bitsAlpha, bitsZulu), crossings in dictionaryBitGroups.items():
43
+ bitsAlphaHasArcs: bool = bitsAlpha > 1
44
+ bitsZuluHasArcs: bool = bitsZulu > 1
45
+ bitsAlphaIsEven = bitsZuluIsEven = 0
46
+
47
+ arcCodeAnalysis = ((bitsAlpha | (bitsZulu << 1)) << 2) | 3
48
+ # simple
49
+ if arcCodeAnalysis < state.MAXIMUMarcCode:
50
+ state.dictionaryMeanders[arcCodeAnalysis] = state.dictionaryMeanders.get(arcCodeAnalysis, 0) + crossings
51
+
52
+ if bitsAlphaHasArcs:
53
+ arcCodeAnalysis = (bitsAlpha >> 2) | (bitsZulu << 3) | ((bitsAlphaIsEven := 1 - (bitsAlpha & 1)) << 1)
54
+ if arcCodeAnalysis < state.MAXIMUMarcCode:
55
+ state.dictionaryMeanders[arcCodeAnalysis] = state.dictionaryMeanders.get(arcCodeAnalysis, 0) + crossings
56
+
57
+ if bitsZuluHasArcs:
58
+ arcCodeAnalysis = (bitsZulu >> 1) | (bitsAlpha << 2) | (bitsZuluIsEven := 1 - (bitsZulu & 1))
59
+ if arcCodeAnalysis < state.MAXIMUMarcCode:
60
+ state.dictionaryMeanders[arcCodeAnalysis] = state.dictionaryMeanders.get(arcCodeAnalysis, 0) + crossings
61
+
62
+ if bitsAlphaHasArcs and bitsZuluHasArcs and (bitsAlphaIsEven or bitsZuluIsEven):
63
+ # aligned
64
+ if bitsAlphaIsEven and not bitsZuluIsEven:
65
+ bitsAlpha ^= walkDyckPath(bitsAlpha) # noqa: PLW2901
66
+ elif bitsZuluIsEven and not bitsAlphaIsEven:
67
+ bitsZulu ^= walkDyckPath(bitsZulu) # noqa: PLW2901
68
+
69
+ arcCodeAnalysis: int = ((bitsZulu >> 2) << 1) | (bitsAlpha >> 2)
70
+ if arcCodeAnalysis < state.MAXIMUMarcCode:
71
+ state.dictionaryMeanders[arcCodeAnalysis] = state.dictionaryMeanders.get(arcCodeAnalysis, 0) + crossings
72
+
73
+ dictionaryBitGroups = {}
74
+
75
+ return state
76
+
77
+ def doTheNeedful(state: MatrixMeandersState) -> int:
78
+ """Compute `crossings` with a transfer matrix algorithm.
79
+
80
+ Parameters
81
+ ----------
82
+ state : MatrixMeandersState
83
+ The algorithm state.
84
+
85
+ Returns
86
+ -------
87
+ crossings : int
88
+ The computed value of `crossings`.
89
+
90
+ Notes
91
+ -----
92
+ Citation: https://github.com/hunterhogan/mapFolding/blob/main/citations/Jensen.bibtex
93
+
94
+ See Also
95
+ --------
96
+ https://oeis.org/A000682
97
+ https://oeis.org/A005316
98
+ """
99
+ state = count(state)
100
+
101
+ return sum(state.dictionaryMeanders.values())