mapFolding 0.3.12__py3-none-any.whl → 0.4.0__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 (45) hide show
  1. mapFolding/__init__.py +40 -38
  2. mapFolding/basecamp.py +50 -50
  3. mapFolding/beDRY.py +336 -336
  4. mapFolding/oeis.py +262 -262
  5. mapFolding/reference/flattened.py +294 -293
  6. mapFolding/reference/hunterNumba.py +126 -126
  7. mapFolding/reference/irvineJavaPort.py +99 -99
  8. mapFolding/reference/jax.py +153 -153
  9. mapFolding/reference/lunnan.py +148 -148
  10. mapFolding/reference/lunnanNumpy.py +115 -115
  11. mapFolding/reference/lunnanWhile.py +114 -114
  12. mapFolding/reference/rotatedEntryPoint.py +183 -183
  13. mapFolding/reference/total_countPlus1vsPlusN.py +203 -203
  14. mapFolding/someAssemblyRequired/__init__.py +2 -1
  15. mapFolding/someAssemblyRequired/getLLVMforNoReason.py +12 -12
  16. mapFolding/someAssemblyRequired/makeJob.py +48 -48
  17. mapFolding/someAssemblyRequired/synthesizeModuleJAX.py +17 -17
  18. mapFolding/someAssemblyRequired/synthesizeNumba.py +343 -633
  19. mapFolding/someAssemblyRequired/synthesizeNumbaGeneralized.py +371 -0
  20. mapFolding/someAssemblyRequired/synthesizeNumbaJob.py +150 -0
  21. mapFolding/someAssemblyRequired/synthesizeNumbaModules.py +75 -0
  22. mapFolding/syntheticModules/__init__.py +0 -0
  23. mapFolding/syntheticModules/numba_countInitialize.py +3 -3
  24. mapFolding/syntheticModules/numba_countParallel.py +3 -3
  25. mapFolding/syntheticModules/numba_countSequential.py +3 -3
  26. mapFolding/syntheticModules/numba_doTheNeedful.py +6 -6
  27. mapFolding/theDao.py +165 -165
  28. mapFolding/theSSOT.py +176 -172
  29. mapFolding/theSSOTnumba.py +90 -74
  30. mapFolding-0.4.0.dist-info/METADATA +122 -0
  31. mapFolding-0.4.0.dist-info/RECORD +41 -0
  32. tests/conftest.py +238 -128
  33. tests/test_oeis.py +80 -80
  34. tests/test_other.py +137 -224
  35. tests/test_tasks.py +21 -21
  36. tests/test_types.py +2 -2
  37. mapFolding/someAssemblyRequired/synthesizeNumbaHardcoding.py +0 -188
  38. mapFolding-0.3.12.dist-info/METADATA +0 -155
  39. mapFolding-0.3.12.dist-info/RECORD +0 -40
  40. tests/conftest_tmpRegistry.py +0 -62
  41. tests/conftest_uniformTests.py +0 -53
  42. {mapFolding-0.3.12.dist-info → mapFolding-0.4.0.dist-info}/LICENSE +0 -0
  43. {mapFolding-0.3.12.dist-info → mapFolding-0.4.0.dist-info}/WHEEL +0 -0
  44. {mapFolding-0.3.12.dist-info → mapFolding-0.4.0.dist-info}/entry_points.txt +0 -0
  45. {mapFolding-0.3.12.dist-info → mapFolding-0.4.0.dist-info}/top_level.txt +0 -0
@@ -8,369 +8,370 @@ import numpy
8
8
  import sys
9
9
 
10
10
  def countFolds(listDimensions: Sequence[int], computationDivisions = None, CPUlimit: Optional[Union[int, float, bool]] = None):
11
- def doWhile():
11
+ def doWhile():
12
12
 
13
- while activeLeafGreaterThan0Condition():
13
+ while activeLeafGreaterThan0Condition():
14
14
 
15
- if activeLeafIsTheFirstLeafCondition() or leafBelowSentinelIs1Condition():
15
+ if activeLeafIsTheFirstLeafCondition() or leafBelowSentinelIs1Condition():
16
16
 
17
- if activeLeafGreaterThanLeavesTotalCondition():
18
- foldsSubTotalsIncrement()
17
+ if activeLeafGreaterThanLeavesTotalCondition():
18
+ foldsSubTotalsIncrement()
19
19
 
20
- else:
20
+ else:
21
21
 
22
- findGapsInitializeVariables()
23
- while loopingTheDimensions():
22
+ findGapsInitializeVariables()
23
+ while loopingTheDimensions():
24
24
 
25
- if dimensionsUnconstrainedCondition():
26
- dimensionsUnconstrainedIncrement()
25
+ if dimensionsUnconstrainedCondition():
26
+ dimensionsUnconstrainedIncrement()
27
27
 
28
- else:
28
+ else:
29
29
 
30
- leafConnecteeInitialization()
31
- while loopingLeavesConnectedToActiveLeaf():
32
- if thereAreComputationDivisionsYouMightSkip():
33
- countGaps()
34
- leafConnecteeUpdate()
30
+ leafConnecteeInitialization()
31
+ while loopingLeavesConnectedToActiveLeaf():
32
+ if thereAreComputationDivisionsYouMightSkip():
33
+ countGaps()
34
+ leafConnecteeUpdate()
35
35
 
36
- dimension1ndexIncrement()
36
+ dimension1ndexIncrement()
37
37
 
38
- if allDimensionsAreUnconstrained():
39
- insertUnconstrainedLeaf()
38
+ if allDimensionsAreUnconstrained():
39
+ insertUnconstrainedLeaf()
40
40
 
41
- indexMiniGapInitialization()
42
- while loopingToActiveGapCeiling():
43
- filterCommonGaps()
44
- indexMiniGapIncrement()
41
+ indexMiniGapInitialization()
42
+ while loopingToActiveGapCeiling():
43
+ filterCommonGaps()
44
+ indexMiniGapIncrement()
45
45
 
46
- while backtrackCondition():
47
- backtrack()
46
+ while backtrackCondition():
47
+ backtrack()
48
48
 
49
- if placeLeafCondition():
50
- placeLeaf()
49
+ if placeLeafCondition():
50
+ placeLeaf()
51
51
 
52
- def activeGapIncrement():
53
- my[indexMy.gap1ndex] += 1
52
+ def activeGapIncrement():
53
+ my[indexMy.gap1ndex] += 1
54
54
 
55
- def activeLeafGreaterThan0Condition():
56
- return my[indexMy.leaf1ndex] > 0
55
+ def activeLeafGreaterThan0Condition():
56
+ return my[indexMy.leaf1ndex] > 0
57
57
 
58
- def activeLeafGreaterThanLeavesTotalCondition():
59
- return my[indexMy.leaf1ndex] > the[indexThe.leavesTotal]
58
+ def activeLeafGreaterThanLeavesTotalCondition():
59
+ return my[indexMy.leaf1ndex] > the[indexThe.leavesTotal]
60
60
 
61
- def activeLeafIsTheFirstLeafCondition():
62
- return my[indexMy.leaf1ndex] <= 1
61
+ def activeLeafIsTheFirstLeafCondition():
62
+ return my[indexMy.leaf1ndex] <= 1
63
63
 
64
- def activeLeafNotEqualToTaskDivisionsCondition():
65
- return my[indexMy.leaf1ndex] != the[indexThe.taskDivisions]
64
+ def activeLeafNotEqualToTaskDivisionsCondition():
65
+ return my[indexMy.leaf1ndex] != the[indexThe.taskDivisions]
66
66
 
67
- def allDimensionsAreUnconstrained():
68
- return my[indexMy.dimensionsUnconstrained] == the[indexThe.dimensionsTotal]
67
+ def allDimensionsAreUnconstrained():
68
+ return my[indexMy.dimensionsUnconstrained] == the[indexThe.dimensionsTotal]
69
69
 
70
- def backtrack():
71
- my[indexMy.leaf1ndex] -= 1
72
- track[indexTrack.leafBelow, track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]] = track[indexTrack.leafBelow, my[indexMy.leaf1ndex]]
73
- track[indexTrack.leafAbove, track[indexTrack.leafBelow, my[indexMy.leaf1ndex]]] = track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]
70
+ def backtrack():
71
+ my[indexMy.leaf1ndex] -= 1
72
+ track[indexTrack.leafBelow, track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]] = track[indexTrack.leafBelow, my[indexMy.leaf1ndex]]
73
+ track[indexTrack.leafAbove, track[indexTrack.leafBelow, my[indexMy.leaf1ndex]]] = track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]
74
74
 
75
- def backtrackCondition():
76
- return my[indexMy.leaf1ndex] > 0 and my[indexMy.gap1ndex] == track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex] - 1]
75
+ def backtrackCondition():
76
+ return my[indexMy.leaf1ndex] > 0 and my[indexMy.gap1ndex] == track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex] - 1]
77
77
 
78
- def computationDivisionsCondition():
79
- return the[indexThe.taskDivisions] == int(False)
78
+ def computationDivisionsCondition():
79
+ return the[indexThe.taskDivisions] == int(False)
80
80
 
81
- def countGaps():
82
- gapsWhere[my[indexMy.gap1ndexCeiling]] = my[indexMy.leafConnectee]
83
- if track[indexTrack.countDimensionsGapped, my[indexMy.leafConnectee]] == 0:
84
- gap1ndexCeilingIncrement()
85
- track[indexTrack.countDimensionsGapped, my[indexMy.leafConnectee]] += 1
81
+ def countGaps():
82
+ gapsWhere[my[indexMy.gap1ndexCeiling]] = my[indexMy.leafConnectee]
83
+ if track[indexTrack.countDimensionsGapped, my[indexMy.leafConnectee]] == 0:
84
+ gap1ndexCeilingIncrement()
85
+ track[indexTrack.countDimensionsGapped, my[indexMy.leafConnectee]] += 1
86
86
 
87
- def dimension1ndexIncrement():
88
- my[indexMy.dimension1ndex] += 1
87
+ def dimension1ndexIncrement():
88
+ my[indexMy.dimension1ndex] += 1
89
89
 
90
- def dimensionsUnconstrainedCondition():
91
- return connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], my[indexMy.leaf1ndex]] == my[indexMy.leaf1ndex]
90
+ def dimensionsUnconstrainedCondition():
91
+ return connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], my[indexMy.leaf1ndex]] == my[indexMy.leaf1ndex]
92
92
 
93
- def dimensionsUnconstrainedIncrement():
94
- my[indexMy.dimensionsUnconstrained] += 1
93
+ def dimensionsUnconstrainedIncrement():
94
+ my[indexMy.dimensionsUnconstrained] += 1
95
95
 
96
- def filterCommonGaps():
97
- gapsWhere[my[indexMy.gap1ndex]] = gapsWhere[my[indexMy.indexMiniGap]]
98
- if track[indexTrack.countDimensionsGapped, gapsWhere[my[indexMy.indexMiniGap]]] == the[indexThe.dimensionsTotal] - my[indexMy.dimensionsUnconstrained]:
99
- activeGapIncrement()
100
- track[indexTrack.countDimensionsGapped, gapsWhere[my[indexMy.indexMiniGap]]] = 0
96
+ def filterCommonGaps():
97
+ gapsWhere[my[indexMy.gap1ndex]] = gapsWhere[my[indexMy.indexMiniGap]]
98
+ if track[indexTrack.countDimensionsGapped, gapsWhere[my[indexMy.indexMiniGap]]] == the[indexThe.dimensionsTotal] - my[indexMy.dimensionsUnconstrained]:
99
+ activeGapIncrement()
100
+ track[indexTrack.countDimensionsGapped, gapsWhere[my[indexMy.indexMiniGap]]] = 0
101
101
 
102
- def findGapsInitializeVariables():
103
- my[indexMy.dimensionsUnconstrained] = 0
104
- my[indexMy.gap1ndexCeiling] = track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex] - 1]
105
- my[indexMy.dimension1ndex] = 1
102
+ def findGapsInitializeVariables():
103
+ my[indexMy.dimensionsUnconstrained] = 0
104
+ my[indexMy.gap1ndexCeiling] = track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex] - 1]
105
+ my[indexMy.dimension1ndex] = 1
106
106
 
107
- def foldsSubTotalsIncrement():
108
- foldsSubTotals[my[indexMy.taskIndex]] += the[indexThe.leavesTotal]
107
+ def foldsSubTotalsIncrement():
108
+ foldsSubTotals[my[indexMy.taskIndex]] += the[indexThe.leavesTotal]
109
109
 
110
- def gap1ndexCeilingIncrement():
111
- my[indexMy.gap1ndexCeiling] += 1
110
+ def gap1ndexCeilingIncrement():
111
+ my[indexMy.gap1ndexCeiling] += 1
112
112
 
113
- def indexMiniGapIncrement():
114
- my[indexMy.indexMiniGap] += 1
113
+ def indexMiniGapIncrement():
114
+ my[indexMy.indexMiniGap] += 1
115
115
 
116
- def indexMiniGapInitialization():
117
- my[indexMy.indexMiniGap] = my[indexMy.gap1ndex]
116
+ def indexMiniGapInitialization():
117
+ my[indexMy.indexMiniGap] = my[indexMy.gap1ndex]
118
118
 
119
- def insertUnconstrainedLeaf():
120
- my[indexMy.indexLeaf] = 0
121
- while my[indexMy.indexLeaf] < my[indexMy.leaf1ndex]:
122
- gapsWhere[my[indexMy.gap1ndexCeiling]] = my[indexMy.indexLeaf]
123
- my[indexMy.gap1ndexCeiling] += 1
124
- my[indexMy.indexLeaf] += 1
119
+ def insertUnconstrainedLeaf():
120
+ my[indexMy.indexLeaf] = 0
121
+ while my[indexMy.indexLeaf] < my[indexMy.leaf1ndex]:
122
+ gapsWhere[my[indexMy.gap1ndexCeiling]] = my[indexMy.indexLeaf]
123
+ my[indexMy.gap1ndexCeiling] += 1
124
+ my[indexMy.indexLeaf] += 1
125
125
 
126
- def leafBelowSentinelIs1Condition():
127
- return track[indexTrack.leafBelow, 0] == 1
126
+ def leafBelowSentinelIs1Condition():
127
+ return track[indexTrack.leafBelow, 0] == 1
128
128
 
129
- def leafConnecteeInitialization():
130
- my[indexMy.leafConnectee] = connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], my[indexMy.leaf1ndex]]
131
-
132
- def leafConnecteeUpdate():
133
- my[indexMy.leafConnectee] = connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], track[indexTrack.leafBelow, my[indexMy.leafConnectee]]]
129
+ def leafConnecteeInitialization():
130
+ my[indexMy.leafConnectee] = connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], my[indexMy.leaf1ndex]]
131
+
132
+ def leafConnecteeUpdate():
133
+ my[indexMy.leafConnectee] = connectionGraph[my[indexMy.dimension1ndex], my[indexMy.leaf1ndex], track[indexTrack.leafBelow, my[indexMy.leafConnectee]]]
134
134
 
135
- def loopingLeavesConnectedToActiveLeaf():
136
- return my[indexMy.leafConnectee] != my[indexMy.leaf1ndex]
135
+ def loopingLeavesConnectedToActiveLeaf():
136
+ return my[indexMy.leafConnectee] != my[indexMy.leaf1ndex]
137
137
 
138
- def loopingTheDimensions():
139
- return my[indexMy.dimension1ndex] <= the[indexThe.dimensionsTotal]
138
+ def loopingTheDimensions():
139
+ return my[indexMy.dimension1ndex] <= the[indexThe.dimensionsTotal]
140
140
 
141
- def loopingToActiveGapCeiling():
142
- return my[indexMy.indexMiniGap] < my[indexMy.gap1ndexCeiling]
143
-
144
- def placeLeaf():
145
- my[indexMy.gap1ndex] -= 1
146
- track[indexTrack.leafAbove, my[indexMy.leaf1ndex]] = gapsWhere[my[indexMy.gap1ndex]]
147
- track[indexTrack.leafBelow, my[indexMy.leaf1ndex]] = track[indexTrack.leafBelow, track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]]
148
- track[indexTrack.leafBelow, track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]] = my[indexMy.leaf1ndex]
149
- track[indexTrack.leafAbove, track[indexTrack.leafBelow, my[indexMy.leaf1ndex]]] = my[indexMy.leaf1ndex]
150
- track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex]] = my[indexMy.gap1ndex]
151
- my[indexMy.leaf1ndex] += 1
152
-
153
- def placeLeafCondition():
154
- return my[indexMy.leaf1ndex] > 0
155
-
156
- def taskIndexCondition():
157
- return my[indexMy.leafConnectee] % the[indexThe.taskDivisions] == my[indexMy.taskIndex]
158
-
159
- def thereAreComputationDivisionsYouMightSkip():
160
- if computationDivisionsCondition():
161
- return True
162
- if activeLeafNotEqualToTaskDivisionsCondition():
163
- return True
164
- if taskIndexCondition():
165
- return True
166
- return False
167
-
168
- stateUniversal = outfitFoldings(listDimensions, computationDivisions=computationDivisions, CPUlimit=CPUlimit)
169
- connectionGraph: Final[numpy.ndarray] = stateUniversal['connectionGraph']
170
- foldsSubTotals = stateUniversal['foldsSubTotals']
171
- gapsWhere = stateUniversal['gapsWhere']
172
- my = stateUniversal['my']
173
- the: Final[numpy.ndarray] = stateUniversal['the']
174
- track = stateUniversal['track']
175
-
176
- if the[indexThe.taskDivisions] == int(False):
177
- doWhile()
178
- else:
179
- stateUniversal['my'] = my.copy()
180
- stateUniversal['gapsWhere'] = gapsWhere.copy()
181
- stateUniversal['track'] = track.copy()
182
- for indexSherpa in range(the[indexThe.taskDivisions]):
183
- my = stateUniversal['my'].copy()
184
- my[indexMy.taskIndex] = indexSherpa
185
- gapsWhere = stateUniversal['gapsWhere'].copy()
186
- track = stateUniversal['track'].copy()
187
- doWhile()
188
-
189
- return numpy.sum(foldsSubTotals).item()
141
+ def loopingToActiveGapCeiling():
142
+ return my[indexMy.indexMiniGap] < my[indexMy.gap1ndexCeiling]
143
+
144
+ def placeLeaf():
145
+ my[indexMy.gap1ndex] -= 1
146
+ track[indexTrack.leafAbove, my[indexMy.leaf1ndex]] = gapsWhere[my[indexMy.gap1ndex]]
147
+ track[indexTrack.leafBelow, my[indexMy.leaf1ndex]] = track[indexTrack.leafBelow, track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]]
148
+ track[indexTrack.leafBelow, track[indexTrack.leafAbove, my[indexMy.leaf1ndex]]] = my[indexMy.leaf1ndex]
149
+ track[indexTrack.leafAbove, track[indexTrack.leafBelow, my[indexMy.leaf1ndex]]] = my[indexMy.leaf1ndex]
150
+ track[indexTrack.gapRangeStart, my[indexMy.leaf1ndex]] = my[indexMy.gap1ndex]
151
+ my[indexMy.leaf1ndex] += 1
152
+
153
+ def placeLeafCondition():
154
+ return my[indexMy.leaf1ndex] > 0
155
+
156
+ def taskIndexCondition():
157
+ return my[indexMy.leafConnectee] % the[indexThe.taskDivisions] == my[indexMy.taskIndex]
158
+
159
+ def thereAreComputationDivisionsYouMightSkip():
160
+ if computationDivisionsCondition():
161
+ return True
162
+ if activeLeafNotEqualToTaskDivisionsCondition():
163
+ return True
164
+ if taskIndexCondition():
165
+ return True
166
+ return False
167
+
168
+ stateUniversal = outfitFoldings(listDimensions, computationDivisions=computationDivisions, CPUlimit=CPUlimit)
169
+ connectionGraph: Final[numpy.ndarray] = stateUniversal['connectionGraph']
170
+ foldsSubTotals = stateUniversal['foldsSubTotals']
171
+ gapsWhere = stateUniversal['gapsWhere']
172
+ my = stateUniversal['my']
173
+ the: Final[numpy.ndarray] = stateUniversal['the']
174
+ track = stateUniversal['track']
175
+
176
+ if the[indexThe.taskDivisions] == int(False):
177
+ doWhile()
178
+ else:
179
+ stateUniversal['my'] = my.copy()
180
+ stateUniversal['gapsWhere'] = gapsWhere.copy()
181
+ stateUniversal['track'] = track.copy()
182
+ for indexSherpa in range(the[indexThe.taskDivisions]):
183
+ my = stateUniversal['my'].copy()
184
+ my[indexMy.taskIndex] = indexSherpa
185
+ gapsWhere = stateUniversal['gapsWhere'].copy()
186
+ track = stateUniversal['track'].copy()
187
+ doWhile()
188
+
189
+ return numpy.sum(foldsSubTotals).item()
190
190
 
191
191
  @enum.verify(enum.CONTINUOUS, enum.UNIQUE) if sys.version_info >= (3, 11) else lambda x: x
192
192
  class EnumIndices(enum.IntEnum):
193
- """Base class for index enums."""
194
- @staticmethod
195
- def _generate_next_value_(name, start, count, last_values):
196
- """0-indexed."""
197
- return count
193
+ """Base class for index enums."""
194
+ @staticmethod
195
+ def _generate_next_value_(name, start, count, last_values):
196
+ """0-indexed."""
197
+ return count
198
198
 
199
- def __index__(self) -> int:
200
- """Adapt enum to the ultra-rare event of indexing a NumPy 'ndarray', which is not the
201
- same as `array.array`. See NumPy.org; I think it will be very popular someday."""
202
- return self
199
+ def __index__(self) -> int:
200
+ """Adapt enum to the ultra-rare event of indexing a NumPy 'ndarray', which is not the
201
+ same as `array.array`. See NumPy.org; I think it will be very popular someday."""
202
+ return self
203
203
 
204
204
  class indexMy(EnumIndices):
205
- """Indices for dynamic values."""
206
- dimension1ndex = enum.auto()
207
- dimensionsUnconstrained = enum.auto()
208
- gap1ndex = enum.auto()
209
- gap1ndexCeiling = enum.auto()
210
- indexLeaf = enum.auto()
211
- indexMiniGap = enum.auto()
212
- leaf1ndex = enum.auto()
213
- leafConnectee = enum.auto()
214
- taskIndex = enum.auto()
205
+ """Indices for dynamic values."""
206
+ dimension1ndex = enum.auto()
207
+ dimensionsUnconstrained = enum.auto()
208
+ gap1ndex = enum.auto()
209
+ gap1ndexCeiling = enum.auto()
210
+ indexLeaf = enum.auto()
211
+ indexMiniGap = enum.auto()
212
+ leaf1ndex = enum.auto()
213
+ leafConnectee = enum.auto()
214
+ taskIndex = enum.auto()
215
215
 
216
216
  class indexThe(EnumIndices):
217
- """Indices for static values."""
218
- dimensionsTotal = enum.auto()
219
- leavesTotal = enum.auto()
220
- taskDivisions = enum.auto()
217
+ """Indices for static values."""
218
+ dimensionsTotal = enum.auto()
219
+ leavesTotal = enum.auto()
220
+ taskDivisions = enum.auto()
221
221
 
222
222
  class indexTrack(EnumIndices):
223
- """Indices for state tracking array."""
224
- leafAbove = enum.auto()
225
- leafBelow = enum.auto()
226
- countDimensionsGapped = enum.auto()
227
- gapRangeStart = enum.auto()
223
+ """Indices for state tracking array."""
224
+ leafAbove = enum.auto()
225
+ leafBelow = enum.auto()
226
+ countDimensionsGapped = enum.auto()
227
+ gapRangeStart = enum.auto()
228
228
 
229
229
  class computationState(TypedDict):
230
- connectionGraph: NDArray[integer[Any]]
231
- foldsSubTotals: NDArray[integer[Any]]
232
- mapShape: Tuple[int, ...]
233
- my: NDArray[integer[Any]]
234
- gapsWhere: NDArray[integer[Any]]
235
- the: NDArray[integer[Any]]
236
- track: NDArray[integer[Any]]
230
+ connectionGraph: NDArray[integer[Any]]
231
+ foldsSubTotals: NDArray[integer[Any]]
232
+ mapShape: Tuple[int, ...]
233
+ my: NDArray[integer[Any]]
234
+ gapsWhere: NDArray[integer[Any]]
235
+ the: NDArray[integer[Any]]
236
+ track: NDArray[integer[Any]]
237
237
 
238
238
  dtypeLarge = numpy.int64
239
239
  dtypeMedium = dtypeLarge
240
240
 
241
241
  def getLeavesTotal(listDimensions: Sequence[int]) -> int:
242
- """
243
- How many leaves are in the map.
242
+ """
243
+ How many leaves are in the map.
244
244
 
245
- Parameters:
246
- listDimensions: A list of integers representing dimensions.
245
+ Parameters:
246
+ listDimensions: A list of integers representing dimensions.
247
247
 
248
- Returns:
249
- productDimensions: The product of all positive integer dimensions.
250
- """
251
- listNonNegative = parseDimensions(listDimensions, 'listDimensions')
252
- listPositive = [dimension for dimension in listNonNegative if dimension > 0]
248
+ Returns:
249
+ productDimensions: The product of all positive integer dimensions.
250
+ """
251
+ listNonNegative = parseDimensions(listDimensions, 'listDimensions')
252
+ listPositive = [dimension for dimension in listNonNegative if dimension > 0]
253
253
 
254
- if not listPositive:
255
- return 0
256
- else:
257
- productDimensions = 1
258
- for dimension in listPositive:
259
- if dimension > sys.maxsize // productDimensions:
260
- raise OverflowError(f"I received {dimension=} in {listDimensions=}, but the product of the dimensions exceeds the maximum size of an integer on this system.")
261
- productDimensions *= dimension
254
+ if not listPositive:
255
+ return 0
256
+ else:
257
+ productDimensions = 1
258
+ for dimension in listPositive:
259
+ if dimension > sys.maxsize // productDimensions:
260
+ raise OverflowError(f"I received {dimension=} in {listDimensions=}, but the product of the dimensions exceeds the maximum size of an integer on this system.")
261
+ productDimensions *= dimension
262
262
 
263
- return productDimensions
263
+ return productDimensions
264
264
 
265
265
  def getTaskDivisions(computationDivisions: Optional[Union[int, str]], concurrencyLimit: int, CPUlimit: Optional[Union[bool, float, int]], listDimensions: Sequence[int]):
266
- if not computationDivisions:
267
- return 0
268
- else:
269
- leavesTotal = getLeavesTotal(listDimensions)
270
- if isinstance(computationDivisions, int):
271
- taskDivisions = computationDivisions
272
- elif isinstance(computationDivisions, str):
273
- computationDivisions = computationDivisions.lower()
274
- if computationDivisions == "maximum":
275
- taskDivisions = leavesTotal
276
- elif computationDivisions == "cpu":
277
- taskDivisions = min(concurrencyLimit, leavesTotal)
278
- else:
279
- raise ValueError("Not my problem.")
280
-
281
- if taskDivisions > leavesTotal:
282
- raise ValueError("What are you doing?")
283
-
284
- return taskDivisions
266
+ if not computationDivisions:
267
+ return 0
268
+ else:
269
+ leavesTotal = getLeavesTotal(listDimensions)
270
+ taskDivisions = 0
271
+ if isinstance(computationDivisions, int):
272
+ taskDivisions = computationDivisions
273
+ elif isinstance(computationDivisions, str):
274
+ computationDivisions = computationDivisions.lower()
275
+ if computationDivisions == "maximum":
276
+ taskDivisions = leavesTotal
277
+ elif computationDivisions == "cpu":
278
+ taskDivisions = min(concurrencyLimit, leavesTotal)
279
+ else:
280
+ raise ValueError("Not my problem.")
281
+
282
+ if taskDivisions > leavesTotal:
283
+ raise ValueError("What are you doing?")
284
+
285
+ return taskDivisions
285
286
 
286
287
  def makeConnectionGraph(listDimensions: Sequence[int], **keywordArguments: Optional[Type]) -> NDArray[integer[Any]]:
287
- datatype = keywordArguments.get('datatype', dtypeMedium)
288
- mapShape = validateListDimensions(listDimensions)
289
- leavesTotal = getLeavesTotal(mapShape)
290
- arrayDimensions = numpy.array(mapShape, dtype=datatype)
291
- dimensionsTotal = len(arrayDimensions)
292
-
293
- cumulativeProduct = numpy.multiply.accumulate([1] + mapShape, dtype=datatype)
294
- coordinateSystem = numpy.zeros((dimensionsTotal + 1, leavesTotal + 1), dtype=datatype)
295
- for dimension1ndex in range(1, dimensionsTotal + 1):
296
- for leaf1ndex in range(1, leavesTotal + 1):
297
- coordinateSystem[dimension1ndex, leaf1ndex] = ( ((leaf1ndex - 1) // cumulativeProduct[dimension1ndex - 1]) % arrayDimensions[dimension1ndex - 1] + 1 )
298
-
299
- connectionGraph = numpy.zeros((dimensionsTotal + 1, leavesTotal + 1, leavesTotal + 1), dtype=datatype)
300
- for dimension1ndex in range(1, dimensionsTotal + 1):
301
- for activeLeaf1ndex in range(1, leavesTotal + 1):
302
- for connectee1ndex in range(1, activeLeaf1ndex + 1):
303
- isFirstCoord = coordinateSystem[dimension1ndex, connectee1ndex] == 1
304
- isLastCoord = coordinateSystem[dimension1ndex, connectee1ndex] == arrayDimensions[dimension1ndex - 1]
305
- exceedsActive = connectee1ndex + cumulativeProduct[dimension1ndex - 1] > activeLeaf1ndex
306
- isEvenParity = (coordinateSystem[dimension1ndex, activeLeaf1ndex] & 1) == (coordinateSystem[dimension1ndex, connectee1ndex] & 1)
307
-
308
- if (isEvenParity and isFirstCoord) or (not isEvenParity and (isLastCoord or exceedsActive)):
309
- connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex
310
- elif isEvenParity and not isFirstCoord:
311
- connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex - cumulativeProduct[dimension1ndex - 1]
312
- elif not isEvenParity and not (isLastCoord or exceedsActive):
313
- connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex + cumulativeProduct[dimension1ndex - 1]
314
- else:
315
- connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex
316
- return connectionGraph
288
+ datatype = keywordArguments.get('datatype', dtypeMedium)
289
+ mapShape = validateListDimensions(listDimensions)
290
+ leavesTotal = getLeavesTotal(mapShape)
291
+ arrayDimensions = numpy.array(mapShape, dtype=datatype)
292
+ dimensionsTotal = len(arrayDimensions)
293
+
294
+ cumulativeProduct = numpy.multiply.accumulate([1] + mapShape, dtype=datatype)
295
+ coordinateSystem = numpy.zeros((dimensionsTotal + 1, leavesTotal + 1), dtype=datatype)
296
+ for dimension1ndex in range(1, dimensionsTotal + 1):
297
+ for leaf1ndex in range(1, leavesTotal + 1):
298
+ coordinateSystem[dimension1ndex, leaf1ndex] = ( ((leaf1ndex - 1) // cumulativeProduct[dimension1ndex - 1]) % arrayDimensions[dimension1ndex - 1] + 1 )
299
+
300
+ connectionGraph = numpy.zeros((dimensionsTotal + 1, leavesTotal + 1, leavesTotal + 1), dtype=datatype)
301
+ for dimension1ndex in range(1, dimensionsTotal + 1):
302
+ for activeLeaf1ndex in range(1, leavesTotal + 1):
303
+ for connectee1ndex in range(1, activeLeaf1ndex + 1):
304
+ isFirstCoord = coordinateSystem[dimension1ndex, connectee1ndex] == 1
305
+ isLastCoord = coordinateSystem[dimension1ndex, connectee1ndex] == arrayDimensions[dimension1ndex - 1]
306
+ exceedsActive = connectee1ndex + cumulativeProduct[dimension1ndex - 1] > activeLeaf1ndex
307
+ isEvenParity = (coordinateSystem[dimension1ndex, activeLeaf1ndex] & 1) == (coordinateSystem[dimension1ndex, connectee1ndex] & 1)
308
+
309
+ if (isEvenParity and isFirstCoord) or (not isEvenParity and (isLastCoord or exceedsActive)):
310
+ connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex
311
+ elif isEvenParity and not isFirstCoord:
312
+ connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex - cumulativeProduct[dimension1ndex - 1]
313
+ elif not isEvenParity and not (isLastCoord or exceedsActive):
314
+ connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex + cumulativeProduct[dimension1ndex - 1]
315
+ else:
316
+ connectionGraph[dimension1ndex, activeLeaf1ndex, connectee1ndex] = connectee1ndex
317
+ return connectionGraph
317
318
 
318
319
  def makeDataContainer(shape, datatype: Optional[Type] = None):
319
- if datatype is None:
320
- datatype = dtypeMedium
321
- return numpy.zeros(shape, dtype=datatype)
320
+ if datatype is None:
321
+ datatype = dtypeMedium
322
+ return numpy.zeros(shape, dtype=datatype)
322
323
 
323
324
  def outfitFoldings(listDimensions: Sequence[int], computationDivisions: Optional[Union[int, str]] = None, CPUlimit: Optional[Union[bool, float, int]] = None, **keywordArguments: Optional[Type]) -> computationState:
324
- datatypeMedium = keywordArguments.get('datatypeMedium', dtypeMedium)
325
- datatypeLarge = keywordArguments.get('datatypeLarge', dtypeLarge)
326
-
327
- the = makeDataContainer(len(indexThe), datatypeMedium)
328
-
329
- mapShape = tuple(sorted(validateListDimensions(listDimensions)))
330
- the[indexThe.leavesTotal] = getLeavesTotal(mapShape)
331
- the[indexThe.dimensionsTotal] = len(mapShape)
332
- concurrencyLimit = setCPUlimit(CPUlimit)
333
- the[indexThe.taskDivisions] = getTaskDivisions(computationDivisions, concurrencyLimit, CPUlimit, listDimensions)
334
-
335
- stateInitialized = computationState(
336
- connectionGraph = makeConnectionGraph(mapShape, datatype=datatypeMedium),
337
- foldsSubTotals = makeDataContainer(the[indexThe.leavesTotal], datatypeLarge),
338
- mapShape = mapShape,
339
- my = makeDataContainer(len(indexMy), datatypeLarge),
340
- gapsWhere = makeDataContainer(int(the[indexThe.leavesTotal]) * int(the[indexThe.leavesTotal]) + 1, datatypeMedium),
341
- the = the,
342
- track = makeDataContainer((len(indexTrack), the[indexThe.leavesTotal] + 1), datatypeLarge)
343
- )
344
-
345
- stateInitialized['my'][indexMy.leaf1ndex] = 1
346
- return stateInitialized
325
+ datatypeMedium = keywordArguments.get('datatypeMedium', dtypeMedium)
326
+ datatypeLarge = keywordArguments.get('datatypeLarge', dtypeLarge)
327
+
328
+ the = makeDataContainer(len(indexThe), datatypeMedium)
329
+
330
+ mapShape = tuple(sorted(validateListDimensions(listDimensions)))
331
+ the[indexThe.leavesTotal] = getLeavesTotal(mapShape)
332
+ the[indexThe.dimensionsTotal] = len(mapShape)
333
+ concurrencyLimit = setCPUlimit(CPUlimit)
334
+ the[indexThe.taskDivisions] = getTaskDivisions(computationDivisions, concurrencyLimit, CPUlimit, listDimensions)
335
+
336
+ stateInitialized = computationState(
337
+ connectionGraph = makeConnectionGraph(mapShape, datatype=datatypeMedium),
338
+ foldsSubTotals = makeDataContainer(the[indexThe.leavesTotal], datatypeLarge),
339
+ mapShape = mapShape,
340
+ my = makeDataContainer(len(indexMy), datatypeLarge),
341
+ gapsWhere = makeDataContainer(int(the[indexThe.leavesTotal]) * int(the[indexThe.leavesTotal]) + 1, datatypeMedium),
342
+ the = the,
343
+ track = makeDataContainer((len(indexTrack), the[indexThe.leavesTotal] + 1), datatypeLarge)
344
+ )
345
+
346
+ stateInitialized['my'][indexMy.leaf1ndex] = 1
347
+ return stateInitialized
347
348
 
348
349
  def parseDimensions(dimensions: Sequence[int], parameterName: str = 'unnamed parameter') -> List[int]:
349
- # listValidated = intInnit(dimensions, parameterName)
350
- listNOTValidated = dimensions if isinstance(dimensions, (list, tuple)) else list(dimensions)
351
- listNonNegative = []
352
- for dimension in listNOTValidated:
353
- if dimension < 0:
354
- raise ValueError(f"Dimension {dimension} must be non-negative")
355
- listNonNegative.append(dimension)
356
- if not listNonNegative:
357
- raise ValueError("At least one dimension must be non-negative")
358
- return listNonNegative
350
+ # listValidated = intInnit(dimensions, parameterName)
351
+ listNOTValidated = dimensions if isinstance(dimensions, (list, tuple)) else list(dimensions)
352
+ listNonNegative = []
353
+ for dimension in listNOTValidated:
354
+ if dimension < 0:
355
+ raise ValueError(f"Dimension {dimension} must be non-negative")
356
+ listNonNegative.append(dimension)
357
+ if not listNonNegative:
358
+ raise ValueError("At least one dimension must be non-negative")
359
+ return listNonNegative
359
360
 
360
361
  def setCPUlimit(CPUlimit: Union[bool, float, int, None]) -> int:
361
- # if not (CPUlimit is None or isinstance(CPUlimit, (bool, int, float))):
362
- # CPUlimit = oopsieKwargsie(CPUlimit)
363
- # concurrencyLimit = defineConcurrencyLimit(CPUlimit)
364
- # numba.set_num_threads(concurrencyLimit)
365
- concurrencyLimitHARDCODED = 1
366
- concurrencyLimit = concurrencyLimitHARDCODED
367
- return concurrencyLimit
362
+ # if not (CPUlimit is None or isinstance(CPUlimit, (bool, int, float))):
363
+ # CPUlimit = oopsieKwargsie(CPUlimit)
364
+ # concurrencyLimit = defineConcurrencyLimit(CPUlimit)
365
+ # numba.set_num_threads(concurrencyLimit)
366
+ concurrencyLimitHARDCODED = 1
367
+ concurrencyLimit = concurrencyLimitHARDCODED
368
+ return concurrencyLimit
368
369
 
369
370
  def validateListDimensions(listDimensions: Sequence[int]) -> List[int]:
370
- if not listDimensions:
371
- raise ValueError(f"listDimensions is a required parameter.")
372
- listNonNegative = parseDimensions(listDimensions, 'listDimensions')
373
- dimensionsValid = [dimension for dimension in listNonNegative if dimension > 0]
374
- if len(dimensionsValid) < 2:
375
- raise NotImplementedError(f"This function requires listDimensions, {listDimensions}, to have at least two dimensions greater than 0. You may want to look at https://oeis.org/.")
376
- return sorted(dimensionsValid)
371
+ if not listDimensions:
372
+ raise ValueError(f"listDimensions is a required parameter.")
373
+ listNonNegative = parseDimensions(listDimensions, 'listDimensions')
374
+ dimensionsValid = [dimension for dimension in listNonNegative if dimension > 0]
375
+ if len(dimensionsValid) < 2:
376
+ raise NotImplementedError(f"This function requires listDimensions, {listDimensions}, to have at least two dimensions greater than 0. You may want to look at https://oeis.org/.")
377
+ return sorted(dimensionsValid)