mapFolding 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mapFolding/__init__.py +1 -0
- mapFolding/beDRY.py +41 -35
- mapFolding/oeis.py +37 -35
- mapFolding/reference/hunterNumba.py +44 -44
- mapFolding/reference/lunnan.py +5 -5
- mapFolding/reference/lunnanNumpy.py +4 -4
- mapFolding/reference/lunnanWhile.py +5 -5
- mapFolding/reference/rotatedEntryPoint.py +68 -68
- mapFolding/reference/total_countPlus1vsPlusN.py +211 -0
- mapFolding/startHere.py +2 -4
- mapFolding/theSSOT.py +6 -1
- {mapFolding-0.2.1.dist-info → mapFolding-0.2.2.dist-info}/METADATA +1 -1
- mapFolding-0.2.2.dist-info/RECORD +28 -0
- tests/conftest.py +95 -37
- tests/test_oeis.py +25 -26
- tests/test_other.py +41 -4
- tests/test_tasks.py +11 -1
- mapFolding/importPackages.py +0 -5
- mapFolding-0.2.1.dist-info/RECORD +0 -28
- {mapFolding-0.2.1.dist-info → mapFolding-0.2.2.dist-info}/WHEEL +0 -0
- {mapFolding-0.2.1.dist-info → mapFolding-0.2.2.dist-info}/entry_points.txt +0 -0
- {mapFolding-0.2.1.dist-info → mapFolding-0.2.2.dist-info}/top_level.txt +0 -0
|
@@ -21,11 +21,11 @@ gapter = gapRangeStart = 3
|
|
|
21
21
|
|
|
22
22
|
# Indices of array `my`, which holds dynamic, small, unsigned, integer values.
|
|
23
23
|
tricky = [
|
|
24
|
-
(
|
|
25
|
-
(
|
|
24
|
+
(leaf1ndex := 0),
|
|
25
|
+
(gap1ndex := 1),
|
|
26
26
|
(unconstrainedLeaf := 2),
|
|
27
27
|
(gap1ndexCeiling := 3),
|
|
28
|
-
(
|
|
28
|
+
(leafConnectee := 4),
|
|
29
29
|
(taskIndex := 5),
|
|
30
30
|
(dimension1ndex := 6),
|
|
31
31
|
(foldingsSubtotal := 7),
|
|
@@ -76,7 +76,7 @@ def countFoldings(TEMPLATEtrack: NDArray,
|
|
|
76
76
|
):
|
|
77
77
|
|
|
78
78
|
TEMPLATEmy = numpy.zeros(COUNTindicesDynamic, dtype=numpy.int64)
|
|
79
|
-
TEMPLATEmy[
|
|
79
|
+
TEMPLATEmy[leaf1ndex] = 1
|
|
80
80
|
|
|
81
81
|
taskDivisions = 0
|
|
82
82
|
# taskDivisions = the[leavesTotal]
|
|
@@ -87,61 +87,61 @@ def countFoldings(TEMPLATEtrack: NDArray,
|
|
|
87
87
|
my: NDArray) -> tuple[NDArray, NDArray, NDArray]:
|
|
88
88
|
foldingsTotal = 0
|
|
89
89
|
while True:
|
|
90
|
-
if my[
|
|
91
|
-
if my[
|
|
90
|
+
if my[leaf1ndex] <= 1 or track[leafBelow][0] == 1:
|
|
91
|
+
if my[leaf1ndex] > the[leavesTotal]:
|
|
92
92
|
foldingsTotal += the[leavesTotal]
|
|
93
93
|
else:
|
|
94
94
|
my[unconstrainedLeaf] = 0
|
|
95
|
-
my[gap1ndexCeiling] = track[gapRangeStart][my[
|
|
96
|
-
my[
|
|
95
|
+
my[gap1ndexCeiling] = track[gapRangeStart][my[leaf1ndex] - 1]
|
|
96
|
+
my[gap1ndex] = my[gap1ndexCeiling]
|
|
97
97
|
|
|
98
98
|
for PREPAREdimension1ndex in range(1, the[dimensionsPlus1]):
|
|
99
|
-
if connectionGraph[PREPAREdimension1ndex][my[
|
|
99
|
+
if connectionGraph[PREPAREdimension1ndex][my[leaf1ndex]][my[leaf1ndex]] == my[leaf1ndex]:
|
|
100
100
|
my[unconstrainedLeaf] += 1
|
|
101
101
|
else:
|
|
102
|
-
my[
|
|
103
|
-
while my[
|
|
102
|
+
my[leafConnectee] = connectionGraph[PREPAREdimension1ndex][my[leaf1ndex]][my[leaf1ndex]]
|
|
103
|
+
while my[leafConnectee] != my[leaf1ndex]:
|
|
104
104
|
|
|
105
|
-
if my[
|
|
105
|
+
if my[leafConnectee] != my[leaf1ndex]:
|
|
106
106
|
my[dimension1ndex] = PREPAREdimension1ndex
|
|
107
107
|
return track, gapsWhere, my
|
|
108
108
|
|
|
109
|
-
if my[
|
|
110
|
-
gapsWhere[my[gap1ndexCeiling]] = my[
|
|
111
|
-
if track[countDimensionsGapped][my[
|
|
109
|
+
if my[leaf1ndex] != the[leavesTotal]:
|
|
110
|
+
gapsWhere[my[gap1ndexCeiling]] = my[leafConnectee]
|
|
111
|
+
if track[countDimensionsGapped][my[leafConnectee]] == 0:
|
|
112
112
|
my[gap1ndexCeiling] += 1
|
|
113
|
-
track[countDimensionsGapped][my[
|
|
113
|
+
track[countDimensionsGapped][my[leafConnectee]] += 1
|
|
114
114
|
else:
|
|
115
115
|
print("else")
|
|
116
116
|
my[dimension1ndex] = PREPAREdimension1ndex
|
|
117
117
|
return track, gapsWhere, my
|
|
118
|
-
# PREPAREmy[
|
|
119
|
-
my[
|
|
118
|
+
# PREPAREmy[leafConnectee] % the[leavesTotal] == PREPAREmy[taskIndex]
|
|
119
|
+
my[leafConnectee] = connectionGraph[dimension1ndex][my[leaf1ndex]][track[leafBelow][my[leafConnectee]]]
|
|
120
120
|
|
|
121
121
|
if my[unconstrainedLeaf] == the[dimensionsTotal]:
|
|
122
|
-
for
|
|
123
|
-
gapsWhere[my[gap1ndexCeiling]] =
|
|
122
|
+
for indexLeaf in range(my[leaf1ndex]):
|
|
123
|
+
gapsWhere[my[gap1ndexCeiling]] = indexLeaf
|
|
124
124
|
my[gap1ndexCeiling] += 1
|
|
125
125
|
|
|
126
|
-
for indexMiniGap in range(my[
|
|
127
|
-
gapsWhere[my[
|
|
126
|
+
for indexMiniGap in range(my[gap1ndex], my[gap1ndexCeiling]):
|
|
127
|
+
gapsWhere[my[gap1ndex]] = gapsWhere[indexMiniGap]
|
|
128
128
|
if track[countDimensionsGapped][gapsWhere[indexMiniGap]] == the[dimensionsTotal] - my[unconstrainedLeaf]:
|
|
129
|
-
my[
|
|
129
|
+
my[gap1ndex] += 1
|
|
130
130
|
track[countDimensionsGapped][gapsWhere[indexMiniGap]] = 0
|
|
131
131
|
|
|
132
|
-
while my[
|
|
133
|
-
my[
|
|
134
|
-
track[leafBelow][track[leafAbove][my[
|
|
135
|
-
track[leafAbove][track[leafBelow][my[
|
|
132
|
+
while my[leaf1ndex] > 0 and my[gap1ndex] == track[gapRangeStart][my[leaf1ndex] - 1]:
|
|
133
|
+
my[leaf1ndex] -= 1
|
|
134
|
+
track[leafBelow][track[leafAbove][my[leaf1ndex]]] = track[leafBelow][my[leaf1ndex]]
|
|
135
|
+
track[leafAbove][track[leafBelow][my[leaf1ndex]]] = track[leafAbove][my[leaf1ndex]]
|
|
136
136
|
|
|
137
|
-
if my[
|
|
138
|
-
my[
|
|
139
|
-
track[leafAbove][my[
|
|
140
|
-
track[leafBelow][my[
|
|
141
|
-
track[leafBelow][track[leafAbove][my[
|
|
142
|
-
track[leafAbove][track[leafBelow][my[
|
|
143
|
-
track[gapRangeStart][my[
|
|
144
|
-
my[
|
|
137
|
+
if my[leaf1ndex] > 0:
|
|
138
|
+
my[gap1ndex] -= 1
|
|
139
|
+
track[leafAbove][my[leaf1ndex]] = gapsWhere[my[gap1ndex]]
|
|
140
|
+
track[leafBelow][my[leaf1ndex]] = track[leafBelow][track[leafAbove][my[leaf1ndex]]]
|
|
141
|
+
track[leafBelow][track[leafAbove][my[leaf1ndex]]] = my[leaf1ndex]
|
|
142
|
+
track[leafAbove][track[leafBelow][my[leaf1ndex]]] = my[leaf1ndex]
|
|
143
|
+
track[gapRangeStart][my[leaf1ndex]] = my[gap1ndex]
|
|
144
|
+
my[leaf1ndex] += 1
|
|
145
145
|
|
|
146
146
|
RETURNtrack, RETURNgapsWhere, RETURNmy = prepareWork(TEMPLATEtrack.copy(), TEMPLATEgapsWhere.copy(), TEMPLATEmy.copy())
|
|
147
147
|
|
|
@@ -166,44 +166,44 @@ def doWork(track: NDArray,
|
|
|
166
166
|
thisIsNotTheFirstPass = False
|
|
167
167
|
|
|
168
168
|
while papasGotABrandNewBag:
|
|
169
|
-
if my[
|
|
169
|
+
if my[leaf1ndex] <= 1 or track[leafBelow][0] == 1 or if_activeLeaf1ndex_LTE_1_or_leafBelow_index_0_equals_1 == True:
|
|
170
170
|
if_activeLeaf1ndex_LTE_1_or_leafBelow_index_0_equals_1 = False
|
|
171
|
-
if my[
|
|
171
|
+
if my[leaf1ndex] > the[leavesTotal] and thisIsNotTheFirstPass:
|
|
172
172
|
my[foldingsSubtotal] += the[leavesTotal]
|
|
173
173
|
else:
|
|
174
174
|
if thisIsNotTheFirstPass:
|
|
175
175
|
my[unconstrainedLeaf] = 0
|
|
176
|
-
my[gap1ndexCeiling] = track[gapRangeStart][my[
|
|
177
|
-
my[
|
|
176
|
+
my[gap1ndexCeiling] = track[gapRangeStart][my[leaf1ndex] - 1]
|
|
177
|
+
my[gap1ndex] = my[gap1ndexCeiling]
|
|
178
178
|
|
|
179
179
|
for_dimension1ndex_in_range_1_to_dimensionsPlus1 = True
|
|
180
180
|
while for_dimension1ndex_in_range_1_to_dimensionsPlus1 == True:
|
|
181
181
|
for_dimension1ndex_in_range_1_to_dimensionsPlus1 = False
|
|
182
|
-
if connectionGraph[my[dimension1ndex]][my[
|
|
182
|
+
if connectionGraph[my[dimension1ndex]][my[leaf1ndex]][my[leaf1ndex]] == my[leaf1ndex] and thisIsNotTheFirstPass:
|
|
183
183
|
my[unconstrainedLeaf] += 1
|
|
184
184
|
else:
|
|
185
185
|
if thisIsNotTheFirstPass:
|
|
186
|
-
my[
|
|
187
|
-
if my[
|
|
186
|
+
my[leafConnectee] = connectionGraph[my[dimension1ndex]][my[leaf1ndex]][my[leaf1ndex]]
|
|
187
|
+
if my[leafConnectee] != my[leaf1ndex]:
|
|
188
188
|
while_leaf1ndexConnectee_notEquals_activeLeaf1ndex = True
|
|
189
189
|
|
|
190
190
|
while while_leaf1ndexConnectee_notEquals_activeLeaf1ndex == True:
|
|
191
191
|
while_leaf1ndexConnectee_notEquals_activeLeaf1ndex = False
|
|
192
192
|
thisIsNotTheFirstPass = True
|
|
193
|
-
if taskDivisions==0 or my[
|
|
193
|
+
if taskDivisions==0 or my[leaf1ndex] != taskDivisions:
|
|
194
194
|
myTask = True
|
|
195
195
|
else:
|
|
196
|
-
modulo = my[
|
|
196
|
+
modulo = my[leafConnectee] % the[leavesTotal]
|
|
197
197
|
if modulo == my[taskIndex]: myTask = True
|
|
198
198
|
else:
|
|
199
199
|
myTask = False
|
|
200
200
|
if myTask:
|
|
201
|
-
gapsWhere[my[gap1ndexCeiling]] = my[
|
|
202
|
-
if track[countDimensionsGapped][my[
|
|
201
|
+
gapsWhere[my[gap1ndexCeiling]] = my[leafConnectee]
|
|
202
|
+
if track[countDimensionsGapped][my[leafConnectee]] == 0:
|
|
203
203
|
my[gap1ndexCeiling] += 1
|
|
204
|
-
track[countDimensionsGapped][my[
|
|
205
|
-
my[
|
|
206
|
-
if my[
|
|
204
|
+
track[countDimensionsGapped][my[leafConnectee]] += 1
|
|
205
|
+
my[leafConnectee] = connectionGraph[my[dimension1ndex]][my[leaf1ndex]][track[leafBelow][my[leafConnectee]]]
|
|
206
|
+
if my[leafConnectee] != my[leaf1ndex]:
|
|
207
207
|
while_leaf1ndexConnectee_notEquals_activeLeaf1ndex = True
|
|
208
208
|
my[dimension1ndex] += 1
|
|
209
209
|
if my[dimension1ndex] < the[dimensionsPlus1]:
|
|
@@ -212,29 +212,29 @@ def doWork(track: NDArray,
|
|
|
212
212
|
my[dimension1ndex] = 1
|
|
213
213
|
|
|
214
214
|
if my[unconstrainedLeaf] == the[dimensionsTotal]:
|
|
215
|
-
for leaf1ndex in range(my[
|
|
215
|
+
for leaf1ndex in range(my[leaf1ndex]):
|
|
216
216
|
gapsWhere[my[gap1ndexCeiling]] = leaf1ndex
|
|
217
217
|
my[gap1ndexCeiling] += 1
|
|
218
218
|
|
|
219
|
-
for indexMiniGap in range(my[
|
|
220
|
-
gapsWhere[my[
|
|
219
|
+
for indexMiniGap in range(my[gap1ndex], my[gap1ndexCeiling]):
|
|
220
|
+
gapsWhere[my[gap1ndex]] = gapsWhere[indexMiniGap]
|
|
221
221
|
if track[countDimensionsGapped][gapsWhere[indexMiniGap]] == the[dimensionsTotal] - my[unconstrainedLeaf]:
|
|
222
|
-
my[
|
|
222
|
+
my[gap1ndex] += 1
|
|
223
223
|
track[countDimensionsGapped][gapsWhere[indexMiniGap]] = 0
|
|
224
224
|
|
|
225
|
-
while my[
|
|
226
|
-
my[
|
|
227
|
-
track[leafBelow][track[leafAbove][my[
|
|
228
|
-
track[leafAbove][track[leafBelow][my[
|
|
229
|
-
|
|
230
|
-
if my[
|
|
231
|
-
my[
|
|
232
|
-
track[leafAbove][my[
|
|
233
|
-
track[leafBelow][my[
|
|
234
|
-
track[leafBelow][track[leafAbove][my[
|
|
235
|
-
track[leafAbove][track[leafBelow][my[
|
|
236
|
-
track[gapRangeStart][my[
|
|
237
|
-
my[
|
|
238
|
-
|
|
239
|
-
if my[
|
|
225
|
+
while my[leaf1ndex] > 0 and my[gap1ndex] == track[gapRangeStart][my[leaf1ndex] - 1]:
|
|
226
|
+
my[leaf1ndex] -= 1
|
|
227
|
+
track[leafBelow][track[leafAbove][my[leaf1ndex]]] = track[leafBelow][my[leaf1ndex]]
|
|
228
|
+
track[leafAbove][track[leafBelow][my[leaf1ndex]]] = track[leafAbove][my[leaf1ndex]]
|
|
229
|
+
|
|
230
|
+
if my[leaf1ndex] > 0:
|
|
231
|
+
my[gap1ndex] -= 1
|
|
232
|
+
track[leafAbove][my[leaf1ndex]] = gapsWhere[my[gap1ndex]]
|
|
233
|
+
track[leafBelow][my[leaf1ndex]] = track[leafBelow][track[leafAbove][my[leaf1ndex]]]
|
|
234
|
+
track[leafBelow][track[leafAbove][my[leaf1ndex]]] = my[leaf1ndex]
|
|
235
|
+
track[leafAbove][track[leafBelow][my[leaf1ndex]]] = my[leaf1ndex]
|
|
236
|
+
track[gapRangeStart][my[leaf1ndex]] = my[gap1ndex]
|
|
237
|
+
my[leaf1ndex] += 1
|
|
238
|
+
|
|
239
|
+
if my[leaf1ndex] <= 0:
|
|
240
240
|
return my[foldingsSubtotal]
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
from numba import njit
|
|
2
|
+
import numpy
|
|
3
|
+
|
|
4
|
+
@njit(cache=True)
|
|
5
|
+
def foldings_plus_1(p: list[int], computationDivisions: int = 0, computationIndex: int = 0) -> int:
|
|
6
|
+
n: int = 1 # Total number of leaves
|
|
7
|
+
for dimension in p:
|
|
8
|
+
n *= dimension
|
|
9
|
+
|
|
10
|
+
d = len(p) # Number of dimensions
|
|
11
|
+
# Compute arrays P, C, D as per the algorithm
|
|
12
|
+
P = numpy.ones(d + 1, dtype=numpy.int64)
|
|
13
|
+
for i in range(1, d + 1):
|
|
14
|
+
P[i] = P[i - 1] * p[i - 1]
|
|
15
|
+
|
|
16
|
+
# C[i][m] holds the i-th coordinate of leaf m
|
|
17
|
+
C = numpy.zeros((d + 1, n + 1), dtype=numpy.int64)
|
|
18
|
+
for i in range(1, d + 1):
|
|
19
|
+
for m in range(1, n + 1):
|
|
20
|
+
C[i][m] = ((m - 1) // P[i - 1]) - ((m - 1) // P[i]) * p[i - 1] + 1
|
|
21
|
+
|
|
22
|
+
# D[i][l][m] computes the leaf connected to m in section i when inserting l
|
|
23
|
+
D = numpy.zeros((d + 1, n + 1, n + 1), dtype=numpy.int64)
|
|
24
|
+
for i in range(1, d + 1):
|
|
25
|
+
for l in range(1, n + 1):
|
|
26
|
+
for m in range(1, l + 1):
|
|
27
|
+
delta = C[i][l] - C[i][m]
|
|
28
|
+
if delta % 2 == 0:
|
|
29
|
+
# If delta is even
|
|
30
|
+
if C[i][m] == 1:
|
|
31
|
+
D[i][l][m] = m
|
|
32
|
+
else:
|
|
33
|
+
D[i][l][m] = m - P[i - 1]
|
|
34
|
+
else:
|
|
35
|
+
# If delta is odd
|
|
36
|
+
if C[i][m] == p[i - 1] or m + P[i - 1] > l:
|
|
37
|
+
D[i][l][m] = m
|
|
38
|
+
else:
|
|
39
|
+
D[i][l][m] = m + P[i - 1]
|
|
40
|
+
# Initialize arrays/lists
|
|
41
|
+
A = numpy.zeros(n + 1, dtype=numpy.int64) # Leaf above leaf m
|
|
42
|
+
B = numpy.zeros(n + 1, dtype=numpy.int64) # Leaf below leaf m
|
|
43
|
+
count = numpy.zeros(n + 1, dtype=numpy.int64) # Counts for potential gaps
|
|
44
|
+
gapter = numpy.zeros(n + 1, dtype=numpy.int64) # Indices for gap stack per leaf
|
|
45
|
+
gap = numpy.zeros(n * n + 1, dtype=numpy.int64) # Stack of potential gaps
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Initialize variables for backtracking
|
|
49
|
+
total_count = 0 # Total number of foldings
|
|
50
|
+
g = 0 # Gap index
|
|
51
|
+
l = 1 # Current leaf
|
|
52
|
+
|
|
53
|
+
# Start backtracking loop
|
|
54
|
+
while l > 0:
|
|
55
|
+
# If we have processed all leaves, increment total count
|
|
56
|
+
if l > n:
|
|
57
|
+
total_count += 1
|
|
58
|
+
else:
|
|
59
|
+
dd = 0 # Number of sections where leaf l is unconstrained
|
|
60
|
+
gg = g # Temporary gap index
|
|
61
|
+
g = gapter[l - 1] # Reset gap index for current leaf
|
|
62
|
+
|
|
63
|
+
# Count possible gaps for leaf l in each section
|
|
64
|
+
for i in range(1, d + 1):
|
|
65
|
+
if D[i][l][l] == l:
|
|
66
|
+
dd += 1
|
|
67
|
+
else:
|
|
68
|
+
m = D[i][l][l]
|
|
69
|
+
while m != l:
|
|
70
|
+
if computationDivisions == 0 or l != computationDivisions or m % computationDivisions == computationIndex:
|
|
71
|
+
gap[gg] = m
|
|
72
|
+
if count[m] == 0:
|
|
73
|
+
gg += 1
|
|
74
|
+
count[m] += 1
|
|
75
|
+
m = D[i][l][B[m]]
|
|
76
|
+
|
|
77
|
+
# If leaf l is unconstrained in all sections, it can be inserted anywhere
|
|
78
|
+
if dd == d:
|
|
79
|
+
for m in range(l):
|
|
80
|
+
gap[gg] = m
|
|
81
|
+
gg += 1
|
|
82
|
+
|
|
83
|
+
# Filter gaps that are common to all sections
|
|
84
|
+
for j in range(g, gg):
|
|
85
|
+
gap[g] = gap[j]
|
|
86
|
+
if count[gap[j]] == d - dd:
|
|
87
|
+
g += 1
|
|
88
|
+
count[gap[j]] = 0 # Reset count for next iteration
|
|
89
|
+
|
|
90
|
+
# Recursive backtracking steps
|
|
91
|
+
while l > 0 and g == gapter[l - 1]:
|
|
92
|
+
l -= 1
|
|
93
|
+
B[A[l]] = B[l]
|
|
94
|
+
A[B[l]] = A[l]
|
|
95
|
+
|
|
96
|
+
if l > 0:
|
|
97
|
+
g -= 1
|
|
98
|
+
A[l] = gap[g]
|
|
99
|
+
B[l] = B[A[l]]
|
|
100
|
+
B[A[l]] = l
|
|
101
|
+
A[B[l]] = l
|
|
102
|
+
gapter[l] = g # Save current gap index
|
|
103
|
+
l += 1 # Move to next leaf
|
|
104
|
+
|
|
105
|
+
return total_count
|
|
106
|
+
|
|
107
|
+
@njit(cache=True)
|
|
108
|
+
def foldings(p: list[int], computationDivisions: int = 0, computationIndex: int = 0) -> int:
|
|
109
|
+
n: int = 1 # Total number of leaves
|
|
110
|
+
for dimension in p:
|
|
111
|
+
n *= dimension
|
|
112
|
+
|
|
113
|
+
d = len(p) # Number of dimensions
|
|
114
|
+
# Compute arrays P, C, D as per the algorithm
|
|
115
|
+
P = numpy.ones(d + 1, dtype=numpy.int64)
|
|
116
|
+
for i in range(1, d + 1):
|
|
117
|
+
P[i] = P[i - 1] * p[i - 1]
|
|
118
|
+
|
|
119
|
+
# C[i][m] holds the i-th coordinate of leaf m
|
|
120
|
+
C = numpy.zeros((d + 1, n + 1), dtype=numpy.int64)
|
|
121
|
+
for i in range(1, d + 1):
|
|
122
|
+
for m in range(1, n + 1):
|
|
123
|
+
C[i][m] = ((m - 1) // P[i - 1]) - ((m - 1) // P[i]) * p[i - 1] + 1
|
|
124
|
+
# C[i][m] = ((m - 1) // P[i - 1]) % p[i - 1] + 1 # NOTE different, but either one works
|
|
125
|
+
|
|
126
|
+
# D[i][l][m] computes the leaf connected to m in section i when inserting l
|
|
127
|
+
D = numpy.zeros((d + 1, n + 1, n + 1), dtype=numpy.int64)
|
|
128
|
+
for i in range(1, d + 1):
|
|
129
|
+
for l in range(1, n + 1):
|
|
130
|
+
for m in range(1, l + 1):
|
|
131
|
+
delta = C[i][l] - C[i][m]
|
|
132
|
+
if delta % 2 == 0:
|
|
133
|
+
# If delta is even
|
|
134
|
+
if C[i][m] == 1:
|
|
135
|
+
D[i][l][m] = m
|
|
136
|
+
else:
|
|
137
|
+
D[i][l][m] = m - P[i - 1]
|
|
138
|
+
else:
|
|
139
|
+
# If delta is odd
|
|
140
|
+
if C[i][m] == p[i - 1] or m + P[i - 1] > l:
|
|
141
|
+
D[i][l][m] = m
|
|
142
|
+
else:
|
|
143
|
+
D[i][l][m] = m + P[i - 1]
|
|
144
|
+
# Initialize arrays/lists
|
|
145
|
+
A = numpy.zeros(n + 1, dtype=numpy.int64) # Leaf above leaf m
|
|
146
|
+
B = numpy.zeros(n + 1, dtype=numpy.int64) # Leaf below leaf m
|
|
147
|
+
count = numpy.zeros(n + 1, dtype=numpy.int64) # Counts for potential gaps
|
|
148
|
+
gapter = numpy.zeros(n + 1, dtype=numpy.int64) # Indices for gap stack per leaf
|
|
149
|
+
gap = numpy.zeros(n * n + 1, dtype=numpy.int64) # Stack of potential gaps
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# Initialize variables for backtracking
|
|
153
|
+
total_count = 0 # Total number of foldings
|
|
154
|
+
g = 0 # Gap index
|
|
155
|
+
l = 1 # Current leaf
|
|
156
|
+
|
|
157
|
+
# Start backtracking loop
|
|
158
|
+
while l > 0:
|
|
159
|
+
if l <= 1 or B[0] == 1: # NOTE different
|
|
160
|
+
# NOTE the above `if` statement encloses the the if/else block below
|
|
161
|
+
# NOTE these changes increase the throughput by more than an order of magnitude
|
|
162
|
+
if l > n:
|
|
163
|
+
total_count += n
|
|
164
|
+
else:
|
|
165
|
+
dd = 0 # Number of sections where leaf l is unconstrained
|
|
166
|
+
gg = gapter[l - 1] # Track possible gaps # NOTE different, but not important
|
|
167
|
+
g = gg # NOTE different, but not important
|
|
168
|
+
|
|
169
|
+
# Count possible gaps for leaf l in each section
|
|
170
|
+
for i in range(1, d + 1):
|
|
171
|
+
if D[i][l][l] == l:
|
|
172
|
+
dd += 1
|
|
173
|
+
else:
|
|
174
|
+
m = D[i][l][l]
|
|
175
|
+
while m != l:
|
|
176
|
+
if computationDivisions == 0 or l != computationDivisions or m % computationDivisions == computationIndex:
|
|
177
|
+
gap[gg] = m
|
|
178
|
+
if count[m] == 0:
|
|
179
|
+
gg += 1
|
|
180
|
+
count[m] += 1
|
|
181
|
+
m = D[i][l][B[m]]
|
|
182
|
+
|
|
183
|
+
# If leaf l is unconstrained in all sections, it can be inserted anywhere
|
|
184
|
+
if dd == d:
|
|
185
|
+
for m in range(l):
|
|
186
|
+
gap[gg] = m
|
|
187
|
+
gg += 1
|
|
188
|
+
|
|
189
|
+
# Filter gaps that are common to all sections
|
|
190
|
+
for j in range(g, gg):
|
|
191
|
+
gap[g] = gap[j]
|
|
192
|
+
if count[gap[j]] == d - dd:
|
|
193
|
+
g += 1
|
|
194
|
+
count[gap[j]] = 0 # Reset count for next iteration
|
|
195
|
+
|
|
196
|
+
# Recursive backtracking steps
|
|
197
|
+
while l > 0 and g == gapter[l - 1]:
|
|
198
|
+
l -= 1
|
|
199
|
+
B[A[l]] = B[l]
|
|
200
|
+
A[B[l]] = A[l]
|
|
201
|
+
|
|
202
|
+
if l > 0:
|
|
203
|
+
g -= 1
|
|
204
|
+
A[l] = gap[g]
|
|
205
|
+
B[l] = B[A[l]]
|
|
206
|
+
B[A[l]] = l
|
|
207
|
+
A[B[l]] = l
|
|
208
|
+
gapter[l] = g # Save current gap index
|
|
209
|
+
l += 1 # Move to next leaf
|
|
210
|
+
|
|
211
|
+
return total_count
|
mapFolding/startHere.py
CHANGED
|
@@ -13,7 +13,7 @@ def countFolds(listDimensions: Sequence[int], writeFoldsTotal: Optional[Union[st
|
|
|
13
13
|
computationDivisions (None):
|
|
14
14
|
Whether and how to divide the computational work. See notes for details.
|
|
15
15
|
CPUlimit (None): This is only relevant if there are `computationDivisions`: whether and how to limit the CPU usage. See notes for details.
|
|
16
|
-
**keywordArguments: Additional arguments including dtypeDefault and dtypeLarge for data type specifications.
|
|
16
|
+
**keywordArguments: Additional arguments including `dtypeDefault` and `dtypeLarge` for data type specifications.
|
|
17
17
|
Returns:
|
|
18
18
|
foldsTotal: Total number of distinct ways to fold a map of the given dimensions.
|
|
19
19
|
|
|
@@ -54,9 +54,7 @@ def countFolds(listDimensions: Sequence[int], writeFoldsTotal: Optional[Union[st
|
|
|
54
54
|
pathFilenameFoldsTotal.write_text(str(foldsTotal))
|
|
55
55
|
except Exception as ERRORmessage:
|
|
56
56
|
print(ERRORmessage)
|
|
57
|
-
print("\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal")
|
|
58
|
-
print(f"{foldsTotal=}")
|
|
59
|
-
print("\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal")
|
|
57
|
+
print(f"\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal\n\n{foldsTotal=}\n\nfoldsTotal foldsTotal foldsTotal foldsTotal foldsTotal")
|
|
60
58
|
|
|
61
59
|
return foldsTotal
|
|
62
60
|
|
mapFolding/theSSOT.py
CHANGED
|
@@ -5,6 +5,10 @@ import numpy.typing
|
|
|
5
5
|
import pathlib
|
|
6
6
|
import sys
|
|
7
7
|
|
|
8
|
+
dtypeLarge = numpy.int64
|
|
9
|
+
dtypeDefault = dtypeLarge
|
|
10
|
+
dtypeSmall = dtypeDefault
|
|
11
|
+
|
|
8
12
|
try:
|
|
9
13
|
_pathModule = pathlib.Path(__file__).parent
|
|
10
14
|
except NameError:
|
|
@@ -24,7 +28,8 @@ class EnumIndices(enum.IntEnum):
|
|
|
24
28
|
return count
|
|
25
29
|
|
|
26
30
|
def __index__(self) -> int:
|
|
27
|
-
"""
|
|
31
|
+
"""Adapt enum to the ultra-rare event of indexing a NumPy 'ndarray', which is not the
|
|
32
|
+
same as `array.array`. See NumPy.org; I think it will be very popular someday."""
|
|
28
33
|
return self.value
|
|
29
34
|
|
|
30
35
|
class indexMy(EnumIndices):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: mapFolding
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Algorithm(s) for counting distinct ways to fold a map (or a strip of stamps)
|
|
5
5
|
Author-email: Hunter Hogan <HunterHogan@pm.me>
|
|
6
6
|
Project-URL: homepage, https://github.com/hunterhogan/mapFolding
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
mapFolding/__init__.py,sha256=POxXTSE6Qu1G8k-YlSXHzbe-_JGuHk-L9p5SLRng4vA,439
|
|
2
|
+
mapFolding/babbage.py,sha256=3D1qcntoiJm2tqgbiCAMc7GpGA0SZTdGORNEnensyxk,1882
|
|
3
|
+
mapFolding/beDRY.py,sha256=ZrUXCNqnumTQ1XX8RT5gGdRr-a-o8QxEiGrerUxKtYg,12784
|
|
4
|
+
mapFolding/lovelace.py,sha256=qcyGpVEPP3n0r-RNrSUgPRP3yZJfBEfmok7jYMm1OI0,11473
|
|
5
|
+
mapFolding/oeis.py,sha256=_-fLGc1ybZ2eFxoiBrSmojMexeg6ROxtrLaBF2BzMn4,12144
|
|
6
|
+
mapFolding/startHere.py,sha256=RGdFoJJdrJ_0tmLIKZn1WnHP0NCZwvQG7C2p4EUHOe4,5034
|
|
7
|
+
mapFolding/theSSOT.py,sha256=yRW6aHyJxheL-Znk537LQA6xUPHz6FfoXY-0Ayh3Lsg,2178
|
|
8
|
+
mapFolding/JAX/lunnanJAX.py,sha256=xMZloN47q-MVfjdYOM1hi9qR4OnLq7qALmGLMraevQs,14819
|
|
9
|
+
mapFolding/JAX/taskJAX.py,sha256=yJNeH0rL6EhJ6ppnATHF0Zf81CDMC10bnPnimVxE1hc,20037
|
|
10
|
+
mapFolding/benchmarks/benchmarking.py,sha256=kv85F6V9pGhZvTOImArOuxyg5rywA_T6JLH_qFXM8BM,3018
|
|
11
|
+
mapFolding/benchmarks/test_benchmarks.py,sha256=c4ANeR3jgqpKXFoxDeZkmAHxSuenMwsjmrhKJ1_XPqY,3659
|
|
12
|
+
mapFolding/reference/hunterNumba.py,sha256=0giUyqAFzP-XKcq3Kz8wIWCK0BVFhjABVJ1s-w4Jhu0,7109
|
|
13
|
+
mapFolding/reference/irvineJavaPort.py,sha256=Sj-63Z-OsGuDoEBXuxyjRrNmmyl0d7Yz_XuY7I47Oyg,4250
|
|
14
|
+
mapFolding/reference/lunnan.py,sha256=XEcql_gxvCCghb6Or3qwmPbn4IZUbZTaSmw_fUjRxZE,5037
|
|
15
|
+
mapFolding/reference/lunnanNumpy.py,sha256=HqDgSwTOZA-G0oophOEfc4zs25Mv4yw2aoF1v8miOLk,4653
|
|
16
|
+
mapFolding/reference/lunnanWhile.py,sha256=7NY2IKO5XBgol0aWWF_Fi-7oTL9pvu_z6lB0TF1uVHk,4063
|
|
17
|
+
mapFolding/reference/rotatedEntryPoint.py,sha256=z0QyDQtnMvXNj5ntWzzJUQUMFm1-xHGLVhtYzwmczUI,11530
|
|
18
|
+
mapFolding/reference/total_countPlus1vsPlusN.py,sha256=usenM8Yn_G1dqlPl7NKKkcnbohBZVZBXTQRm2S3_EDA,8106
|
|
19
|
+
tests/__init__.py,sha256=PGYVr7r23gATgcvZ3Sfph9D_g1MVvhgzMNWXBs_9tmY,52
|
|
20
|
+
tests/conftest.py,sha256=VFYSd7-tHWd-LUKnTY24PIJhq9quP9S3sK2SYusNNog,12875
|
|
21
|
+
tests/test_oeis.py,sha256=vxnwO-cSR68htkyMh9QMVv-lvxBo6qlwPg1Rbx4JylY,7963
|
|
22
|
+
tests/test_other.py,sha256=cf8DbkZxm_DHNq9lkMe7auXye_XspruU9qiNZATkxr4,6930
|
|
23
|
+
tests/test_tasks.py,sha256=Nwe4iuSjwGZvsw5CXCcic7tkBxgM5JX9mrGZMDYhAwE,1785
|
|
24
|
+
mapFolding-0.2.2.dist-info/METADATA,sha256=BSCXcKZDhAtOWr8A5pZMG8bZnm5YBLf-6uMN9qs8JDk,5914
|
|
25
|
+
mapFolding-0.2.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
26
|
+
mapFolding-0.2.2.dist-info/entry_points.txt,sha256=F3OUeZR1XDTpoH7k3wXuRb3KF_kXTTeYhu5AGK1SiOQ,146
|
|
27
|
+
mapFolding-0.2.2.dist-info/top_level.txt,sha256=1gP2vFaqPwHujGwb3UjtMlLEGN-943VSYFR7V4gDqW8,17
|
|
28
|
+
mapFolding-0.2.2.dist-info/RECORD,,
|