mapFolding 0.17.0__py3-none-any.whl → 0.17.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.
- easyRun/NOTcountingFolds.py +16 -6
- easyRun/__init__.py +1 -0
- easyRun/countFolds.py +12 -5
- easyRun/eliminateFolds.py +60 -0
- mapFolding/__init__.py +2 -1
- mapFolding/_theTypes.py +0 -1
- mapFolding/algorithms/A086345.py +8 -3
- mapFolding/algorithms/__init__.py +1 -1
- mapFolding/algorithms/constraintPropagation.py +184 -0
- mapFolding/algorithms/elimination.py +131 -0
- mapFolding/algorithms/eliminationCount.py +26 -0
- mapFolding/algorithms/eliminationPinned.py +35 -0
- mapFolding/algorithms/iff.py +206 -0
- mapFolding/algorithms/patternFinder.py +280 -0
- mapFolding/algorithms/pinning2Dn.py +345 -0
- mapFolding/algorithms/pinning2DnAnnex.py +43 -0
- mapFolding/basecamp.py +72 -18
- mapFolding/beDRY.py +14 -1
- mapFolding/dataBaskets.py +56 -0
- mapFolding/someAssemblyRequired/transformationTools.py +1 -1
- mapFolding/tests/conftest.py +1 -1
- mapFolding/tests/test_computations.py +17 -26
- mapFolding/tests/verify.py +323 -0
- {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/METADATA +6 -3
- {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/RECORD +29 -24
- easyRun/A000682.py +0 -25
- easyRun/A005316.py +0 -20
- mapFolding/algorithms/A000136constraintPropagation.py +0 -95
- mapFolding/algorithms/A000136elimination.py +0 -163
- mapFolding/algorithms/A000136eliminationParallel.py +0 -77
- {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/WHEEL +0 -0
- {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
# ruff: noqa ERA001
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from gmpy2 import bit_test, is_even, is_odd
|
|
4
|
+
from hunterMakesPy import raiseIfNone
|
|
5
|
+
from mapFolding.algorithms.patternFinder import (
|
|
6
|
+
bitBiggest, bitSecond, distanceFromPowerOf2, getDictionaryAddends4Next, getDictionaryAddends4Prior,
|
|
7
|
+
getDictionaryLeafRanges, getDictionaryPileToLeaves, getExcludedAddendIndices, getExcludedIndexLeaves,
|
|
8
|
+
multiplicityOfPrimeFactor2, numeralOfLengthInBase)
|
|
9
|
+
from mapFolding.algorithms.pinning2DnAnnex import addItUp, exclude_rBefore_k
|
|
10
|
+
from mapFolding.dataBaskets import EliminationState
|
|
11
|
+
from mapFolding.tests.verify import printStatisticsPermutations, verifyPinning2Dn
|
|
12
|
+
from math import log2, prod
|
|
13
|
+
from pprint import pprint
|
|
14
|
+
|
|
15
|
+
def pinByFormula(state: EliminationState, maximumListPinnedLeaves: int = 5000) -> EliminationState:
|
|
16
|
+
if not ((state.dimensionsTotal > 2) and (state.mapShape[0] == 2)):
|
|
17
|
+
return state
|
|
18
|
+
|
|
19
|
+
def appendPinnedLeavesAtPile(pinnedLeavesWorkbench: dict[int, int], listIndexLeavesAtPile: list[int], pile: int, mapShape: tuple[int, ...]) -> None:
|
|
20
|
+
for indexLeaf in listIndexLeavesAtPile:
|
|
21
|
+
if indexLeaf < sumsProductsOfDimensions[0]:
|
|
22
|
+
continue
|
|
23
|
+
|
|
24
|
+
if indexLeaf > sumsProductsOfDimensions[-1]:
|
|
25
|
+
continue
|
|
26
|
+
|
|
27
|
+
if indexLeaf in pinnedLeavesWorkbench.values():
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
if pile not in list(dictionaryLeafRanges[indexLeaf]):
|
|
31
|
+
continue
|
|
32
|
+
|
|
33
|
+
if exclude_rBefore_k(pile, indexLeaf, pinnedLeavesWorkbench, mapShape):
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
pileToPin: int = pile
|
|
37
|
+
pinnedLeaves: dict[int, int] = pinnedLeavesWorkbench.copy()
|
|
38
|
+
|
|
39
|
+
if indexLeaf in [0b000011, ordinal([0,1],'0',0)]:
|
|
40
|
+
pinnedLeaves[pileToPin] = indexLeaf
|
|
41
|
+
pileToPin += 1
|
|
42
|
+
indexLeaf += dictionaryAddends4Next[indexLeaf][0]
|
|
43
|
+
|
|
44
|
+
if indexLeaf in [0b000010, ordinal([1,1],'0',0)]:
|
|
45
|
+
pinnedLeaves[pileToPin] = indexLeaf
|
|
46
|
+
pileToPin -= 1
|
|
47
|
+
indexLeaf += dictionaryAddends4Prior[indexLeaf][0]
|
|
48
|
+
|
|
49
|
+
pinnedLeaves[pileToPin] = indexLeaf
|
|
50
|
+
state.listPinnedLeaves.append(pinnedLeaves.copy())
|
|
51
|
+
|
|
52
|
+
def nextPinnedLeavesWorkbench(state: EliminationState) -> dict[int, int] | None:
|
|
53
|
+
pinnedLeavesWorkbench: dict[int, int] | None = None
|
|
54
|
+
for pile in pileProcessingOrder:
|
|
55
|
+
if pile == queueStopBefore:
|
|
56
|
+
break
|
|
57
|
+
if not all(pile in pinnedLeaves for pinnedLeaves in state.listPinnedLeaves):
|
|
58
|
+
pinnedLeavesWorkbench = next((pinnedLeaves.copy() for pinnedLeaves in state.listPinnedLeaves if pile not in pinnedLeaves))
|
|
59
|
+
state.listPinnedLeaves.remove(pinnedLeavesWorkbench)
|
|
60
|
+
break
|
|
61
|
+
return pinnedLeavesWorkbench
|
|
62
|
+
|
|
63
|
+
def whereNext(pilingsPinned: list[int]) -> int:
|
|
64
|
+
return next(pile for pile in pileProcessingOrder if pile not in pilingsPinned)
|
|
65
|
+
|
|
66
|
+
ordinal: Callable[[int | list[int], str, int | list[int]], int] = numeralOfLengthInBase(positions=state.dimensionsTotal, base=state.mapShape[0])
|
|
67
|
+
"""Prototype."""
|
|
68
|
+
|
|
69
|
+
productsOfDimensions: list[int] = [prod(state.mapShape[0:dimension]) for dimension in range(state.dimensionsTotal + 1)]
|
|
70
|
+
sumsProductsOfDimensions: list[int] = [sum(productsOfDimensions[0:dimension]) for dimension in range(state.dimensionsTotal + 1)]
|
|
71
|
+
|
|
72
|
+
dictionaryAddends4Next: dict[int, list[int]] = getDictionaryAddends4Next(state)
|
|
73
|
+
dictionaryAddends4Prior: dict[int, list[int]] = getDictionaryAddends4Prior(state)
|
|
74
|
+
dictionaryLeafRanges: dict[int, range] = getDictionaryLeafRanges(state)
|
|
75
|
+
dictionaryPileToLeaves: dict[int, list[int]] = getDictionaryPileToLeaves(state)
|
|
76
|
+
|
|
77
|
+
state.listPinnedLeaves = state.listPinnedLeaves or [{0b000000: 0b000000}]
|
|
78
|
+
|
|
79
|
+
pileProcessingOrder: list[int] = [0b000000, 0b000001, 0b000010, ordinal([1,1],'1',1), ordinal([1,1],'1',0), 0b000011, ordinal([1,1],'1',[0,1]), 0b000100]
|
|
80
|
+
# pileProcessingOrder.extend([5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
|
|
81
|
+
|
|
82
|
+
pileProcessingOrder.extend([ordinal([0,1],'1',1), ordinal([0,1],'0',1), ordinal([1,1],'0',1)])
|
|
83
|
+
queueStopBefore: int = ordinal([0,1],'0',1)
|
|
84
|
+
|
|
85
|
+
oneTime: int = 0
|
|
86
|
+
|
|
87
|
+
while (len(state.listPinnedLeaves) < maximumListPinnedLeaves) and (pinnedLeavesWorkbench := nextPinnedLeavesWorkbench(state)):
|
|
88
|
+
pile: int = whereNext(list(pinnedLeavesWorkbench.keys()))
|
|
89
|
+
listIndexLeavesAtPile: list[int] = []
|
|
90
|
+
listAddendIndicesExcluded: list[int] = []
|
|
91
|
+
listRemoveIndexLeaves: list[int] = []
|
|
92
|
+
|
|
93
|
+
if pile == 0b000000:
|
|
94
|
+
listIndexLeavesAtPile.append(0b000000)
|
|
95
|
+
if pile == 0b000001:
|
|
96
|
+
listIndexLeavesAtPile.append(0b000001)
|
|
97
|
+
if pile == 0b000010:
|
|
98
|
+
listIndexLeavesAtPile = addItUp(dictionaryAddends4Next, pinnedLeavesWorkbench[pile - 1], listAddendIndicesExcluded)
|
|
99
|
+
if pile == ordinal([1,1],'1',1):
|
|
100
|
+
listIndexLeavesAtPile.append(ordinal([1,0],'0',0))
|
|
101
|
+
if pile == ordinal([1,1],'1',0):
|
|
102
|
+
indexLeafAt__10: int = pinnedLeavesWorkbench[0b000010]
|
|
103
|
+
if indexLeafAt__10.bit_length() < state.dimensionsTotal:
|
|
104
|
+
listAddendIndicesExcluded.extend([*range(0b000001, indexLeafAt__10.bit_length())])
|
|
105
|
+
listIndexLeavesAtPile = addItUp(dictionaryAddends4Prior, pinnedLeavesWorkbench[pile + 1], listAddendIndicesExcluded)
|
|
106
|
+
if pile == 0b000011:
|
|
107
|
+
listAddendIndicesExcluded.append(0)
|
|
108
|
+
indexLeafAtPileLess1: int = pinnedLeavesWorkbench[pile - 1]
|
|
109
|
+
indexLeafAt11ones0: int = pinnedLeavesWorkbench[ordinal([1,1],'1',0)]
|
|
110
|
+
if is_even(indexLeafAt11ones0) and (indexLeafAtPileLess1 == ordinal([1,0],'0',1)):
|
|
111
|
+
listAddendIndicesExcluded.extend([*range(multiplicityOfPrimeFactor2(pinnedLeavesWorkbench[ordinal([1,1],'1',0)]) + 1, state.dimensionsTotal)])
|
|
112
|
+
listIndexLeavesAtPile = addItUp(dictionaryAddends4Next, indexLeafAtPileLess1, listAddendIndicesExcluded)
|
|
113
|
+
if pile == ordinal([1,1],'1',[0,1]):
|
|
114
|
+
indexLeafAtPilePlus1: int = pinnedLeavesWorkbench[pile + 1]
|
|
115
|
+
if indexLeafAtPilePlus1 < ordinal([1,1],'0',0):
|
|
116
|
+
listAddendIndicesExcluded.append(-1)
|
|
117
|
+
indexLeafAt__10 = pinnedLeavesWorkbench[0b000010]
|
|
118
|
+
if (indexLeafAtPilePlus1 == ordinal([1,0],'0',1)) and (indexLeafAt__10 != 0b000011):
|
|
119
|
+
listAddendIndicesExcluded.extend([*range(0, indexLeafAt__10.bit_length() - 2)])
|
|
120
|
+
listIndexLeavesAtPile = addItUp(dictionaryAddends4Prior, indexLeafAtPilePlus1, listAddendIndicesExcluded)
|
|
121
|
+
if pile == 0b000100:
|
|
122
|
+
indexLeafAtPileLess1 = pinnedLeavesWorkbench[pile - 1]
|
|
123
|
+
if is_odd(indexLeafAtPileLess1):
|
|
124
|
+
listAddendIndicesExcluded.extend([*range(indexLeafAtPileLess1.bit_length() - 1, 5), distanceFromPowerOf2(indexLeafAtPileLess1 - 0b000011).bit_count()])
|
|
125
|
+
indexLeafAt11ones0 = pinnedLeavesWorkbench[ordinal([1,1],'1',0)]
|
|
126
|
+
if is_even(indexLeafAtPileLess1) and is_even(indexLeafAt11ones0):
|
|
127
|
+
listAddendIndicesExcluded.extend([*range(multiplicityOfPrimeFactor2(distanceFromPowerOf2(indexLeafAt11ones0)) - 0b000010, (state.dimensionsTotal - 3))])
|
|
128
|
+
if is_odd(indexLeafAtPileLess1):
|
|
129
|
+
listAddendIndicesExcluded.append((int(log2(distanceFromPowerOf2(indexLeafAt11ones0))) + 4) % 5)
|
|
130
|
+
indexLeafAt11ones01: int = pinnedLeavesWorkbench[ordinal([1,1],'1',[0,1])]
|
|
131
|
+
if is_even(indexLeafAtPileLess1) and indexLeafAt11ones01:
|
|
132
|
+
listAddendIndicesExcluded.extend([*range((state.dimensionsTotal - 3))][(state.dimensionsTotal - 3) - ((state.dimensionsTotal - 2) - distanceFromPowerOf2(indexLeafAt11ones01 - (indexLeafAt11ones01.bit_count() - is_even(indexLeafAt11ones01))).bit_count()) % (state.dimensionsTotal - 2) - is_even(indexLeafAt11ones01): None])
|
|
133
|
+
indexLeafAt__10 = pinnedLeavesWorkbench[0b000010]
|
|
134
|
+
if (indexLeafAt__10 == ordinal([1,0],'0',1)):
|
|
135
|
+
listAddendIndicesExcluded.extend([(int(log2(distanceFromPowerOf2(indexLeafAt11ones0))) + 4) % 5, multiplicityOfPrimeFactor2(indexLeafAt11ones01) - 1])
|
|
136
|
+
if (indexLeafAt__10 == ordinal([1,0],'0',1)) and (indexLeafAt11ones01 > ordinal([1,0],'0',1)):
|
|
137
|
+
listAddendIndicesExcluded.extend([*range(int(indexLeafAt11ones01 - 2**(indexLeafAt11ones01.bit_length() - 1)).bit_length() - 1, state.dimensionsTotal - 2)])
|
|
138
|
+
if ((indexLeafAt__10 == ordinal([1,0],'0',1)) and (0 < indexLeafAtPileLess1 - indexLeafAt__10 <= 2**(state.dimensionsTotal - 4)) and (0 < (indexLeafAt11ones0 - indexLeafAtPileLess1) <= 2**(state.dimensionsTotal - 3))):
|
|
139
|
+
listAddendIndicesExcluded.extend([distanceFromPowerOf2(indexLeafAtPileLess1 - 0b11).bit_count(), state.dimensionsTotal - 3, state.dimensionsTotal - 4])
|
|
140
|
+
listIndexLeavesAtPile = addItUp(dictionaryAddends4Next, indexLeafAtPileLess1, listAddendIndicesExcluded)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if pile == ordinal([0,1],'1',1):
|
|
144
|
+
listRemoveIndexLeaves = []
|
|
145
|
+
|
|
146
|
+
pileExcluder: int = 0b000010
|
|
147
|
+
indexLeafAtPileExcluder: int = pinnedLeavesWorkbench[pileExcluder]
|
|
148
|
+
for d in range(state.dimensionsTotal):
|
|
149
|
+
if d < state.dimensionsTotal - 2:
|
|
150
|
+
indexLeaf: int = dictionaryPileToLeaves[pileExcluder][d]
|
|
151
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
152
|
+
listRemoveIndexLeaves.extend([0b000010, ordinal([1,0],'0',0) + indexLeafAtPileExcluder])
|
|
153
|
+
if 0 < d < state.dimensionsTotal - 2:
|
|
154
|
+
indexLeaf = dictionaryPileToLeaves[pileExcluder][d]
|
|
155
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
156
|
+
listRemoveIndexLeaves.extend([0b000010 + indexLeafAtPileExcluder])
|
|
157
|
+
if d == 1:
|
|
158
|
+
indexLeaf = dictionaryPileToLeaves[pileExcluder][d]
|
|
159
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
160
|
+
listRemoveIndexLeaves.extend([ordinal([1,0],'0',0) + indexLeafAtPileExcluder + 1])
|
|
161
|
+
if d == state.dimensionsTotal - 2:
|
|
162
|
+
indexLeaf = dictionaryPileToLeaves[pileExcluder][d]
|
|
163
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
164
|
+
listRemoveIndexLeaves.extend([ordinal([0,1],'0',0), ordinal([0,1],'0',0) + indexLeafAtPileExcluder])
|
|
165
|
+
del pileExcluder
|
|
166
|
+
|
|
167
|
+
pileExcluder = ordinal([1,1],'1',0)
|
|
168
|
+
indexLeafAtPileExcluder = pinnedLeavesWorkbench[pileExcluder]
|
|
169
|
+
for d in range(state.dimensionsTotal):
|
|
170
|
+
if d == 0:
|
|
171
|
+
indexLeaf = dictionaryPileToLeaves[pileExcluder][d]
|
|
172
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
173
|
+
listRemoveIndexLeaves.extend([0b000010])
|
|
174
|
+
if d < state.dimensionsTotal - 2:
|
|
175
|
+
indexLeaf = dictionaryPileToLeaves[pileExcluder][d]
|
|
176
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
177
|
+
listRemoveIndexLeaves.extend([ordinal([0,1],'0',0) + indexLeafAtPileExcluder])
|
|
178
|
+
if 0 < d < state.dimensionsTotal - 2:
|
|
179
|
+
indexLeaf = dictionaryPileToLeaves[pileExcluder][d]
|
|
180
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
181
|
+
listRemoveIndexLeaves.extend([2**d, ordinal([0,1],'0',0) + indexLeafAtPileExcluder - (2**d - 0b000001)])
|
|
182
|
+
if 0 < d < state.dimensionsTotal - 3:
|
|
183
|
+
indexLeaf = dictionaryPileToLeaves[pileExcluder][d]
|
|
184
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
185
|
+
listRemoveIndexLeaves.extend([0b000001 + indexLeafAtPileExcluder])
|
|
186
|
+
if 0 < d < state.dimensionsTotal - 1:
|
|
187
|
+
indexLeaf = dictionaryPileToLeaves[pileExcluder][d]
|
|
188
|
+
if indexLeaf == indexLeafAtPileExcluder:
|
|
189
|
+
listRemoveIndexLeaves.extend([ordinal([0,1],'0',0)])
|
|
190
|
+
del pileExcluder
|
|
191
|
+
|
|
192
|
+
"""indexLeafAt__11
|
|
193
|
+
(2,) * 5:
|
|
194
|
+
13 False [2, 4, 7, 11, 13, 19, 21, 25, 28] [13, 4, 2, 28, 25, 11, 19]
|
|
195
|
+
25 False [8, 25, 28] [25, 8, 25, 8]
|
|
196
|
+
|
|
197
|
+
(2,) * 6:
|
|
198
|
+
13 False [2, 4, 7, 11, 13, 35, 37, 41, 44] [13, 4, 2, 44, 41, 11, 35]
|
|
199
|
+
21 False [2, 4, 8, 19, 21, 25, 28, 35, 49, 52, 56] [21, 4, 2, 52, 49, 19, 35]
|
|
200
|
+
25 False [2, 8, 19, 25, 41, 49, 56, 59] [25, 8, 2, 56, 49]
|
|
201
|
+
49 False [16, 49, 56] [49, 16, 49, 16]
|
|
202
|
+
"""
|
|
203
|
+
pileExcluder = 0b000011
|
|
204
|
+
indexLeafAtPileExcluder = pinnedLeavesWorkbench[pileExcluder]
|
|
205
|
+
|
|
206
|
+
if is_odd(indexLeafAtPileExcluder):
|
|
207
|
+
listRemoveIndexLeaves.extend([indexLeafAtPileExcluder, productsOfDimensions[raiseIfNone(bitSecond(indexLeafAtPileExcluder))]])
|
|
208
|
+
|
|
209
|
+
if indexLeafAtPileExcluder < ordinal([1,0],'0',0):
|
|
210
|
+
comebackOffset: int = sumsProductsOfDimensions[distanceFromPowerOf2(indexLeafAtPileExcluder - 0b000011).bit_count() + 1]
|
|
211
|
+
listRemoveIndexLeaves.extend([
|
|
212
|
+
0b000010
|
|
213
|
+
, indexLeafAtPileExcluder + ordinal([0,1],'1',1)
|
|
214
|
+
, indexLeafAtPileExcluder + ordinal([0,1],'1',1) - comebackOffset
|
|
215
|
+
])
|
|
216
|
+
if distanceFromPowerOf2(indexLeafAtPileExcluder - 0b000011).bit_count() == 1:
|
|
217
|
+
listRemoveIndexLeaves.extend([
|
|
218
|
+
productsOfDimensions[bitBiggest(indexLeafAtPileExcluder)] + comebackOffset
|
|
219
|
+
, ordinal([1,0],'0',0) + comebackOffset
|
|
220
|
+
])
|
|
221
|
+
|
|
222
|
+
if ordinal([1,0],'0',0) < indexLeafAtPileExcluder:
|
|
223
|
+
listRemoveIndexLeaves.extend([ordinal([1,1],'0',1), productsOfDimensions[bitBiggest(indexLeafAtPileExcluder) - 1]])
|
|
224
|
+
del pileExcluder
|
|
225
|
+
|
|
226
|
+
"""ordinal([1,1],'1',[0,1])
|
|
227
|
+
38: [2, 4, 16, 21, 35, 37, 38, 49, 50], # NOTE missing 21
|
|
228
|
+
42: [2, 4, 14, 16, 35, 37, 38, 41, 42, 49, 50], # NOTE missing 4, 14, 37, 38, 41
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
pileExcluder = ordinal([1,1],'1',[0,1])
|
|
232
|
+
indexLeafAtPileExcluder = pinnedLeavesWorkbench[pileExcluder]
|
|
233
|
+
if ordinal([1,0],'0',0) < indexLeafAtPileExcluder:
|
|
234
|
+
listRemoveIndexLeaves.extend([ordinal([1,1],'0',1), indexLeafAtPileExcluder])
|
|
235
|
+
|
|
236
|
+
if is_even(indexLeafAtPileExcluder):
|
|
237
|
+
listRemoveIndexLeaves.extend([ordinal([0,1],'0',0)])
|
|
238
|
+
bit = 1
|
|
239
|
+
if bit_test(indexLeafAtPileExcluder, bit):
|
|
240
|
+
listRemoveIndexLeaves.extend([2**bit, ordinal([1,0],'0',0) + 2**bit + 0b000001])
|
|
241
|
+
listRemoveIndexLeaves.extend([state.leavesTotal - sum(productsOfDimensions[bit: state.dimensionsTotal - 2])])
|
|
242
|
+
bit = 2
|
|
243
|
+
if bit_test(indexLeafAtPileExcluder, bit):
|
|
244
|
+
listRemoveIndexLeaves.extend([2**bit, ordinal([1,0],'0',0) + 2**bit + 0b000001])
|
|
245
|
+
if 1 < multiplicityOfPrimeFactor2(indexLeafAtPileExcluder):
|
|
246
|
+
listRemoveIndexLeaves.extend([state.leavesTotal - sum(productsOfDimensions[bit: state.dimensionsTotal - 2])])
|
|
247
|
+
bit = 3
|
|
248
|
+
if bit_test(indexLeafAtPileExcluder, bit) and (1 < multiplicityOfPrimeFactor2(indexLeafAtPileExcluder)):
|
|
249
|
+
listRemoveIndexLeaves.extend([2**bit])
|
|
250
|
+
listRemoveIndexLeaves.extend([state.leavesTotal - sum(productsOfDimensions[bit: state.dimensionsTotal - 2])])
|
|
251
|
+
if multiplicityOfPrimeFactor2(indexLeafAtPileExcluder) < state.dimensionsTotal - 3:
|
|
252
|
+
listRemoveIndexLeaves.extend([ordinal([1,0],'0',0) + 2**bit + 0b000001])
|
|
253
|
+
|
|
254
|
+
if is_odd(indexLeafAtPileExcluder):
|
|
255
|
+
listRemoveIndexLeaves.extend([0b000010])
|
|
256
|
+
|
|
257
|
+
sheepOrGoat = distanceFromPowerOf2(indexLeafAtPileExcluder - 0b000011).bit_count()
|
|
258
|
+
if 0 < sheepOrGoat < state.dimensionsTotal - 3:
|
|
259
|
+
comebackOffset = 2**bitBiggest(indexLeafAtPileExcluder) - 2
|
|
260
|
+
listRemoveIndexLeaves.extend([indexLeafAtPileExcluder - comebackOffset])
|
|
261
|
+
if 0 < sheepOrGoat < state.dimensionsTotal - 4:
|
|
262
|
+
comebackOffset = 2**raiseIfNone(bitSecond(indexLeafAtPileExcluder)) - 2
|
|
263
|
+
listRemoveIndexLeaves.extend([indexLeafAtPileExcluder - comebackOffset])
|
|
264
|
+
|
|
265
|
+
pileExcluder = 0b000100
|
|
266
|
+
indexLeafAtPileExcluder = pinnedLeavesWorkbench[pileExcluder]
|
|
267
|
+
|
|
268
|
+
if is_even(indexLeafAtPileExcluder):
|
|
269
|
+
listRemoveIndexLeaves.extend([0b000010, indexLeafAtPileExcluder + 1, ordinal([1,0],'0',0) + 0b000011])
|
|
270
|
+
if is_odd(indexLeafAtPileExcluder):
|
|
271
|
+
listRemoveIndexLeaves.extend([indexLeafAtPileExcluder - 1])
|
|
272
|
+
if ordinal([0,1],'0',0) < indexLeafAtPileExcluder < ordinal([1,0],'0',0):
|
|
273
|
+
listRemoveIndexLeaves.extend([ordinal([0,1],'0',0) + 0b000011, ordinal([1,1],'0',1)])
|
|
274
|
+
if ordinal([1,0],'0',0) < indexLeafAtPileExcluder:
|
|
275
|
+
listRemoveIndexLeaves.extend([ordinal([0,1],'0',0), ordinal([1,1],'0',1)])
|
|
276
|
+
bit = 1
|
|
277
|
+
if bit_test(indexLeafAtPileExcluder, bit):
|
|
278
|
+
listRemoveIndexLeaves.extend([2**bit, ordinal([1,0],'0',0) + 2**bit + 0b000001])
|
|
279
|
+
bit = 2
|
|
280
|
+
if bit_test(indexLeafAtPileExcluder, bit):
|
|
281
|
+
listRemoveIndexLeaves.extend([ordinal([1,0],'0',0) + 2**bit + 0b000001])
|
|
282
|
+
bit = 3
|
|
283
|
+
if bit_test(indexLeafAtPileExcluder, bit):
|
|
284
|
+
listRemoveIndexLeaves.extend([ordinal([1,0],'0',0) + 2**bit + 0b000001])
|
|
285
|
+
bit = 4
|
|
286
|
+
if bit_test(indexLeafAtPileExcluder, bit) and (indexLeafAtPileExcluder.bit_length() > 5):
|
|
287
|
+
listRemoveIndexLeaves.extend([ordinal([1,1,1],'0',0)])
|
|
288
|
+
del pileExcluder
|
|
289
|
+
|
|
290
|
+
indexLeafAt__10 = pinnedLeavesWorkbench[0b000010]
|
|
291
|
+
indexLeafAt11ones0 = pinnedLeavesWorkbench[ordinal([1,1],'1',0)]
|
|
292
|
+
indexLeafAt__11 = pinnedLeavesWorkbench[0b000011]
|
|
293
|
+
indexLeafAt11ones01 = pinnedLeavesWorkbench[ordinal([1,1],'1',[0,1])]
|
|
294
|
+
|
|
295
|
+
if (indexLeafAt__11 != ordinal([1,1],'0',1)) and (indexLeafAt11ones0 == ordinal([1,1],'0',0)):
|
|
296
|
+
listRemoveIndexLeaves.append(0b000010)
|
|
297
|
+
if (indexLeafAt11ones01 != ordinal([1,0],'0',1) + dictionaryAddends4Prior[ordinal([1,0],'0',1)][0]) and (indexLeafAt__10 == 0b000011):
|
|
298
|
+
listRemoveIndexLeaves.append(ordinal([0,1],'0',0))
|
|
299
|
+
|
|
300
|
+
tuplePilesExcluders = (0b000010, ordinal([1,1],'1',0))
|
|
301
|
+
(indexLeavesAtPilesExcluders) = (indexLeafAt__10, indexLeafAt11ones0)
|
|
302
|
+
if (indexLeafAt__10 == ordinal([0,0,1],'0',1)) and (indexLeafAt11ones0 == ordinal([1,1],'0',0)):
|
|
303
|
+
listRemoveIndexLeaves.extend([ordinal([0,0,1],'0',0), ordinal([1,1,1],'0',0)])
|
|
304
|
+
if indexLeafAt__10 == ordinal([1,0],'0',1):
|
|
305
|
+
listRemoveIndexLeaves.extend([ordinal([0,1],'0',0), indexLeafAt11ones0 + 0b000001])
|
|
306
|
+
if indexLeafAt__10.bit_length() < state.dimensionsTotal - 2:
|
|
307
|
+
listRemoveIndexLeaves.extend([0b000010, indexLeafAt11ones0 + 0b000010])
|
|
308
|
+
|
|
309
|
+
tuplePilesExcluders = (0b000010, 0b000011)
|
|
310
|
+
(indexLeavesAtPilesExcluders) = (indexLeafAt__10, indexLeafAt__11)
|
|
311
|
+
|
|
312
|
+
tuplePilesExcluders = (ordinal([1,1],'1',0), ordinal([1,1],'1',[0,1]))
|
|
313
|
+
(indexLeavesAtPilesExcluders) = (indexLeafAt11ones0, indexLeafAt11ones01)
|
|
314
|
+
|
|
315
|
+
tuplePilesExcluders = (0b000011, ordinal([1,1],'1',[0,1]))
|
|
316
|
+
(indexLeavesAtPilesExcluders) = (indexLeafAt__11, indexLeafAt11ones01)
|
|
317
|
+
|
|
318
|
+
# listRemoveIndexLeaves: list[int] = []
|
|
319
|
+
|
|
320
|
+
dictionaryExcludedIndexLeaves = getExcludedIndexLeaves(state, pile, tuplePilesExcluders)
|
|
321
|
+
if oneTime < 1:
|
|
322
|
+
oneTime += 1
|
|
323
|
+
# pprint(dictionaryExcludedIndexLeaves, width=140)
|
|
324
|
+
|
|
325
|
+
listExcludedIndexLeavesGoal = dictionaryExcludedIndexLeaves[((indexLeavesAtPilesExcluders))]
|
|
326
|
+
|
|
327
|
+
# print(indexLeavesAtPilesExcluders, sorted(set(listExcludedIndexLeavesGoal).difference(set(listRemoveIndexLeaves)))
|
|
328
|
+
# , listExcludedIndexLeavesGoal == sorted(set(listRemoveIndexLeaves)), sorted(set(listRemoveIndexLeaves)), listExcludedIndexLeavesGoal, sep='\t')
|
|
329
|
+
|
|
330
|
+
listIndexLeavesAtPile = sorted(set(dictionaryPileToLeaves[pile]).difference(set(listRemoveIndexLeaves)))
|
|
331
|
+
|
|
332
|
+
appendPinnedLeavesAtPile(pinnedLeavesWorkbench, listIndexLeavesAtPile, pile, state.mapShape)
|
|
333
|
+
|
|
334
|
+
return state
|
|
335
|
+
|
|
336
|
+
if __name__ == '__main__':
|
|
337
|
+
state = EliminationState((2,) * 5)
|
|
338
|
+
state: EliminationState = pinByFormula(state)
|
|
339
|
+
|
|
340
|
+
# pprint(state.listPinnedLeaves)
|
|
341
|
+
print(f"{len(state.listPinnedLeaves)=}")
|
|
342
|
+
|
|
343
|
+
printStatisticsPermutations(state)
|
|
344
|
+
verifyPinning2Dn(state)
|
|
345
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from itertools import pairwise, repeat
|
|
2
|
+
from mapFolding import exclude
|
|
3
|
+
from mapFolding.algorithms.patternFinder import getDictionaryLeafRanges
|
|
4
|
+
from mapFolding.dataBaskets import EliminationState
|
|
5
|
+
from math import prod
|
|
6
|
+
from operator import add
|
|
7
|
+
|
|
8
|
+
def secondOrderLeaves(state: EliminationState) -> EliminationState:
|
|
9
|
+
if not ((state.dimensionsTotal > 2) and (state.mapShape[0] == 2)):
|
|
10
|
+
return state
|
|
11
|
+
|
|
12
|
+
for pile in getDictionaryLeafRanges(state)[state.leavesTotal//2**2]:
|
|
13
|
+
state.listPinnedLeaves.append({0: 0, 1: 1
|
|
14
|
+
, pile : (1) * state.leavesTotal//2**2
|
|
15
|
+
, pile + 1 : (2**2 - 1) * state.leavesTotal//2**2
|
|
16
|
+
, state.leavesTotal - 1 : state.leavesTotal//2**1})
|
|
17
|
+
|
|
18
|
+
return state
|
|
19
|
+
|
|
20
|
+
def secondOrderPilings(state: EliminationState) -> EliminationState:
|
|
21
|
+
if not ((state.dimensionsTotal > 2) and (state.mapShape[0] == 2)):
|
|
22
|
+
return state
|
|
23
|
+
|
|
24
|
+
dictionaryLeafRanges: dict[int, range] = getDictionaryLeafRanges(state)
|
|
25
|
+
pile: int = state.leavesTotal//2**1
|
|
26
|
+
for indexLeaf in range(state.leavesTotal):
|
|
27
|
+
if pile in list(dictionaryLeafRanges[indexLeaf]):
|
|
28
|
+
state.listPinnedLeaves.append({0: 0, 1: 1
|
|
29
|
+
, pile : indexLeaf
|
|
30
|
+
, state.leavesTotal - 1 : state.leavesTotal//2**1})
|
|
31
|
+
|
|
32
|
+
return state
|
|
33
|
+
|
|
34
|
+
def addItUp(dictionaryAddends: dict[int, list[int]], indexLeafAddend: int, listIndicesExcluded: list[int]) -> list[int]:
|
|
35
|
+
return list(map(add, repeat(indexLeafAddend), exclude(dictionaryAddends[indexLeafAddend], listIndicesExcluded)))
|
|
36
|
+
|
|
37
|
+
def exclude_rBefore_k(pile: int, indexLeaf: int, pinnedLeaves: dict[int, int], mapShape: tuple[int, ...]) -> bool:
|
|
38
|
+
productsOfDimensions: list[int] = [prod(mapShape[0:dimension]) for dimension in range((len(mapShape)) + 1)]
|
|
39
|
+
dictionary_r_to_k: dict[int, int] = {r: k for k, r in pairwise(productsOfDimensions[0:-1])}
|
|
40
|
+
|
|
41
|
+
if (k := dictionary_r_to_k.get(indexLeaf)) and (pileOf_k := next(iter(pilePinned for pilePinned, indexLeafPinned in pinnedLeaves.items() if indexLeafPinned == k), None)):
|
|
42
|
+
return pile < pileOf_k
|
|
43
|
+
return False
|
mapFolding/basecamp.py
CHANGED
|
@@ -169,12 +169,12 @@ def countFolds(listDimensions: Sequence[int] | None = None
|
|
|
169
169
|
|
|
170
170
|
mapFoldingParallelState: ParallelMapFoldingState = ParallelMapFoldingState(mapShape, taskDivisions=taskDivisions)
|
|
171
171
|
|
|
172
|
-
# `listStatesParallel` exists so you can research the parallel computation.
|
|
172
|
+
# NOTE `listStatesParallel` exists so you can research the parallel computation.
|
|
173
173
|
foldsTotal, _listStatesParallel = doTheNeedful(mapFoldingParallelState, concurrencyLimit)
|
|
174
174
|
|
|
175
175
|
# ruff: noqa: E701
|
|
176
176
|
else:
|
|
177
|
-
if all(dimension <
|
|
177
|
+
if all(dimension < 2 for dimension in mapShape):
|
|
178
178
|
from mapFolding.algorithms.daoOfMapFolding import doTheNeedful
|
|
179
179
|
else:
|
|
180
180
|
match flow:
|
|
@@ -196,6 +196,75 @@ def countFolds(listDimensions: Sequence[int] | None = None
|
|
|
196
196
|
|
|
197
197
|
return foldsTotal
|
|
198
198
|
|
|
199
|
+
def eliminateFolds(mapShape: tuple[int, ...]
|
|
200
|
+
, pathLikeWriteFoldsTotal: PathLike[str] | PurePath | None = None
|
|
201
|
+
# , * # TODO improve `standardizedEqualToCallableReturn` so it will work with keyword arguments
|
|
202
|
+
, CPUlimit: bool | float | int | None = None # noqa: FBT001
|
|
203
|
+
, flow: str | None = None
|
|
204
|
+
) -> int:
|
|
205
|
+
"""
|
|
206
|
+
Compute foldsTotal by elimination.
|
|
207
|
+
|
|
208
|
+
Parameters
|
|
209
|
+
----------
|
|
210
|
+
mapShape : tuple[int, ...] | None = None
|
|
211
|
+
Tuple of integers representing the dimensions of the map to be folded. Mathematicians almost always use the term
|
|
212
|
+
"dimensions", such as in the seminal paper, "Multi-dimensional map-folding". Nevertheless, in contemporary Python
|
|
213
|
+
programming, in the context of these algorithms, the term "shape" makes it much easier to align the mathematics with the
|
|
214
|
+
syntax of the programming language.
|
|
215
|
+
pathLikeWriteFoldsTotal : PathLike[str] | PurePath | None = None
|
|
216
|
+
A filename, a path of only directories, or a path with directories and a filename to which `countFolds` will write the
|
|
217
|
+
value of `foldsTotal`. If `pathLikeWriteFoldsTotal` is a path of only directories, `countFolds` creates a filename based
|
|
218
|
+
on the map dimensions.
|
|
219
|
+
CPUlimit : bool | float | int | None = None
|
|
220
|
+
If relevant, whether and how to limit the number of processors `countFolds` will use.
|
|
221
|
+
- `False`, `None`, or `0`: No limits on processor usage; uses all available processors. All other values will
|
|
222
|
+
potentially limit processor usage.
|
|
223
|
+
- `True`: Yes, limit the processor usage; limits to 1 processor.
|
|
224
|
+
- `int >= 1`: The maximum number of available processors to use.
|
|
225
|
+
- `0 < float < 1`: The maximum number of processors to use expressed as a fraction of available processors.
|
|
226
|
+
- `-1 < float < 0`: The number of processors to *not* use expressed as a fraction of available processors.
|
|
227
|
+
- `int <= -1`: The number of available processors to *not* use.
|
|
228
|
+
- If the value of `CPUlimit` is a `float` greater than 1 or less than -1, `countFolds` truncates the value to an `int`
|
|
229
|
+
with the same sign as the `float`.
|
|
230
|
+
flow : str | None = None
|
|
231
|
+
My stupid way of selecting the version of the algorithm to use in the computation.
|
|
232
|
+
|
|
233
|
+
Returns
|
|
234
|
+
-------
|
|
235
|
+
foldsTotal : int
|
|
236
|
+
Number of distinct ways to fold a map of the given dimensions.
|
|
237
|
+
"""
|
|
238
|
+
from mapFolding.beDRY import setProcessorLimit
|
|
239
|
+
concurrencyLimit: int = setProcessorLimit(CPUlimit, packageSettings.concurrencyPackage)
|
|
240
|
+
|
|
241
|
+
# ------- memorialization instructions ---------------------------------------------
|
|
242
|
+
|
|
243
|
+
if pathLikeWriteFoldsTotal is not None:
|
|
244
|
+
pathFilenameFoldsTotal: Path | None = getPathFilenameFoldsTotal(mapShape, pathLikeWriteFoldsTotal)
|
|
245
|
+
saveFoldsTotalFAILearly(pathFilenameFoldsTotal)
|
|
246
|
+
else:
|
|
247
|
+
pathFilenameFoldsTotal = None
|
|
248
|
+
|
|
249
|
+
# ------- Algorithm version -----------------------------------------------------
|
|
250
|
+
# ruff: noqa: E701
|
|
251
|
+
match flow:
|
|
252
|
+
case 'constraintPropagation': from mapFolding.algorithms.constraintPropagation import doTheNeedful
|
|
253
|
+
case 'pinned': from mapFolding.algorithms.eliminationPinned import doTheNeedful
|
|
254
|
+
case 'elimination' | _: from mapFolding.algorithms.elimination import doTheNeedful
|
|
255
|
+
|
|
256
|
+
from mapFolding.dataBaskets import EliminationState
|
|
257
|
+
eliminationState: EliminationState = EliminationState(mapShape)
|
|
258
|
+
eliminationState = doTheNeedful(eliminationState, concurrencyLimit)
|
|
259
|
+
foldsTotal = eliminationState.foldsTotal
|
|
260
|
+
|
|
261
|
+
# ------- Follow memorialization instructions ---------------------------------------------
|
|
262
|
+
|
|
263
|
+
if pathFilenameFoldsTotal is not None:
|
|
264
|
+
saveFoldsTotal(pathFilenameFoldsTotal, foldsTotal)
|
|
265
|
+
|
|
266
|
+
return foldsTotal
|
|
267
|
+
|
|
199
268
|
def NOTcountingFolds(oeisID: str, oeis_n: int, flow: str | None = None
|
|
200
269
|
# TODO , pathLikeWriteFoldsTotal: PathLike[str] | PurePath | None = None
|
|
201
270
|
, CPUlimit: bool | float | int | None = None # noqa: FBT001
|
|
@@ -205,6 +274,7 @@ def NOTcountingFolds(oeisID: str, oeis_n: int, flow: str | None = None
|
|
|
205
274
|
matched_oeisID: bool = True
|
|
206
275
|
|
|
207
276
|
match oeisID:
|
|
277
|
+
case 'A000136': from mapFolding.algorithms.oeisIDbyFormula import A000136 as doTheNeedful
|
|
208
278
|
case 'A000560': from mapFolding.algorithms.oeisIDbyFormula import A000560 as doTheNeedful
|
|
209
279
|
case 'A001010': from mapFolding.algorithms.oeisIDbyFormula import A001010 as doTheNeedful
|
|
210
280
|
case 'A001011': from mapFolding.algorithms.oeisIDbyFormula import A001011 as doTheNeedful
|
|
@@ -223,22 +293,6 @@ def NOTcountingFolds(oeisID: str, oeis_n: int, flow: str | None = None
|
|
|
223
293
|
else:
|
|
224
294
|
matched_oeisID = True
|
|
225
295
|
match oeisID:
|
|
226
|
-
case 'A000136':
|
|
227
|
-
from mapFolding import setProcessorLimit
|
|
228
|
-
concurrencyLimit: int = setProcessorLimit(CPUlimit)
|
|
229
|
-
match flow:
|
|
230
|
-
case 'elimination':
|
|
231
|
-
from mapFolding.algorithms.A000136elimination import doTheNeedful
|
|
232
|
-
countTotal = doTheNeedful(oeis_n)
|
|
233
|
-
case 'eliminationParallel':
|
|
234
|
-
from mapFolding.algorithms.A000136eliminationParallel import doTheNeedful
|
|
235
|
-
countTotal = doTheNeedful(oeis_n, concurrencyLimit)
|
|
236
|
-
case 'constraintPropagation':
|
|
237
|
-
from mapFolding.algorithms.A000136constraintPropagation import doTheNeedful
|
|
238
|
-
countTotal = doTheNeedful(oeis_n, concurrencyLimit)
|
|
239
|
-
case _:
|
|
240
|
-
from mapFolding.algorithms.oeisIDbyFormula import A000136 as doTheNeedful
|
|
241
|
-
countTotal = doTheNeedful(oeis_n)
|
|
242
296
|
case 'A000682' | 'A005316':
|
|
243
297
|
match flow:
|
|
244
298
|
case 'matrixNumPy':
|
mapFolding/beDRY.py
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
"""Oft-needed computations or actions, especially for multi-dimensional map folding."""
|
|
2
2
|
|
|
3
|
-
from collections.abc import Sequence
|
|
3
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
4
|
+
from functools import cache
|
|
4
5
|
from hunterMakesPy import defineConcurrencyLimit, intInnit, oopsieKwargsie
|
|
5
6
|
from mapFolding import NumPyIntegerType
|
|
7
|
+
from more_itertools import extract
|
|
6
8
|
from numpy import dtype as numpy_dtype, int64 as numpy_int64, ndarray
|
|
7
9
|
from sys import maxsize as sysMaxsize
|
|
8
10
|
from typing import Any
|
|
9
11
|
import numpy
|
|
10
12
|
|
|
13
|
+
def exclude[个](iterable: Sequence[个], indices: Iterable[int]) -> Iterator[个]:
|
|
14
|
+
"""Yield items from `iterable` whose positions are not in `indices`."""
|
|
15
|
+
lengthIterable: int = len(iterable)
|
|
16
|
+
def normalizeIndex(index: int) -> int:
|
|
17
|
+
if index < 0:
|
|
18
|
+
index = (index + lengthIterable) % lengthIterable
|
|
19
|
+
return index
|
|
20
|
+
indicesInclude: list[int] = sorted(set(range(lengthIterable)).difference(map(normalizeIndex, indices)))
|
|
21
|
+
return extract(iterable, indicesInclude)
|
|
22
|
+
|
|
23
|
+
@cache
|
|
11
24
|
def getLeavesTotal(mapShape: tuple[int, ...]) -> int:
|
|
12
25
|
"""Calculate the total number of leaves in a map with the given dimensions.
|
|
13
26
|
|
mapFolding/dataBaskets.py
CHANGED
|
@@ -25,6 +25,62 @@ from mapFolding import (
|
|
|
25
25
|
getConnectionGraph, getLeavesTotal, makeDataContainer)
|
|
26
26
|
import dataclasses
|
|
27
27
|
|
|
28
|
+
@dataclasses.dataclass(slots=True)
|
|
29
|
+
class EliminationState:
|
|
30
|
+
"""Computational state for algorithms to compute foldsTotal by elimination.
|
|
31
|
+
|
|
32
|
+
Attributes
|
|
33
|
+
----------
|
|
34
|
+
mapShape : tuple[DatatypeLeavesTotal, ...]
|
|
35
|
+
Dimensions of the map being analyzed for folding patterns.
|
|
36
|
+
groupsOfFolds : DatatypeFoldsTotal = DatatypeFoldsTotal(0)
|
|
37
|
+
Current count of distinct folding pattern groups: each group has `leavesTotal`-many foldings.
|
|
38
|
+
dimensionsTotal : DatatypeLeavesTotal
|
|
39
|
+
Unchanging total number of dimensions in the map.
|
|
40
|
+
leavesTotal : DatatypeLeavesTotal
|
|
41
|
+
Unchanging total number of leaves in the map.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
mapShape: tuple[DatatypeLeavesTotal, ...] = dataclasses.field(init=True, metadata={'elementConstructor': 'DatatypeLeavesTotal'})
|
|
45
|
+
"""Dimensions of the map being analyzed for folding patterns."""
|
|
46
|
+
|
|
47
|
+
groupsOfFolds: DatatypeFoldsTotal = dataclasses.field(default=DatatypeFoldsTotal(0), metadata={'theCountingIdentifier': True})
|
|
48
|
+
"""Current count of distinct folding pattern groups: each group has `leavesTotal`-many foldings."""
|
|
49
|
+
|
|
50
|
+
listPinnedLeaves: list[dict[int, int]] = dataclasses.field(default_factory=list[dict[int, int]], init=True)
|
|
51
|
+
"""column: leaf or pile: indexLeaf"""
|
|
52
|
+
pile: DatatypeLeavesTotal = DatatypeLeavesTotal(-1) # noqa: RUF009
|
|
53
|
+
pinnedLeaves: dict[int, int] = dataclasses.field(default_factory=dict[int, int], init=True, metadata={'elementConstructor': 'DatatypeLeavesTotal'})
|
|
54
|
+
"""column: leaf or pile: indexLeaf"""
|
|
55
|
+
|
|
56
|
+
subsetsTheorem2: DatatypeLeavesTotal = DatatypeLeavesTotal(1) # noqa: RUF009
|
|
57
|
+
subsetsTheorem3: DatatypeLeavesTotal = DatatypeLeavesTotal(1) # noqa: RUF009
|
|
58
|
+
subsetsTheorem4: DatatypeLeavesTotal = DatatypeLeavesTotal(1) # noqa: RUF009
|
|
59
|
+
|
|
60
|
+
columnLast: DatatypeLeavesTotal = dataclasses.field(init=False)
|
|
61
|
+
dimensionsTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
|
|
62
|
+
"""Unchanging total number of dimensions in the map."""
|
|
63
|
+
leavesTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
|
|
64
|
+
"""Unchanging total number of leaves in the map."""
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def foldsTotal(self) -> DatatypeFoldsTotal:
|
|
68
|
+
"""The total number of possible folding patterns for this map.
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
foldsTotal : DatatypeFoldsTotal
|
|
73
|
+
The complete count of distinct folding patterns achievable with the current map configuration.
|
|
74
|
+
|
|
75
|
+
"""
|
|
76
|
+
return DatatypeFoldsTotal(self.leavesTotal) * self.groupsOfFolds * self.subsetsTheorem2 * self.subsetsTheorem3 * self.subsetsTheorem4
|
|
77
|
+
|
|
78
|
+
def __post_init__(self) -> None:
|
|
79
|
+
"""Ensure all fields have a value."""
|
|
80
|
+
self.dimensionsTotal = DatatypeLeavesTotal(len(self.mapShape))
|
|
81
|
+
self.leavesTotal = DatatypeLeavesTotal(getLeavesTotal(self.mapShape))
|
|
82
|
+
self.columnLast = self.leavesTotal - DatatypeLeavesTotal(1)
|
|
83
|
+
|
|
28
84
|
@dataclasses.dataclass(slots=True)
|
|
29
85
|
class MapFoldingState:
|
|
30
86
|
"""Core computational state for map folding algorithms.
|
|
@@ -26,7 +26,7 @@ low-level optimized implementations, maintaining code clarity while achieving pe
|
|
|
26
26
|
through specialized compilation paths essential for computationally intensive map folding research.
|
|
27
27
|
"""
|
|
28
28
|
from astToolkit import Be, extractClassDef, identifierDotAttribute, Make, NodeChanger, parseLogicalPath2astModule, Then
|
|
29
|
-
from astToolkit.containers import IngredientsFunction
|
|
29
|
+
from astToolkit.containers import IngredientsFunction
|
|
30
30
|
from astToolkit.transformationTools import unparseFindReplace
|
|
31
31
|
from hunterMakesPy import importLogicalPath2Identifier
|
|
32
32
|
from mapFolding.someAssemblyRequired import DeReConstructField2ast, IfThis, ShatteredDataclass
|
mapFolding/tests/conftest.py
CHANGED
|
@@ -242,7 +242,7 @@ def mapShapeTestCountFolds(oeisIDmapFolding: str) -> tuple[int, ...]:
|
|
|
242
242
|
n = random.choice(dictionaryOEISMapFolding[oeisIDmapFolding]['valuesTestValidation'])
|
|
243
243
|
if n < 2:
|
|
244
244
|
continue
|
|
245
|
-
listDimensionsCandidate = list(dictionaryOEISMapFolding[oeisIDmapFolding]['getMapShape'](n))
|
|
245
|
+
listDimensionsCandidate: list[int] = list(dictionaryOEISMapFolding[oeisIDmapFolding]['getMapShape'](n))
|
|
246
246
|
|
|
247
247
|
try:
|
|
248
248
|
return validateListDimensions(listDimensionsCandidate)
|