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.
Files changed (34) hide show
  1. easyRun/NOTcountingFolds.py +16 -6
  2. easyRun/__init__.py +1 -0
  3. easyRun/countFolds.py +12 -5
  4. easyRun/eliminateFolds.py +60 -0
  5. mapFolding/__init__.py +2 -1
  6. mapFolding/_theTypes.py +0 -1
  7. mapFolding/algorithms/A086345.py +8 -3
  8. mapFolding/algorithms/__init__.py +1 -1
  9. mapFolding/algorithms/constraintPropagation.py +184 -0
  10. mapFolding/algorithms/elimination.py +131 -0
  11. mapFolding/algorithms/eliminationCount.py +26 -0
  12. mapFolding/algorithms/eliminationPinned.py +35 -0
  13. mapFolding/algorithms/iff.py +206 -0
  14. mapFolding/algorithms/patternFinder.py +280 -0
  15. mapFolding/algorithms/pinning2Dn.py +345 -0
  16. mapFolding/algorithms/pinning2DnAnnex.py +43 -0
  17. mapFolding/basecamp.py +72 -18
  18. mapFolding/beDRY.py +14 -1
  19. mapFolding/dataBaskets.py +56 -0
  20. mapFolding/someAssemblyRequired/transformationTools.py +1 -1
  21. mapFolding/tests/conftest.py +1 -1
  22. mapFolding/tests/test_computations.py +17 -26
  23. mapFolding/tests/verify.py +323 -0
  24. {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/METADATA +6 -3
  25. {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/RECORD +29 -24
  26. easyRun/A000682.py +0 -25
  27. easyRun/A005316.py +0 -20
  28. mapFolding/algorithms/A000136constraintPropagation.py +0 -95
  29. mapFolding/algorithms/A000136elimination.py +0 -163
  30. mapFolding/algorithms/A000136eliminationParallel.py +0 -77
  31. {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/WHEEL +0 -0
  32. {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/entry_points.txt +0 -0
  33. {mapfolding-0.17.0.dist-info → mapfolding-0.17.1.dist-info}/licenses/LICENSE +0 -0
  34. {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 < 3 for dimension in mapShape):
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, LedgerOfImports
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
@@ -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)