mapFolding 0.8.0__py3-none-any.whl → 0.8.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 +33 -4
- mapFolding/basecamp.py +16 -2
- mapFolding/beDRY.py +40 -32
- mapFolding/filesystem.py +124 -90
- mapFolding/noHomeYet.py +12 -0
- mapFolding/oeis.py +18 -3
- mapFolding/reference/__init__.py +38 -0
- mapFolding/reference/flattened.py +66 -47
- mapFolding/reference/hunterNumba.py +28 -4
- mapFolding/reference/irvineJavaPort.py +13 -1
- mapFolding/reference/{jax.py → jaxCount.py} +46 -27
- mapFolding/reference/lunnanNumpy.py +19 -5
- mapFolding/reference/lunnanWhile.py +19 -7
- mapFolding/reference/rotatedEntryPoint.py +20 -3
- mapFolding/reference/total_countPlus1vsPlusN.py +226 -203
- mapFolding/someAssemblyRequired/__init__.py +29 -0
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +32 -14
- mapFolding/someAssemblyRequired/ingredientsNumba.py +22 -1
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +193 -0
- mapFolding/someAssemblyRequired/synthesizeNumbaJobVESTIGIAL.py +3 -4
- mapFolding/someAssemblyRequired/transformDataStructures.py +168 -0
- mapFolding/someAssemblyRequired/transformationTools.py +233 -225
- mapFolding/theDao.py +19 -5
- mapFolding/theSSOT.py +89 -122
- mapfolding-0.8.2.dist-info/METADATA +187 -0
- mapfolding-0.8.2.dist-info/RECORD +39 -0
- {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/WHEEL +1 -1
- tests/conftest.py +43 -33
- tests/test_computations.py +7 -7
- tests/test_other.py +2 -2
- mapFolding/reference/lunnan.py +0 -153
- mapFolding/someAssemblyRequired/Z0Z_workbench.py +0 -350
- mapFolding/someAssemblyRequired/synthesizeDataConverters.py +0 -117
- mapFolding/syntheticModules/numbaCountHistoricalExample.py +0 -158
- mapFolding/syntheticModules/numba_doTheNeedfulHistoricalExample.py +0 -13
- mapfolding-0.8.0.dist-info/METADATA +0 -157
- mapfolding-0.8.0.dist-info/RECORD +0 -41
- {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info/licenses}/LICENSE +0 -0
- {mapfolding-0.8.0.dist-info → mapfolding-0.8.2.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,33 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
1
|
+
"""
|
|
2
|
+
Semantically decomposed implementation of Lunnon's algorithm with operation grouping.
|
|
3
|
+
|
|
4
|
+
This implementation restructures the map folding algorithm into semantic sections with
|
|
5
|
+
clear function boundaries, making the algorithm more readable and understandable. Each
|
|
6
|
+
operation is isolated into its own named function, providing a clear mapping between
|
|
7
|
+
the mathematical concepts and their implementation.
|
|
8
|
+
|
|
9
|
+
Key characteristics:
|
|
10
|
+
- Breaks down the algorithm into small, single-purpose functions
|
|
11
|
+
- Uses descriptive function names that explain what each part does
|
|
12
|
+
- Clearly separates logical sections of the algorithm
|
|
13
|
+
- Provides a more maintainable and educational view of the algorithm
|
|
14
|
+
- Uses Python's type hints for better code understanding
|
|
15
|
+
|
|
16
|
+
This implementation serves as a bridge between the historical implementations and the
|
|
17
|
+
modern functional approach used in the main package. It's particularly valuable for
|
|
18
|
+
understanding the algorithm's operation before diving into the highly optimized versions.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from collections.abc import Sequence
|
|
3
22
|
from numpy import integer
|
|
4
23
|
from numpy.typing import NDArray
|
|
5
|
-
from typing import
|
|
24
|
+
from typing import Any, Final, TypedDict
|
|
6
25
|
import enum
|
|
7
26
|
import numpy
|
|
8
27
|
import sys
|
|
9
28
|
|
|
10
|
-
def countFolds(listDimensions: Sequence[int], computationDivisions = None, CPUlimit:
|
|
11
|
-
def doWhile():
|
|
29
|
+
def countFolds(listDimensions: Sequence[int], computationDivisions: int | str | None = None, CPUlimit: int | float | bool | None = None) -> int:
|
|
30
|
+
def doWhile() -> None:
|
|
12
31
|
|
|
13
32
|
while activeLeafGreaterThan0Condition():
|
|
14
33
|
|
|
@@ -49,99 +68,99 @@ def countFolds(listDimensions: Sequence[int], computationDivisions = None, CPUli
|
|
|
49
68
|
if placeLeafCondition():
|
|
50
69
|
placeLeaf()
|
|
51
70
|
|
|
52
|
-
def activeGapIncrement():
|
|
71
|
+
def activeGapIncrement() -> None:
|
|
53
72
|
my[indexMy.gap1ndex] += 1
|
|
54
73
|
|
|
55
|
-
def activeLeafGreaterThan0Condition():
|
|
74
|
+
def activeLeafGreaterThan0Condition() -> bool:
|
|
56
75
|
return my[indexMy.leaf1ndex] > 0
|
|
57
76
|
|
|
58
|
-
def activeLeafGreaterThanLeavesTotalCondition():
|
|
77
|
+
def activeLeafGreaterThanLeavesTotalCondition() -> bool:
|
|
59
78
|
return my[indexMy.leaf1ndex] > the[indexThe.leavesTotal]
|
|
60
79
|
|
|
61
|
-
def activeLeafIsTheFirstLeafCondition():
|
|
80
|
+
def activeLeafIsTheFirstLeafCondition() -> bool:
|
|
62
81
|
return my[indexMy.leaf1ndex] <= 1
|
|
63
82
|
|
|
64
|
-
def activeLeafNotEqualToTaskDivisionsCondition():
|
|
83
|
+
def activeLeafNotEqualToTaskDivisionsCondition() -> bool:
|
|
65
84
|
return my[indexMy.leaf1ndex] != the[indexThe.taskDivisions]
|
|
66
85
|
|
|
67
|
-
def allDimensionsAreUnconstrained():
|
|
86
|
+
def allDimensionsAreUnconstrained() -> bool:
|
|
68
87
|
return my[indexMy.dimensionsUnconstrained] == the[indexThe.dimensionsTotal]
|
|
69
88
|
|
|
70
|
-
def backtrack():
|
|
89
|
+
def backtrack() -> None:
|
|
71
90
|
my[indexMy.leaf1ndex] -= 1
|
|
72
91
|
track[indexTrack.leafBelow, track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]] = track[indexTrack.leafBelow, my[indexMy.leaf1ndex]]
|
|
73
92
|
track[indexTrack.leafAbove, track[indexTrack.leafBelow, my[indexMy.leaf1ndex]]] = track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]
|
|
74
93
|
|
|
75
|
-
def backtrackCondition():
|
|
94
|
+
def backtrackCondition() -> bool:
|
|
76
95
|
return my[indexMy.leaf1ndex] > 0 and my[indexMy.gap1ndex] == track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex] - 1]
|
|
77
96
|
|
|
78
|
-
def computationDivisionsCondition():
|
|
97
|
+
def computationDivisionsCondition() -> bool:
|
|
79
98
|
return the[indexThe.taskDivisions] == int(False)
|
|
80
99
|
|
|
81
|
-
def countGaps():
|
|
100
|
+
def countGaps() -> None:
|
|
82
101
|
gapsWhere[my[indexMy.gap1ndexCeiling]] = my[indexMy.leafConnectee]
|
|
83
102
|
if track[indexTrack.countDimensionsGapped, my[indexMy.leafConnectee]] == 0:
|
|
84
103
|
gap1ndexCeilingIncrement()
|
|
85
104
|
track[indexTrack.countDimensionsGapped, my[indexMy.leafConnectee]] += 1
|
|
86
105
|
|
|
87
|
-
def dimension1ndexIncrement():
|
|
106
|
+
def dimension1ndexIncrement() -> None:
|
|
88
107
|
my[indexMy.dimension1ndex] += 1
|
|
89
108
|
|
|
90
|
-
def dimensionsUnconstrainedCondition():
|
|
109
|
+
def dimensionsUnconstrainedCondition() -> bool:
|
|
91
110
|
return connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], my[indexMy.leaf1ndex]] == my[indexMy.leaf1ndex]
|
|
92
111
|
|
|
93
|
-
def dimensionsUnconstrainedIncrement():
|
|
112
|
+
def dimensionsUnconstrainedIncrement() -> None:
|
|
94
113
|
my[indexMy.dimensionsUnconstrained] += 1
|
|
95
114
|
|
|
96
|
-
def filterCommonGaps():
|
|
115
|
+
def filterCommonGaps() -> None:
|
|
97
116
|
gapsWhere[my[indexMy.gap1ndex]] = gapsWhere[my[indexMy.indexMiniGap]]
|
|
98
117
|
if track[indexTrack.countDimensionsGapped, gapsWhere[my[indexMy.indexMiniGap]]] == the[indexThe.dimensionsTotal] - my[indexMy.dimensionsUnconstrained]:
|
|
99
118
|
activeGapIncrement()
|
|
100
119
|
track[indexTrack.countDimensionsGapped, gapsWhere[my[indexMy.indexMiniGap]]] = 0
|
|
101
120
|
|
|
102
|
-
def findGapsInitializeVariables():
|
|
121
|
+
def findGapsInitializeVariables() -> None:
|
|
103
122
|
my[indexMy.dimensionsUnconstrained] = 0
|
|
104
123
|
my[indexMy.gap1ndexCeiling] = track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex] - 1]
|
|
105
124
|
my[indexMy.dimension1ndex] = 1
|
|
106
125
|
|
|
107
|
-
def foldsSubTotalsIncrement():
|
|
126
|
+
def foldsSubTotalsIncrement() -> None:
|
|
108
127
|
foldsSubTotals[my[indexMy.taskIndex]] += the[indexThe.leavesTotal]
|
|
109
128
|
|
|
110
|
-
def gap1ndexCeilingIncrement():
|
|
129
|
+
def gap1ndexCeilingIncrement() -> None:
|
|
111
130
|
my[indexMy.gap1ndexCeiling] += 1
|
|
112
131
|
|
|
113
|
-
def indexMiniGapIncrement():
|
|
132
|
+
def indexMiniGapIncrement() -> None:
|
|
114
133
|
my[indexMy.indexMiniGap] += 1
|
|
115
134
|
|
|
116
|
-
def indexMiniGapInitialization():
|
|
135
|
+
def indexMiniGapInitialization() -> None:
|
|
117
136
|
my[indexMy.indexMiniGap] = my[indexMy.gap1ndex]
|
|
118
137
|
|
|
119
|
-
def insertUnconstrainedLeaf():
|
|
138
|
+
def insertUnconstrainedLeaf() -> None:
|
|
120
139
|
my[indexMy.indexLeaf] = 0
|
|
121
140
|
while my[indexMy.indexLeaf] < my[indexMy.leaf1ndex]:
|
|
122
141
|
gapsWhere[my[indexMy.gap1ndexCeiling]] = my[indexMy.indexLeaf]
|
|
123
142
|
my[indexMy.gap1ndexCeiling] += 1
|
|
124
143
|
my[indexMy.indexLeaf] += 1
|
|
125
144
|
|
|
126
|
-
def leafBelowSentinelIs1Condition():
|
|
145
|
+
def leafBelowSentinelIs1Condition() -> bool:
|
|
127
146
|
return track[indexTrack.leafBelow, 0] == 1
|
|
128
147
|
|
|
129
|
-
def leafConnecteeInitialization():
|
|
148
|
+
def leafConnecteeInitialization() -> None:
|
|
130
149
|
my[indexMy.leafConnectee] = connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], my[indexMy.leaf1ndex]]
|
|
131
150
|
|
|
132
|
-
def leafConnecteeUpdate():
|
|
151
|
+
def leafConnecteeUpdate() -> None:
|
|
133
152
|
my[indexMy.leafConnectee] = connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], track[indexTrack.leafBelow, my[indexMy.leafConnectee]]]
|
|
134
153
|
|
|
135
|
-
def loopingLeavesConnectedToActiveLeaf():
|
|
154
|
+
def loopingLeavesConnectedToActiveLeaf() -> bool:
|
|
136
155
|
return my[indexMy.leafConnectee] != my[indexMy.leaf1ndex]
|
|
137
156
|
|
|
138
|
-
def loopingTheDimensions():
|
|
157
|
+
def loopingTheDimensions() -> bool:
|
|
139
158
|
return my[indexMy.dimension1ndex] <= the[indexThe.dimensionsTotal]
|
|
140
159
|
|
|
141
|
-
def loopingToActiveGapCeiling():
|
|
160
|
+
def loopingToActiveGapCeiling() -> bool:
|
|
142
161
|
return my[indexMy.indexMiniGap] < my[indexMy.gap1ndexCeiling]
|
|
143
162
|
|
|
144
|
-
def placeLeaf():
|
|
163
|
+
def placeLeaf() -> None:
|
|
145
164
|
my[indexMy.gap1ndex] -= 1
|
|
146
165
|
track[indexTrack.leafAbove, my[indexMy.leaf1ndex]] = gapsWhere[my[indexMy.gap1ndex]]
|
|
147
166
|
track[indexTrack.leafBelow, my[indexMy.leaf1ndex]] = track[indexTrack.leafBelow, track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]]
|
|
@@ -150,13 +169,13 @@ def countFolds(listDimensions: Sequence[int], computationDivisions = None, CPUli
|
|
|
150
169
|
track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex]] = my[indexMy.gap1ndex]
|
|
151
170
|
my[indexMy.leaf1ndex] += 1
|
|
152
171
|
|
|
153
|
-
def placeLeafCondition():
|
|
172
|
+
def placeLeafCondition() -> bool:
|
|
154
173
|
return my[indexMy.leaf1ndex] > 0
|
|
155
174
|
|
|
156
|
-
def taskIndexCondition():
|
|
175
|
+
def taskIndexCondition() -> bool:
|
|
157
176
|
return my[indexMy.leafConnectee] % the[indexThe.taskDivisions] == my[indexMy.taskIndex]
|
|
158
177
|
|
|
159
|
-
def thereAreComputationDivisionsYouMightSkip():
|
|
178
|
+
def thereAreComputationDivisionsYouMightSkip() -> bool:
|
|
160
179
|
if computationDivisionsCondition():
|
|
161
180
|
return True
|
|
162
181
|
if activeLeafNotEqualToTaskDivisionsCondition():
|
|
@@ -166,11 +185,11 @@ def countFolds(listDimensions: Sequence[int], computationDivisions = None, CPUli
|
|
|
166
185
|
return False
|
|
167
186
|
|
|
168
187
|
stateUniversal = outfitFoldings(listDimensions, computationDivisions=computationDivisions, CPUlimit=CPUlimit)
|
|
169
|
-
connectionGraph: Final[numpy.
|
|
188
|
+
connectionGraph: Final[NDArray[numpy.integer[Any]]] = stateUniversal['connectionGraph']
|
|
170
189
|
foldsSubTotals = stateUniversal['foldsSubTotals']
|
|
171
190
|
gapsWhere = stateUniversal['gapsWhere']
|
|
172
191
|
my = stateUniversal['my']
|
|
173
|
-
the: Final[numpy.
|
|
192
|
+
the: Final[NDArray[numpy.integer[Any]]] = stateUniversal['the']
|
|
174
193
|
track = stateUniversal['track']
|
|
175
194
|
|
|
176
195
|
if the[indexThe.taskDivisions] == int(False):
|
|
@@ -192,7 +211,7 @@ def countFolds(listDimensions: Sequence[int], computationDivisions = None, CPUli
|
|
|
192
211
|
class EnumIndices(enum.IntEnum):
|
|
193
212
|
"""Base class for index enums."""
|
|
194
213
|
@staticmethod
|
|
195
|
-
def _generate_next_value_(name, start, count, last_values):
|
|
214
|
+
def _generate_next_value_(name: str, start: int, count: int, last_values: list[int]) -> int:
|
|
196
215
|
"""0-indexed."""
|
|
197
216
|
return count
|
|
198
217
|
|
|
@@ -229,7 +248,7 @@ class indexTrack(EnumIndices):
|
|
|
229
248
|
class computationState(TypedDict):
|
|
230
249
|
connectionGraph: NDArray[integer[Any]]
|
|
231
250
|
foldsSubTotals: NDArray[integer[Any]]
|
|
232
|
-
mapShape:
|
|
251
|
+
mapShape: tuple[int, ...]
|
|
233
252
|
my: NDArray[integer[Any]]
|
|
234
253
|
gapsWhere: NDArray[integer[Any]]
|
|
235
254
|
the: NDArray[integer[Any]]
|
|
@@ -262,7 +281,7 @@ def getLeavesTotal(listDimensions: Sequence[int]) -> int:
|
|
|
262
281
|
|
|
263
282
|
return productDimensions
|
|
264
283
|
|
|
265
|
-
def getTaskDivisions(computationDivisions:
|
|
284
|
+
def getTaskDivisions(computationDivisions: int | str | None, concurrencyLimit: int, CPUlimit: bool | float | int | None, listDimensions: Sequence[int]) -> int:
|
|
266
285
|
if not computationDivisions:
|
|
267
286
|
return 0
|
|
268
287
|
else:
|
|
@@ -284,7 +303,7 @@ def getTaskDivisions(computationDivisions: Optional[Union[int, str]], concurrenc
|
|
|
284
303
|
|
|
285
304
|
return taskDivisions
|
|
286
305
|
|
|
287
|
-
def makeConnectionGraph(listDimensions: Sequence[int], **keywordArguments:
|
|
306
|
+
def makeConnectionGraph(listDimensions: Sequence[int], **keywordArguments: type | None) -> NDArray[integer[Any]]:
|
|
288
307
|
datatype = keywordArguments.get('datatype', dtypeMedium)
|
|
289
308
|
mapShape = validateListDimensions(listDimensions)
|
|
290
309
|
leavesTotal = getLeavesTotal(mapShape)
|
|
@@ -316,12 +335,12 @@ def makeConnectionGraph(listDimensions: Sequence[int], **keywordArguments: Optio
|
|
|
316
335
|
connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex
|
|
317
336
|
return connectionGraph
|
|
318
337
|
|
|
319
|
-
def makeDataContainer(shape, datatype:
|
|
338
|
+
def makeDataContainer(shape: int | Sequence[int], datatype: type | None = None) -> NDArray[integer[Any]]:
|
|
320
339
|
if datatype is None:
|
|
321
340
|
datatype = dtypeMedium
|
|
322
341
|
return numpy.zeros(shape, dtype=datatype)
|
|
323
342
|
|
|
324
|
-
def outfitFoldings(listDimensions: Sequence[int], computationDivisions:
|
|
343
|
+
def outfitFoldings(listDimensions: Sequence[int], computationDivisions: int | str | None = None, CPUlimit: bool | float | int | None = None, **keywordArguments: type | None) -> computationState:
|
|
325
344
|
datatypeMedium = keywordArguments.get('datatypeMedium', dtypeMedium)
|
|
326
345
|
datatypeLarge = keywordArguments.get('datatypeLarge', dtypeLarge)
|
|
327
346
|
|
|
@@ -346,10 +365,10 @@ def outfitFoldings(listDimensions: Sequence[int], computationDivisions: Optional
|
|
|
346
365
|
stateInitialized['my'][indexMy.leaf1ndex] = 1
|
|
347
366
|
return stateInitialized
|
|
348
367
|
|
|
349
|
-
def parseDimensions(dimensions: Sequence[int], parameterName: str = 'unnamed parameter') ->
|
|
368
|
+
def parseDimensions(dimensions: Sequence[int], parameterName: str = 'unnamed parameter') -> list[int]:
|
|
350
369
|
# listValidated = intInnit(dimensions, parameterName)
|
|
351
370
|
listNOTValidated = dimensions if isinstance(dimensions, (list, tuple)) else list(dimensions)
|
|
352
|
-
listNonNegative = []
|
|
371
|
+
listNonNegative: list[int] = []
|
|
353
372
|
for dimension in listNOTValidated:
|
|
354
373
|
if dimension < 0:
|
|
355
374
|
raise ValueError(f"Dimension {dimension} must be non-negative")
|
|
@@ -358,7 +377,7 @@ def parseDimensions(dimensions: Sequence[int], parameterName: str = 'unnamed par
|
|
|
358
377
|
raise ValueError("At least one dimension must be non-negative")
|
|
359
378
|
return listNonNegative
|
|
360
379
|
|
|
361
|
-
def setCPUlimit(CPUlimit:
|
|
380
|
+
def setCPUlimit(CPUlimit: bool | float | int | None) -> int:
|
|
362
381
|
# if not (CPUlimit is None or isinstance(CPUlimit, (bool, int, float))):
|
|
363
382
|
# CPUlimit = oopsieKwargsie(CPUlimit)
|
|
364
383
|
# concurrencyLimit = defineConcurrencyLimit(CPUlimit)
|
|
@@ -367,7 +386,7 @@ def setCPUlimit(CPUlimit: Union[bool, float, int, None]) -> int:
|
|
|
367
386
|
concurrencyLimit = concurrencyLimitHARDCODED
|
|
368
387
|
return concurrencyLimit
|
|
369
388
|
|
|
370
|
-
def validateListDimensions(listDimensions: Sequence[int]) ->
|
|
389
|
+
def validateListDimensions(listDimensions: Sequence[int]) -> list[int]:
|
|
371
390
|
if not listDimensions:
|
|
372
391
|
raise ValueError(f"listDimensions is a required parameter.")
|
|
373
392
|
listNonNegative = parseDimensions(listDimensions, 'listDimensions')
|
|
@@ -1,9 +1,33 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
|
+
High-performance Numba-accelerated implementation of Lunnon's algorithm.
|
|
3
|
+
|
|
4
|
+
This implementation focuses on maximum computational performance by leveraging Numba's
|
|
5
|
+
just-in-time (JIT) compilation capabilities to generate native machine code. It represents
|
|
6
|
+
a manually optimized version that served as inspiration for the automated transformation
|
|
7
|
+
framework in the someAssemblyRequired package.
|
|
8
|
+
|
|
9
|
+
Key characteristics:
|
|
10
|
+
- Optimized data structures using NumPy typed arrays with appropriate data types
|
|
11
|
+
- Function decorators for Numba JIT compilation with performance-oriented settings
|
|
12
|
+
- Memory-efficient implementation with careful type management
|
|
13
|
+
- Reduced Python overhead through native code execution
|
|
14
|
+
- Algorithmic optimizations tailored for numerical computation
|
|
15
|
+
|
|
16
|
+
Performance considerations:
|
|
17
|
+
- Up to 1000× faster than pure Python implementations
|
|
18
|
+
- Optimized for larger map dimensions where computational demands increase exponentially
|
|
19
|
+
- Incorporates lessons from multiple implementation strategies
|
|
20
|
+
|
|
21
|
+
Note: This serves as a reference for manually-optimized code before the development of
|
|
22
|
+
the automated transformation pipeline in the main package.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from typing import Any
|
|
2
26
|
import numba
|
|
3
27
|
import numpy
|
|
4
28
|
|
|
5
29
|
@numba.jit(cache=True, nopython=True, fastmath=True)
|
|
6
|
-
def countFolds(listDimensions:
|
|
30
|
+
def countFolds(listDimensions: list[int]) -> int:
|
|
7
31
|
"""
|
|
8
32
|
Count the number of distinct ways to fold a map with at least two positive dimensions.
|
|
9
33
|
|
|
@@ -13,10 +37,10 @@ def countFolds(listDimensions: List[int]) -> int:
|
|
|
13
37
|
Returns:
|
|
14
38
|
foldsTotal: The total number of distinct folds for the given map dimensions.
|
|
15
39
|
"""
|
|
16
|
-
def integerSmall(value) -> numpy.uint8:
|
|
40
|
+
def integerSmall(value: numpy.integer[Any] | Any) -> numpy.uint8:
|
|
17
41
|
return numpy.uint8(value)
|
|
18
42
|
|
|
19
|
-
def integerLarge(value) -> numpy.uint64:
|
|
43
|
+
def integerLarge(value: numpy.integer[Any] | Any) -> numpy.uint64:
|
|
20
44
|
return numpy.uint64(value)
|
|
21
45
|
|
|
22
46
|
dtypeMedium = numpy.uint8
|
|
@@ -2,8 +2,20 @@
|
|
|
2
2
|
Ported from the Java version by Sean A. Irvine:
|
|
3
3
|
https://github.com/archmageirvine/joeis/blob/80e3e844b11f149704acbab520bc3a3a25ac34ff/src/irvine/oeis/a001/A001415.java
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This implementation is a conversion from a well-known Java implementation of Lunnon's algorithm
|
|
6
|
+
by Sean A. Irvine, a contributor to the OEIS project. It provides a clean, procedural implementation
|
|
7
|
+
with straightforward variable naming and control flow that may be more approachable for
|
|
8
|
+
programmers familiar with modern languages.
|
|
9
|
+
|
|
10
|
+
Key characteristics:
|
|
11
|
+
- Clear variable naming following modern programming conventions
|
|
12
|
+
- Procedural implementation style similar to Java but adapted for Python
|
|
13
|
+
- Follows the same algorithmic structure as Lunnon's original but with cleaner organization
|
|
14
|
+
- Uses primitive Python data structures (lists) without NumPy dependencies
|
|
15
|
+
|
|
16
|
+
Citation: https://github.com/hunterhogan/mapFolding/blob/134f2e6ecdf59fb6f6829c775475544a6aaaa800/citations/jOEIS.bibtex
|
|
6
17
|
"""
|
|
18
|
+
|
|
7
19
|
def foldings(p: list[int], res: int = 0, mod: int = 0) -> int:
|
|
8
20
|
"""
|
|
9
21
|
Compute the total number of foldings for a map with dimensions specified in p.
|
|
@@ -1,20 +1,39 @@
|
|
|
1
|
-
"""
|
|
2
|
-
I
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"""
|
|
2
|
+
I was able to implement the algorithm with JAX, but I didn't see an advantage and it's a pain in the ass.
|
|
3
|
+
|
|
4
|
+
Experimental JAX implementation of Lunnon's algorithm for potential GPU acceleration.
|
|
5
|
+
|
|
6
|
+
This implementation explores the use of JAX (Just After eXecution) for potential GPU acceleration
|
|
7
|
+
of the map folding algorithm. It represents an experimental approach that attempts to leverage
|
|
8
|
+
JAX's transformation capabilities and hardware acceleration through XLA compilation.
|
|
9
|
+
|
|
10
|
+
Key characteristics:
|
|
11
|
+
- Uses JAX's functional programming model with lax control flow primitives
|
|
12
|
+
- Attempts to leverage GPU acceleration for numerical operations
|
|
13
|
+
- Demonstrates JAX-specific patterns for handling loops and conditions
|
|
14
|
+
- Supports jit compilation for performance optimization
|
|
15
|
+
|
|
16
|
+
As noted in the file's comment, this implementation didn't demonstrate significant advantages
|
|
17
|
+
over other approaches and presented additional complexity. It serves as a valuable reference
|
|
18
|
+
for exploring alternative acceleration strategies and understanding the limitations of
|
|
19
|
+
different computational frameworks for this specific algorithm.
|
|
20
|
+
"""
|
|
21
|
+
from flattened import validateListDimensions, getLeavesTotal, makeConnectionGraph
|
|
22
|
+
from numpy.typing import NDArray
|
|
23
|
+
from typing import Any
|
|
5
24
|
import jax
|
|
6
25
|
import jaxtyping
|
|
26
|
+
import numpy
|
|
7
27
|
|
|
8
28
|
dtypeMedium = jax.numpy.uint32
|
|
9
29
|
dtypeMaximum = jax.numpy.uint32
|
|
10
30
|
|
|
11
|
-
def countFolds(listDimensions:
|
|
12
|
-
listDimensionsPositive:
|
|
31
|
+
def countFolds(listDimensions: list[int]) -> int:
|
|
32
|
+
listDimensionsPositive: list[int] = validateListDimensions(listDimensions)
|
|
13
33
|
|
|
14
34
|
n: int = getLeavesTotal(listDimensionsPositive)
|
|
15
35
|
d: int = len(listDimensions)
|
|
16
|
-
|
|
17
|
-
D: numpy.ndarray = makeConnectionGraph(listDimensionsPositive)
|
|
36
|
+
D: NDArray[numpy.integer[Any]] = makeConnectionGraph(listDimensionsPositive)
|
|
18
37
|
connectionGraph = jax.numpy.asarray(D, dtype=dtypeMedium)
|
|
19
38
|
del listDimensionsPositive
|
|
20
39
|
|
|
@@ -22,14 +41,14 @@ def countFolds(listDimensions: List[int]) -> int:
|
|
|
22
41
|
|
|
23
42
|
def foldingsJAX(leavesTotal: jaxtyping.UInt32, dimensionsTotal: jaxtyping.UInt32, connectionGraph: jaxtyping.Array) -> jaxtyping.UInt32:
|
|
24
43
|
|
|
25
|
-
def doNothing(argument):
|
|
44
|
+
def doNothing(argument: Any):
|
|
26
45
|
return argument
|
|
27
46
|
|
|
28
|
-
def while_activeLeaf1ndex_greaterThan_0(comparisonValues:
|
|
47
|
+
def while_activeLeaf1ndex_greaterThan_0(comparisonValues: tuple):
|
|
29
48
|
comparand = comparisonValues[6]
|
|
30
49
|
return comparand > 0
|
|
31
50
|
|
|
32
|
-
def countFoldings(allValues:
|
|
51
|
+
def countFoldings(allValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
33
52
|
_0, leafBelow, _2, _3, _4, _5, activeLeaf1ndex, _7 = allValues
|
|
34
53
|
|
|
35
54
|
sentinel = leafBelow.at[0].get().astype(jax.numpy.uint32)
|
|
@@ -44,24 +63,24 @@ def foldingsJAX(leavesTotal: jaxtyping.UInt32, dimensionsTotal: jaxtyping.UInt32
|
|
|
44
63
|
def findGapsCondition(leafBelowSentinel, activeLeafNumber):
|
|
45
64
|
return jax.numpy.logical_or(jax.numpy.logical_and(leafBelowSentinel == 1, activeLeafNumber <= leavesTotal), activeLeafNumber <= 1)
|
|
46
65
|
|
|
47
|
-
def findGapsDo(allValues:
|
|
48
|
-
def for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1(comparisonValues:
|
|
66
|
+
def findGapsDo(allValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
67
|
+
def for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1(comparisonValues: tuple):
|
|
49
68
|
return comparisonValues[-1] <= dimensionsTotal
|
|
50
69
|
|
|
51
|
-
def for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1_do(for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1Values:
|
|
70
|
+
def for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1_do(for_dimension1ndex_in_range_1_to_dimensionsTotalPlus1Values: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
52
71
|
def ifLeafIsUnconstrainedCondition(comparand):
|
|
53
72
|
return jax.numpy.equal(connectionGraph[comparand, activeLeaf1ndex, activeLeaf1ndex], activeLeaf1ndex)
|
|
54
73
|
|
|
55
|
-
def ifLeafIsUnconstrainedDo(unconstrainedValues:
|
|
74
|
+
def ifLeafIsUnconstrainedDo(unconstrainedValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
56
75
|
unconstrained_unconstrainedLeaf = unconstrainedValues[3]
|
|
57
76
|
unconstrained_unconstrainedLeaf = 1 + unconstrained_unconstrainedLeaf
|
|
58
77
|
return (unconstrainedValues[0], unconstrainedValues[1], unconstrainedValues[2], unconstrained_unconstrainedLeaf)
|
|
59
78
|
|
|
60
|
-
def ifLeafIsUnconstrainedElse(unconstrainedValues:
|
|
61
|
-
def while_leaf1ndexConnectee_notEquals_activeLeaf1ndex(comparisonValues:
|
|
79
|
+
def ifLeafIsUnconstrainedElse(unconstrainedValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
80
|
+
def while_leaf1ndexConnectee_notEquals_activeLeaf1ndex(comparisonValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
62
81
|
return comparisonValues[-1] != activeLeaf1ndex
|
|
63
82
|
|
|
64
|
-
def countGaps(countGapsDoValues:
|
|
83
|
+
def countGaps(countGapsDoValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
65
84
|
countGapsCountDimensionsGapped, countGapsPotentialGaps, countGapsGap1ndexLowerBound, countGapsLeaf1ndexConnectee = countGapsDoValues
|
|
66
85
|
|
|
67
86
|
countGapsPotentialGaps = countGapsPotentialGaps.at[countGapsGap1ndexLowerBound].set(countGapsLeaf1ndexConnectee)
|
|
@@ -93,11 +112,11 @@ def foldingsJAX(leavesTotal: jaxtyping.UInt32, dimensionsTotal: jaxtyping.UInt32
|
|
|
93
112
|
def almostUselessCondition(comparand):
|
|
94
113
|
return comparand == dimensionsTotal
|
|
95
114
|
|
|
96
|
-
def almostUselessConditionDo(for_leaf1ndex_in_range_activeLeaf1ndexValues:
|
|
115
|
+
def almostUselessConditionDo(for_leaf1ndex_in_range_activeLeaf1ndexValues: tuple[jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
97
116
|
def for_leaf1ndex_in_range_activeLeaf1ndex(comparisonValues):
|
|
98
117
|
return comparisonValues[-1] < activeLeaf1ndex
|
|
99
118
|
|
|
100
|
-
def for_leaf1ndex_in_range_activeLeaf1ndex_do(for_leaf1ndex_in_range_activeLeaf1ndexValues:
|
|
119
|
+
def for_leaf1ndex_in_range_activeLeaf1ndex_do(for_leaf1ndex_in_range_activeLeaf1ndexValues: tuple[jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
101
120
|
leafInRangePotentialGaps, gapNumberLowerBound, leafNumber = for_leaf1ndex_in_range_activeLeaf1ndexValues
|
|
102
121
|
leafInRangePotentialGaps = leafInRangePotentialGaps.at[gapNumberLowerBound].set(leafNumber)
|
|
103
122
|
gapNumberLowerBound = 1 + gapNumberLowerBound
|
|
@@ -105,10 +124,10 @@ def foldingsJAX(leavesTotal: jaxtyping.UInt32, dimensionsTotal: jaxtyping.UInt32
|
|
|
105
124
|
return (leafInRangePotentialGaps, gapNumberLowerBound, leafNumber)
|
|
106
125
|
return jax.lax.while_loop(for_leaf1ndex_in_range_activeLeaf1ndex, for_leaf1ndex_in_range_activeLeaf1ndex_do, for_leaf1ndex_in_range_activeLeaf1ndexValues)
|
|
107
126
|
|
|
108
|
-
def for_range_from_activeGap1ndex_to_gap1ndexCeiling(comparisonValues:
|
|
127
|
+
def for_range_from_activeGap1ndex_to_gap1ndexCeiling(comparisonValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
109
128
|
return comparisonValues[-1] < gap1ndexCeiling
|
|
110
129
|
|
|
111
|
-
def miniGapDo(gapToGapValues:
|
|
130
|
+
def miniGapDo(gapToGapValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
112
131
|
gapToGapCountDimensionsGapped, gapToGapPotentialGaps, activeGapNumber, index = gapToGapValues
|
|
113
132
|
gapToGapPotentialGaps = gapToGapPotentialGaps.at[activeGapNumber].set(gapToGapPotentialGaps.at[index].get())
|
|
114
133
|
activeGapNumber = jax.numpy.where(jax.numpy.equal(gapToGapCountDimensionsGapped.at[gapToGapPotentialGaps.at[index].get()].get(), dimensionsTotal - unconstrainedLeaf), activeGapNumber + 1, activeGapNumber).astype(jax.numpy.uint32)
|
|
@@ -144,17 +163,17 @@ def foldingsJAX(leavesTotal: jaxtyping.UInt32, dimensionsTotal: jaxtyping.UInt32
|
|
|
144
163
|
def incrementCondition(leafBelowSentinel, activeLeafNumber):
|
|
145
164
|
return jax.numpy.logical_and(activeLeafNumber > leavesTotal, leafBelowSentinel == 1)
|
|
146
165
|
|
|
147
|
-
def incrementDo(allValues:
|
|
166
|
+
def incrementDo(allValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
148
167
|
foldingsSubTotal = allValues[5]
|
|
149
168
|
foldingsSubTotal = leavesTotal + foldingsSubTotal
|
|
150
169
|
return (allValues[0], allValues[1], allValues[2], allValues[3], allValues[4], foldingsSubTotal, allValues[6], allValues[7])
|
|
151
170
|
|
|
152
|
-
def dao(allValues:
|
|
153
|
-
def whileBacktrackingCondition(backtrackingValues:
|
|
171
|
+
def dao(allValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
172
|
+
def whileBacktrackingCondition(backtrackingValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32]):
|
|
154
173
|
comparand = backtrackingValues[2]
|
|
155
174
|
return jax.numpy.logical_and(comparand > 0, jax.numpy.equal(activeGap1ndex, gapRangeStart.at[comparand - 1].get()))
|
|
156
175
|
|
|
157
|
-
def whileBacktrackingDo(backtrackingValues:
|
|
176
|
+
def whileBacktrackingDo(backtrackingValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32]):
|
|
158
177
|
backtrackAbove, backtrackBelow, activeLeafNumber = backtrackingValues
|
|
159
178
|
|
|
160
179
|
activeLeafNumber = activeLeafNumber - 1
|
|
@@ -166,7 +185,7 @@ def foldingsJAX(leavesTotal: jaxtyping.UInt32, dimensionsTotal: jaxtyping.UInt32
|
|
|
166
185
|
def if_activeLeaf1ndex_greaterThan_0(activeLeafNumber):
|
|
167
186
|
return activeLeafNumber > 0
|
|
168
187
|
|
|
169
|
-
def if_activeLeaf1ndex_greaterThan_0_do(leafPlacementValues:
|
|
188
|
+
def if_activeLeaf1ndex_greaterThan_0_do(leafPlacementValues: tuple[jaxtyping.Array, jaxtyping.Array, jaxtyping.Array, jaxtyping.UInt32, jaxtyping.UInt32]):
|
|
170
189
|
placeLeafAbove, placeLeafBelow, placeGapRangeStart, activeLeafNumber, activeGapNumber = leafPlacementValues
|
|
171
190
|
activeGapNumber = activeGapNumber - 1
|
|
172
191
|
placeLeafAbove = placeLeafAbove.at[activeLeafNumber].set(gapsWhere.at[activeGapNumber].get())
|
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
"""
|
|
2
2
|
A generally faithful translation of the original Atlas Autocode code by W. F. Lunnon to Python using NumPy.
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
This implementation transforms Lunnon's 1971 algorithm to leverage NumPy's array operations for improved
|
|
5
|
+
performance while maintaining algorithmic fidelity. It preserves the core logic and variable naming
|
|
6
|
+
conventions of the original algorithm but benefits from NumPy's vectorized operations and efficient
|
|
7
|
+
memory management.
|
|
8
|
+
|
|
9
|
+
Key characteristics:
|
|
10
|
+
- Uses NumPy arrays instead of Python lists for better memory efficiency
|
|
11
|
+
- Maintains the original algorithm structure and control flow
|
|
12
|
+
- Preserves variable naming for algorithmic clarity
|
|
13
|
+
- Offers significant performance improvements over pure Python implementations
|
|
14
|
+
|
|
15
|
+
Reference:
|
|
16
|
+
W. F. Lunnon, Multi-dimensional map-folding, The Computer Journal, Volume 14, Issue 1, 1971,
|
|
17
|
+
Pages 75-80, https://doi.org/10.1093/comjnl/14.1.75
|
|
4
18
|
"""
|
|
5
|
-
|
|
19
|
+
|
|
6
20
|
import numpy
|
|
7
21
|
|
|
8
|
-
def foldings(p:
|
|
22
|
+
def foldings(p: list[int]) -> int:
|
|
9
23
|
"""
|
|
10
24
|
Run loop with (A, B) on each folding of a p[1] x ... x p[d] map, where A and B are the above and below vectors.
|
|
11
25
|
|
|
@@ -66,7 +80,7 @@ def foldings(p: List[int]) -> int:
|
|
|
66
80
|
# D[i][l][m] = leaf connected to m in section i when inserting l;
|
|
67
81
|
|
|
68
82
|
G: int = 0
|
|
69
|
-
l
|
|
83
|
+
l = 1
|
|
70
84
|
|
|
71
85
|
# kick off with null folding
|
|
72
86
|
while l > 0:
|
|
@@ -86,7 +100,7 @@ def foldings(p: List[int]) -> int:
|
|
|
86
100
|
if D[i][l][l] == l:
|
|
87
101
|
dd = dd + 1
|
|
88
102
|
else:
|
|
89
|
-
m
|
|
103
|
+
m = D[i][l][l]
|
|
90
104
|
while m != l:
|
|
91
105
|
gap[gg] = m
|
|
92
106
|
if count[m] == 0:
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
"""
|
|
2
2
|
A largely faithful translation of the original Atlas Autocode code by W. F. Lunnon to Python using `while`.
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
This implementation closely follows the structure and logic of Lunnon's 1971 paper, preserving the
|
|
5
|
+
variable names and core algorithm design. It uses while loops instead of Atlas Autocode's procedural
|
|
6
|
+
control structures, maintaining the imperative programming style of the original.
|
|
7
|
+
|
|
8
|
+
Key characteristics:
|
|
9
|
+
- Preserves original algorithm structure for historical accuracy
|
|
10
|
+
- Uses primarily scalar operations and explicit loops
|
|
11
|
+
- Maintains the original variable naming from Lunnon's work
|
|
12
|
+
- Provides a baseline for comparison against optimized implementations
|
|
13
|
+
|
|
14
|
+
Reference:
|
|
15
|
+
W. F. Lunnon, Multi-dimensional map-folding, The Computer Journal, Volume 14, Issue 1, 1971,
|
|
16
|
+
Pages 75-80, https://doi.org/10.1093/comjnl/14.1.75
|
|
4
17
|
"""
|
|
5
|
-
from typing import Sequence
|
|
6
18
|
|
|
7
|
-
def foldings(p:
|
|
19
|
+
def foldings(p: list[int]) -> int:
|
|
8
20
|
"""
|
|
9
21
|
Run loop with (A, B) on each folding of a p[1] x ... x p[d] map, where A and B are the above and below vectors.
|
|
10
22
|
|
|
@@ -38,8 +50,8 @@ def foldings(p: Sequence[int]) -> int:
|
|
|
38
50
|
# and later gap[gapter[l]] is the gap where leaf l is currently inserted
|
|
39
51
|
|
|
40
52
|
P = [1] * (d + 1)
|
|
41
|
-
C = [[0] * (n + 1) for
|
|
42
|
-
D = [[[0] * (n + 1) for
|
|
53
|
+
C = [[0] * (n + 1) for _dimension1 in range(d + 1)]
|
|
54
|
+
D = [[[0] * (n + 1) for _dimension2 in range(n + 1)] for _dimension1 in range(d + 1)]
|
|
43
55
|
|
|
44
56
|
for i in range(1, d + 1):
|
|
45
57
|
P[i] = P[i - 1] * p[i - 1]
|
|
@@ -65,7 +77,7 @@ def foldings(p: Sequence[int]) -> int:
|
|
|
65
77
|
# D[i][l][m] = leaf connected to m in section i when inserting l;
|
|
66
78
|
|
|
67
79
|
G: int = 0
|
|
68
|
-
l
|
|
80
|
+
l = 1
|
|
69
81
|
|
|
70
82
|
# kick off with null folding
|
|
71
83
|
while l > 0:
|
|
@@ -84,7 +96,7 @@ def foldings(p: Sequence[int]) -> int:
|
|
|
84
96
|
if D[i][l][l] == l:
|
|
85
97
|
dd = dd + 1
|
|
86
98
|
else:
|
|
87
|
-
m
|
|
99
|
+
m = D[i][l][l]
|
|
88
100
|
while m != l:
|
|
89
101
|
gap[gg] = m
|
|
90
102
|
if count[m] == 0:
|
|
@@ -1,6 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Alternative algorithm entry point implementation for Lunnon's map folding algorithm.
|
|
3
|
+
|
|
4
|
+
This implementation demonstrates an interesting algorithmic variation where the main processing
|
|
5
|
+
loop is "rotated" to enter at a different point in the execution flow. Specifically, it's
|
|
6
|
+
structured to enter at the modulo operator rather than the traditional starting point.
|
|
7
|
+
|
|
8
|
+
Key characteristics:
|
|
9
|
+
- Restructures the control flow by reorganizing the entry point of the algorithm
|
|
10
|
+
- Separates preparation work from the main computational loop
|
|
11
|
+
- Uses explicit variable naming with index constants for clarity
|
|
12
|
+
- Demonstrates how the same algorithm can be approached from different entry points
|
|
13
|
+
|
|
14
|
+
Note: This implementation is intentionally incomplete and requires supporting code from
|
|
15
|
+
other modules to function. It serves primarily as a demonstration of how algorithmic
|
|
16
|
+
structure can be creatively redesigned while maintaining the core computational approach.
|
|
17
|
+
"""
|
|
18
|
+
|
|
1
19
|
from mapFolding import outfitFoldings
|
|
2
20
|
from numba import njit
|
|
3
|
-
from typing import List
|
|
4
21
|
import numpy
|
|
5
22
|
from numpy.typing import NDArray
|
|
6
23
|
|
|
@@ -42,7 +59,7 @@ tricky = [
|
|
|
42
59
|
|
|
43
60
|
COUNTindicesStatic = len(tricky)
|
|
44
61
|
|
|
45
|
-
def countFolds(listDimensions:
|
|
62
|
+
def countFolds(listDimensions: list[int]):
|
|
46
63
|
static = numpy.zeros(COUNTindicesStatic, dtype=numpy.int64)
|
|
47
64
|
|
|
48
65
|
listDimensions, static[leavesTotal], D, track,gapsWhere = outfitFoldings(listDimensions)
|
|
@@ -55,7 +72,7 @@ def countFolds(listDimensions: List[int]):
|
|
|
55
72
|
return foldingsTotal
|
|
56
73
|
|
|
57
74
|
# @recordBenchmarks()
|
|
58
|
-
def _sherpa(track: NDArray, gap: NDArray, static: NDArray, D: NDArray, p:
|
|
75
|
+
def _sherpa(track: NDArray, gap: NDArray, static: NDArray, D: NDArray, p: list[int]):
|
|
59
76
|
"""Performance critical section that counts foldings.
|
|
60
77
|
|
|
61
78
|
Parameters:
|