mapFolding 0.7.1__py3-none-any.whl → 0.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mapFolding/__init__.py +33 -4
- mapFolding/basecamp.py +14 -0
- mapFolding/beDRY.py +93 -82
- mapFolding/filesystem.py +124 -90
- mapFolding/noHomeYet.py +14 -2
- mapFolding/oeis.py +18 -3
- mapFolding/reference/flattened.py +46 -45
- mapFolding/reference/hunterNumba.py +4 -4
- mapFolding/reference/irvineJavaPort.py +1 -1
- mapFolding/reference/lunnanNumpy.py +3 -4
- mapFolding/reference/lunnanWhile.py +5 -7
- mapFolding/reference/rotatedEntryPoint.py +2 -3
- mapFolding/someAssemblyRequired/__init__.py +33 -3
- mapFolding/someAssemblyRequired/getLLVMforNoReason.py +32 -15
- mapFolding/someAssemblyRequired/ingredientsNumba.py +108 -2
- mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +196 -0
- mapFolding/someAssemblyRequired/{synthesizeNumbaJob.py → synthesizeNumbaJobVESTIGIAL.py} +19 -23
- mapFolding/someAssemblyRequired/transformDataStructures.py +162 -0
- mapFolding/someAssemblyRequired/transformationTools.py +607 -252
- mapFolding/syntheticModules/numbaCount_doTheNeedful.py +197 -12
- mapFolding/theDao.py +37 -16
- mapFolding/theSSOT.py +47 -44
- {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info}/METADATA +51 -46
- mapfolding-0.8.1.dist-info/RECORD +39 -0
- {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info}/WHEEL +1 -1
- tests/conftest.py +2 -3
- tests/test_filesystem.py +0 -2
- tests/test_other.py +2 -3
- tests/test_tasks.py +0 -4
- mapFolding/reference/lunnan.py +0 -153
- mapFolding/someAssemblyRequired/Z0Z_workbench.py +0 -33
- mapFolding/someAssemblyRequired/synthesizeCountingFunctions.py +0 -7
- mapFolding/someAssemblyRequired/synthesizeDataConverters.py +0 -135
- mapFolding/someAssemblyRequired/synthesizeNumba.py +0 -91
- mapFolding/someAssemblyRequired/synthesizeNumbaModules.py +0 -91
- mapFolding/someAssemblyRequired/whatWillBe.py +0 -357
- mapFolding/syntheticModules/dataNamespaceFlattened.py +0 -30
- mapFolding/syntheticModules/multiprocessingCount_doTheNeedful.py +0 -216
- mapFolding/syntheticModules/numbaCount.py +0 -90
- mapFolding/syntheticModules/numbaCountExample.py +0 -158
- mapFolding/syntheticModules/numbaCountSequential.py +0 -111
- mapFolding/syntheticModules/numba_doTheNeedful.py +0 -12
- mapFolding/syntheticModules/numba_doTheNeedfulExample.py +0 -13
- mapfolding-0.7.1.dist-info/RECORD +0 -51
- /mapFolding/{syntheticModules → reference}/__init__.py +0 -0
- {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info/licenses}/LICENSE +0 -0
- {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info}/top_level.txt +0 -0
|
@@ -1,13 +1,198 @@
|
|
|
1
|
-
from
|
|
2
|
-
from
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
from concurrent.futures import Future as ConcurrentFuture, ProcessPoolExecutor
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from mapFolding.theSSOT import Array1DElephino, Array1DFoldsTotal, Array1DLeavesTotal, Array3D, ComputationState, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal
|
|
4
|
+
from numba import jit
|
|
5
|
+
|
|
6
|
+
def countInitialize(state: ComputationState) -> ComputationState:
|
|
7
|
+
while state.leaf1ndex > 0:
|
|
8
|
+
if state.leaf1ndex <= 1 or state.leafBelow[0] == 1:
|
|
9
|
+
state.dimensionsUnconstrained = state.dimensionsTotal
|
|
10
|
+
state.gap1ndexCeiling = state.gapRangeStart[state.leaf1ndex - 1]
|
|
11
|
+
state.indexDimension = 0
|
|
12
|
+
while state.indexDimension < state.dimensionsTotal:
|
|
13
|
+
state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leaf1ndex]
|
|
14
|
+
if state.leafConnectee == state.leaf1ndex:
|
|
15
|
+
state.dimensionsUnconstrained -= 1
|
|
16
|
+
else:
|
|
17
|
+
while state.leafConnectee != state.leaf1ndex:
|
|
18
|
+
state.gapsWhere[state.gap1ndexCeiling] = state.leafConnectee
|
|
19
|
+
if state.countDimensionsGapped[state.leafConnectee] == 0:
|
|
20
|
+
state.gap1ndexCeiling += 1
|
|
21
|
+
state.countDimensionsGapped[state.leafConnectee] += 1
|
|
22
|
+
state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leafBelow[state.leafConnectee]]
|
|
23
|
+
state.indexDimension += 1
|
|
24
|
+
if not state.dimensionsUnconstrained:
|
|
25
|
+
indexLeaf = 0
|
|
26
|
+
while indexLeaf < state.leaf1ndex:
|
|
27
|
+
state.gapsWhere[state.gap1ndexCeiling] = indexLeaf
|
|
28
|
+
state.gap1ndexCeiling += 1
|
|
29
|
+
indexLeaf += 1
|
|
30
|
+
state.indexMiniGap = state.gap1ndex
|
|
31
|
+
while state.indexMiniGap < state.gap1ndexCeiling:
|
|
32
|
+
state.gapsWhere[state.gap1ndex] = state.gapsWhere[state.indexMiniGap]
|
|
33
|
+
if state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] == state.dimensionsUnconstrained:
|
|
34
|
+
state.gap1ndex += 1
|
|
35
|
+
state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] = 0
|
|
36
|
+
state.indexMiniGap += 1
|
|
37
|
+
if state.leaf1ndex > 0:
|
|
38
|
+
state.gap1ndex -= 1
|
|
39
|
+
state.leafAbove[state.leaf1ndex] = state.gapsWhere[state.gap1ndex]
|
|
40
|
+
state.leafBelow[state.leaf1ndex] = state.leafBelow[state.leafAbove[state.leaf1ndex]]
|
|
41
|
+
state.leafBelow[state.leafAbove[state.leaf1ndex]] = state.leaf1ndex
|
|
42
|
+
state.leafAbove[state.leafBelow[state.leaf1ndex]] = state.leaf1ndex
|
|
43
|
+
state.gapRangeStart[state.leaf1ndex] = state.gap1ndex
|
|
44
|
+
state.leaf1ndex += 1
|
|
45
|
+
if state.gap1ndex > 0:
|
|
46
|
+
break
|
|
47
|
+
return state
|
|
48
|
+
|
|
49
|
+
@jit(_nrt=True, boundscheck=False, cache=True, error_model='numpy', fastmath=True, forceinline=True, inline='always', looplift=False, no_cfunc_wrapper=False, no_cpython_wrapper=False, nopython=True, parallel=False)
|
|
50
|
+
def countParallel(mapShape: tuple[DatatypeLeavesTotal, ...], leavesTotal: DatatypeLeavesTotal, taskDivisions: DatatypeLeavesTotal, concurrencyLimit: DatatypeElephino, connectionGraph: Array3D, dimensionsTotal: DatatypeLeavesTotal, countDimensionsGapped: Array1DLeavesTotal, dimensionsUnconstrained: DatatypeLeavesTotal, gapRangeStart: Array1DElephino, gapsWhere: Array1DLeavesTotal, leafAbove: Array1DLeavesTotal, leafBelow: Array1DLeavesTotal, foldGroups: Array1DFoldsTotal, foldsTotal: DatatypeFoldsTotal, gap1ndex: DatatypeLeavesTotal, gap1ndexCeiling: DatatypeElephino, groupsOfFolds: DatatypeFoldsTotal, indexDimension: DatatypeLeavesTotal, indexLeaf: DatatypeLeavesTotal, indexMiniGap: DatatypeElephino, leaf1ndex: DatatypeElephino, leafConnectee: DatatypeElephino, taskIndex: DatatypeLeavesTotal) -> DatatypeFoldsTotal:
|
|
51
|
+
while leaf1ndex > 0:
|
|
52
|
+
if leaf1ndex <= 1 or leafBelow[0] == 1:
|
|
53
|
+
if leaf1ndex > leavesTotal:
|
|
54
|
+
groupsOfFolds += 1
|
|
55
|
+
else:
|
|
56
|
+
dimensionsUnconstrained = dimensionsTotal
|
|
57
|
+
gap1ndexCeiling = gapRangeStart[leaf1ndex - 1]
|
|
58
|
+
indexDimension = 0
|
|
59
|
+
while indexDimension < dimensionsTotal:
|
|
60
|
+
if connectionGraph[indexDimension, leaf1ndex, leaf1ndex] == leaf1ndex:
|
|
61
|
+
dimensionsUnconstrained -= 1
|
|
62
|
+
else:
|
|
63
|
+
leafConnectee = connectionGraph[indexDimension, leaf1ndex, leaf1ndex]
|
|
64
|
+
while leafConnectee != leaf1ndex:
|
|
65
|
+
if leaf1ndex != taskDivisions or leafConnectee % taskDivisions == taskIndex:
|
|
66
|
+
gapsWhere[gap1ndexCeiling] = leafConnectee
|
|
67
|
+
if countDimensionsGapped[leafConnectee] == 0:
|
|
68
|
+
gap1ndexCeiling += 1
|
|
69
|
+
countDimensionsGapped[leafConnectee] += 1
|
|
70
|
+
leafConnectee = connectionGraph[indexDimension, leaf1ndex, leafBelow[leafConnectee]]
|
|
71
|
+
indexDimension += 1
|
|
72
|
+
indexMiniGap = gap1ndex
|
|
73
|
+
while indexMiniGap < gap1ndexCeiling:
|
|
74
|
+
gapsWhere[gap1ndex] = gapsWhere[indexMiniGap]
|
|
75
|
+
if countDimensionsGapped[gapsWhere[indexMiniGap]] == dimensionsUnconstrained:
|
|
76
|
+
gap1ndex += 1
|
|
77
|
+
countDimensionsGapped[gapsWhere[indexMiniGap]] = 0
|
|
78
|
+
indexMiniGap += 1
|
|
79
|
+
while leaf1ndex > 0 and gap1ndex == gapRangeStart[leaf1ndex - 1]:
|
|
80
|
+
leaf1ndex -= 1
|
|
81
|
+
leafBelow[leafAbove[leaf1ndex]] = leafBelow[leaf1ndex]
|
|
82
|
+
leafAbove[leafBelow[leaf1ndex]] = leafAbove[leaf1ndex]
|
|
83
|
+
if leaf1ndex > 0:
|
|
84
|
+
gap1ndex -= 1
|
|
85
|
+
leafAbove[leaf1ndex] = gapsWhere[gap1ndex]
|
|
86
|
+
leafBelow[leaf1ndex] = leafBelow[leafAbove[leaf1ndex]]
|
|
87
|
+
leafBelow[leafAbove[leaf1ndex]] = leaf1ndex
|
|
88
|
+
leafAbove[leafBelow[leaf1ndex]] = leaf1ndex
|
|
89
|
+
gapRangeStart[leaf1ndex] = gap1ndex
|
|
90
|
+
leaf1ndex += 1
|
|
91
|
+
foldGroups[taskIndex] = groupsOfFolds
|
|
92
|
+
return groupsOfFolds
|
|
93
|
+
|
|
94
|
+
@jit(_nrt=True, boundscheck=False, cache=True, error_model='numpy', fastmath=True, forceinline=True, inline='always', looplift=False, no_cfunc_wrapper=False, no_cpython_wrapper=False, nopython=True, parallel=False)
|
|
95
|
+
def countSequential(mapShape: tuple[DatatypeLeavesTotal, ...], leavesTotal: DatatypeLeavesTotal, taskDivisions: DatatypeLeavesTotal, concurrencyLimit: DatatypeElephino, connectionGraph: Array3D, dimensionsTotal: DatatypeLeavesTotal, countDimensionsGapped: Array1DLeavesTotal, dimensionsUnconstrained: DatatypeLeavesTotal, gapRangeStart: Array1DElephino, gapsWhere: Array1DLeavesTotal, leafAbove: Array1DLeavesTotal, leafBelow: Array1DLeavesTotal, foldGroups: Array1DFoldsTotal, foldsTotal: DatatypeFoldsTotal, gap1ndex: DatatypeLeavesTotal, gap1ndexCeiling: DatatypeElephino, groupsOfFolds: DatatypeFoldsTotal, indexDimension: DatatypeLeavesTotal, indexLeaf: DatatypeLeavesTotal, indexMiniGap: DatatypeElephino, leaf1ndex: DatatypeElephino, leafConnectee: DatatypeElephino, taskIndex: DatatypeLeavesTotal) -> tuple[tuple[DatatypeLeavesTotal, ...], DatatypeLeavesTotal, DatatypeLeavesTotal, DatatypeElephino, Array3D, DatatypeLeavesTotal, Array1DLeavesTotal, DatatypeLeavesTotal, Array1DElephino, Array1DLeavesTotal, Array1DLeavesTotal, Array1DLeavesTotal, Array1DFoldsTotal, DatatypeFoldsTotal, DatatypeLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal, DatatypeLeavesTotal, DatatypeElephino, DatatypeElephino, DatatypeElephino, DatatypeLeavesTotal]:
|
|
96
|
+
while leaf1ndex > 0:
|
|
97
|
+
if leaf1ndex <= 1 or leafBelow[0] == 1:
|
|
98
|
+
if leaf1ndex > leavesTotal:
|
|
99
|
+
groupsOfFolds += 1
|
|
100
|
+
else:
|
|
101
|
+
dimensionsUnconstrained = dimensionsTotal
|
|
102
|
+
gap1ndexCeiling = gapRangeStart[leaf1ndex - 1]
|
|
103
|
+
indexDimension = 0
|
|
104
|
+
while indexDimension < dimensionsTotal:
|
|
105
|
+
leafConnectee = connectionGraph[indexDimension, leaf1ndex, leaf1ndex]
|
|
106
|
+
if leafConnectee == leaf1ndex:
|
|
107
|
+
dimensionsUnconstrained -= 1
|
|
108
|
+
else:
|
|
109
|
+
while leafConnectee != leaf1ndex:
|
|
110
|
+
gapsWhere[gap1ndexCeiling] = leafConnectee
|
|
111
|
+
if countDimensionsGapped[leafConnectee] == 0:
|
|
112
|
+
gap1ndexCeiling += 1
|
|
113
|
+
countDimensionsGapped[leafConnectee] += 1
|
|
114
|
+
leafConnectee = connectionGraph[indexDimension, leaf1ndex, leafBelow[leafConnectee]]
|
|
115
|
+
indexDimension += 1
|
|
116
|
+
indexMiniGap = gap1ndex
|
|
117
|
+
while indexMiniGap < gap1ndexCeiling:
|
|
118
|
+
gapsWhere[gap1ndex] = gapsWhere[indexMiniGap]
|
|
119
|
+
if countDimensionsGapped[gapsWhere[indexMiniGap]] == dimensionsUnconstrained:
|
|
120
|
+
gap1ndex += 1
|
|
121
|
+
countDimensionsGapped[gapsWhere[indexMiniGap]] = 0
|
|
122
|
+
indexMiniGap += 1
|
|
123
|
+
while leaf1ndex > 0 and gap1ndex == gapRangeStart[leaf1ndex - 1]:
|
|
124
|
+
leaf1ndex -= 1
|
|
125
|
+
leafBelow[leafAbove[leaf1ndex]] = leafBelow[leaf1ndex]
|
|
126
|
+
leafAbove[leafBelow[leaf1ndex]] = leafAbove[leaf1ndex]
|
|
127
|
+
if leaf1ndex > 0:
|
|
128
|
+
gap1ndex -= 1
|
|
129
|
+
leafAbove[leaf1ndex] = gapsWhere[gap1ndex]
|
|
130
|
+
leafBelow[leaf1ndex] = leafBelow[leafAbove[leaf1ndex]]
|
|
131
|
+
leafBelow[leafAbove[leaf1ndex]] = leaf1ndex
|
|
132
|
+
leafAbove[leafBelow[leaf1ndex]] = leaf1ndex
|
|
133
|
+
gapRangeStart[leaf1ndex] = gap1ndex
|
|
134
|
+
leaf1ndex += 1
|
|
135
|
+
foldGroups[taskIndex] = groupsOfFolds
|
|
136
|
+
return (mapShape, leavesTotal, taskDivisions, concurrencyLimit, connectionGraph, dimensionsTotal, countDimensionsGapped, dimensionsUnconstrained, gapRangeStart, gapsWhere, leafAbove, leafBelow, foldGroups, foldsTotal, gap1ndex, gap1ndexCeiling, groupsOfFolds, indexDimension, indexLeaf, indexMiniGap, leaf1ndex, leafConnectee, taskIndex)
|
|
137
|
+
|
|
138
|
+
def doTheNeedful(state: ComputationState) -> ComputationState:
|
|
139
|
+
state = countInitialize(state)
|
|
140
|
+
if state.taskDivisions > 0:
|
|
141
|
+
dictionaryConcurrency: dict[int, ConcurrentFuture[ComputationState]] = {}
|
|
142
|
+
with ProcessPoolExecutor(state.concurrencyLimit) as concurrencyManager:
|
|
143
|
+
for indexSherpa in range(state.taskDivisions):
|
|
144
|
+
stateParallel = deepcopy(state)
|
|
145
|
+
stateParallel.taskIndex = indexSherpa
|
|
146
|
+
mapShape: tuple[DatatypeLeavesTotal, ...] = stateParallel.mapShape
|
|
147
|
+
leavesTotal: DatatypeLeavesTotal = stateParallel.leavesTotal
|
|
148
|
+
taskDivisions: DatatypeLeavesTotal = stateParallel.taskDivisions
|
|
149
|
+
concurrencyLimit: DatatypeElephino = stateParallel.concurrencyLimit
|
|
150
|
+
connectionGraph: Array3D = stateParallel.connectionGraph
|
|
151
|
+
dimensionsTotal: DatatypeLeavesTotal = stateParallel.dimensionsTotal
|
|
152
|
+
countDimensionsGapped: Array1DLeavesTotal = stateParallel.countDimensionsGapped
|
|
153
|
+
dimensionsUnconstrained: DatatypeLeavesTotal = stateParallel.dimensionsUnconstrained
|
|
154
|
+
gapRangeStart: Array1DElephino = stateParallel.gapRangeStart
|
|
155
|
+
gapsWhere: Array1DLeavesTotal = stateParallel.gapsWhere
|
|
156
|
+
leafAbove: Array1DLeavesTotal = stateParallel.leafAbove
|
|
157
|
+
leafBelow: Array1DLeavesTotal = stateParallel.leafBelow
|
|
158
|
+
foldGroups: Array1DFoldsTotal = stateParallel.foldGroups
|
|
159
|
+
foldsTotal: DatatypeFoldsTotal = stateParallel.foldsTotal
|
|
160
|
+
gap1ndex: DatatypeLeavesTotal = stateParallel.gap1ndex
|
|
161
|
+
gap1ndexCeiling: DatatypeElephino = stateParallel.gap1ndexCeiling
|
|
162
|
+
groupsOfFolds: DatatypeFoldsTotal = stateParallel.groupsOfFolds
|
|
163
|
+
indexDimension: DatatypeLeavesTotal = stateParallel.indexDimension
|
|
164
|
+
indexLeaf: DatatypeLeavesTotal = stateParallel.indexLeaf
|
|
165
|
+
indexMiniGap: DatatypeElephino = stateParallel.indexMiniGap
|
|
166
|
+
leaf1ndex: DatatypeElephino = stateParallel.leaf1ndex
|
|
167
|
+
leafConnectee: DatatypeElephino = stateParallel.leafConnectee
|
|
168
|
+
taskIndex: DatatypeLeavesTotal = stateParallel.taskIndex
|
|
169
|
+
dictionaryConcurrency[indexSherpa] = concurrencyManager.submit(countParallel, mapShape, leavesTotal, taskDivisions, concurrencyLimit, connectionGraph, dimensionsTotal, countDimensionsGapped, dimensionsUnconstrained, gapRangeStart, gapsWhere, leafAbove, leafBelow, foldGroups, foldsTotal, gap1ndex, gap1ndexCeiling, groupsOfFolds, indexDimension, indexLeaf, indexMiniGap, leaf1ndex, leafConnectee, taskIndex)
|
|
170
|
+
for indexSherpa in range(state.taskDivisions):
|
|
171
|
+
state.foldGroups[indexSherpa] = dictionaryConcurrency[indexSherpa].result()
|
|
12
172
|
else:
|
|
13
|
-
|
|
173
|
+
mapShape: tuple[DatatypeLeavesTotal, ...] = state.mapShape
|
|
174
|
+
leavesTotal: DatatypeLeavesTotal = state.leavesTotal
|
|
175
|
+
taskDivisions: DatatypeLeavesTotal = state.taskDivisions
|
|
176
|
+
concurrencyLimit: DatatypeElephino = state.concurrencyLimit
|
|
177
|
+
connectionGraph: Array3D = state.connectionGraph
|
|
178
|
+
dimensionsTotal: DatatypeLeavesTotal = state.dimensionsTotal
|
|
179
|
+
countDimensionsGapped: Array1DLeavesTotal = state.countDimensionsGapped
|
|
180
|
+
dimensionsUnconstrained: DatatypeLeavesTotal = state.dimensionsUnconstrained
|
|
181
|
+
gapRangeStart: Array1DElephino = state.gapRangeStart
|
|
182
|
+
gapsWhere: Array1DLeavesTotal = state.gapsWhere
|
|
183
|
+
leafAbove: Array1DLeavesTotal = state.leafAbove
|
|
184
|
+
leafBelow: Array1DLeavesTotal = state.leafBelow
|
|
185
|
+
foldGroups: Array1DFoldsTotal = state.foldGroups
|
|
186
|
+
foldsTotal: DatatypeFoldsTotal = state.foldsTotal
|
|
187
|
+
gap1ndex: DatatypeLeavesTotal = state.gap1ndex
|
|
188
|
+
gap1ndexCeiling: DatatypeElephino = state.gap1ndexCeiling
|
|
189
|
+
groupsOfFolds: DatatypeFoldsTotal = state.groupsOfFolds
|
|
190
|
+
indexDimension: DatatypeLeavesTotal = state.indexDimension
|
|
191
|
+
indexLeaf: DatatypeLeavesTotal = state.indexLeaf
|
|
192
|
+
indexMiniGap: DatatypeElephino = state.indexMiniGap
|
|
193
|
+
leaf1ndex: DatatypeElephino = state.leaf1ndex
|
|
194
|
+
leafConnectee: DatatypeElephino = state.leafConnectee
|
|
195
|
+
taskIndex: DatatypeLeavesTotal = state.taskIndex
|
|
196
|
+
mapShape, leavesTotal, taskDivisions, concurrencyLimit, connectionGraph, dimensionsTotal, countDimensionsGapped, dimensionsUnconstrained, gapRangeStart, gapsWhere, leafAbove, leafBelow, foldGroups, foldsTotal, gap1ndex, gap1ndexCeiling, groupsOfFolds, indexDimension, indexLeaf, indexMiniGap, leaf1ndex, leafConnectee, taskIndex = countSequential(mapShape, leavesTotal, taskDivisions, concurrencyLimit, connectionGraph, dimensionsTotal, countDimensionsGapped, dimensionsUnconstrained, gapRangeStart, gapsWhere, leafAbove, leafBelow, foldGroups, foldsTotal, gap1ndex, gap1ndexCeiling, groupsOfFolds, indexDimension, indexLeaf, indexMiniGap, leaf1ndex, leafConnectee, taskIndex)
|
|
197
|
+
state = ComputationState(mapShape=mapShape, leavesTotal=leavesTotal, taskDivisions=taskDivisions, concurrencyLimit=concurrencyLimit, countDimensionsGapped=countDimensionsGapped, dimensionsUnconstrained=dimensionsUnconstrained, gapRangeStart=gapRangeStart, gapsWhere=gapsWhere, leafAbove=leafAbove, leafBelow=leafBelow, foldGroups=foldGroups, foldsTotal=foldsTotal, gap1ndex=gap1ndex, gap1ndexCeiling=gap1ndexCeiling, groupsOfFolds=groupsOfFolds, indexDimension=indexDimension, indexLeaf=indexLeaf, indexMiniGap=indexMiniGap, leaf1ndex=leaf1ndex, leafConnectee=leafConnectee, taskIndex=taskIndex)
|
|
198
|
+
return state
|
mapFolding/theDao.py
CHANGED
|
@@ -1,12 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
|
+
Core computational algorithm for map folding counting and enumeration.
|
|
3
|
+
|
|
4
|
+
This module implements the core algorithms for enumerating and counting the various ways
|
|
5
|
+
a rectangular map can be folded. It uses a functional state-transformation approach, where
|
|
6
|
+
each function performs a specific state mutation and returns the updated state. The module
|
|
7
|
+
provides three main counting algorithms:
|
|
8
|
+
|
|
9
|
+
1. countInitialize: Sets up the initial state for computation
|
|
10
|
+
2. countSequential: Processes the folding computation sequentially
|
|
11
|
+
3. countParallel: Distributes the computation across multiple processes
|
|
12
|
+
|
|
13
|
+
All algorithms operate on a ComputationState object that tracks the folding process, including:
|
|
14
|
+
- A "leaf" is a unit square in the map
|
|
15
|
+
- A "gap" is a potential position where a new leaf can be folded
|
|
16
|
+
- Connections track how leaves can connect above/below each other
|
|
17
|
+
- Leaves are enumerated starting from 1, not 0; hence, leaf1ndex not leafIndex
|
|
18
|
+
|
|
19
|
+
The doTheNeedful function is the main entry point that orchestrates the computation strategy
|
|
20
|
+
based on task divisions and concurrency parameters.
|
|
21
|
+
"""
|
|
22
|
+
from concurrent.futures import Future as ConcurrentFuture, ProcessPoolExecutor
|
|
23
|
+
from copy import deepcopy
|
|
2
24
|
from mapFolding.theSSOT import ComputationState
|
|
3
|
-
import
|
|
4
|
-
import copy
|
|
5
|
-
import multiprocessing
|
|
25
|
+
from multiprocessing import set_start_method as multiprocessing_set_start_method
|
|
6
26
|
|
|
7
27
|
# When to use multiprocessing.set_start_method https://github.com/hunterhogan/mapFolding/issues/6
|
|
8
28
|
if __name__ == '__main__':
|
|
9
|
-
|
|
29
|
+
multiprocessing_set_start_method('spawn')
|
|
10
30
|
|
|
11
31
|
def activeLeafConnectedToItself(state: ComputationState) -> bool:
|
|
12
32
|
return state.leafConnectee == state.leaf1ndex
|
|
@@ -23,7 +43,7 @@ def activeLeafIsTheFirstLeaf(state: ComputationState) -> bool:
|
|
|
23
43
|
def allDimensionsAreUnconstrained(state: ComputationState) -> bool:
|
|
24
44
|
return not state.dimensionsUnconstrained
|
|
25
45
|
|
|
26
|
-
def
|
|
46
|
+
def undoLastLeafPlacement(state: ComputationState) -> ComputationState:
|
|
27
47
|
state.leaf1ndex -= 1
|
|
28
48
|
state.leafBelow[state.leafAbove[state.leaf1ndex]] = state.leafBelow[state.leaf1ndex]
|
|
29
49
|
state.leafAbove[state.leafBelow[state.leaf1ndex]] = state.leafAbove[state.leaf1ndex]
|
|
@@ -103,7 +123,7 @@ def loopUpToDimensionsTotal(state: ComputationState) -> bool:
|
|
|
103
123
|
def noGapsHere(state: ComputationState) -> bool:
|
|
104
124
|
return (state.leaf1ndex > 0) and (state.gap1ndex == state.gapRangeStart[state.leaf1ndex - 1])
|
|
105
125
|
|
|
106
|
-
def
|
|
126
|
+
def insertLeafAtGap(state: ComputationState) -> ComputationState:
|
|
107
127
|
state.gap1ndex -= 1
|
|
108
128
|
state.leafAbove[state.leaf1ndex] = state.gapsWhere[state.gap1ndex]
|
|
109
129
|
state.leafBelow[state.leaf1ndex] = state.leafBelow[state.leafAbove[state.leaf1ndex]]
|
|
@@ -143,7 +163,7 @@ def countInitialize(state: ComputationState) -> ComputationState:
|
|
|
143
163
|
state = filterCommonGaps(state)
|
|
144
164
|
state = incrementIndexMiniGap(state)
|
|
145
165
|
if thereIsAnActiveLeaf(state):
|
|
146
|
-
state =
|
|
166
|
+
state = insertLeafAtGap(state)
|
|
147
167
|
if state.gap1ndex > 0:
|
|
148
168
|
break
|
|
149
169
|
return state
|
|
@@ -170,9 +190,9 @@ def countParallel(state: ComputationState) -> ComputationState:
|
|
|
170
190
|
state = filterCommonGaps(state)
|
|
171
191
|
state = incrementIndexMiniGap(state)
|
|
172
192
|
while noGapsHere(state):
|
|
173
|
-
state =
|
|
193
|
+
state = undoLastLeafPlacement(state)
|
|
174
194
|
if thereIsAnActiveLeaf(state):
|
|
175
|
-
state =
|
|
195
|
+
state = insertLeafAtGap(state)
|
|
176
196
|
state.foldGroups[state.taskIndex] = state.groupsOfFolds
|
|
177
197
|
return state
|
|
178
198
|
|
|
@@ -197,23 +217,24 @@ def countSequential(state: ComputationState) -> ComputationState:
|
|
|
197
217
|
state = filterCommonGaps(state)
|
|
198
218
|
state = incrementIndexMiniGap(state)
|
|
199
219
|
while noGapsHere(state):
|
|
200
|
-
state =
|
|
220
|
+
state = undoLastLeafPlacement(state)
|
|
201
221
|
if thereIsAnActiveLeaf(state):
|
|
202
|
-
state =
|
|
222
|
+
state = insertLeafAtGap(state)
|
|
203
223
|
state.foldGroups[state.taskIndex] = state.groupsOfFolds
|
|
204
224
|
return state
|
|
205
225
|
|
|
206
226
|
def doTheNeedful(state: ComputationState) -> ComputationState:
|
|
207
227
|
state = countInitialize(state)
|
|
208
228
|
if state.taskDivisions > 0:
|
|
209
|
-
dictionaryConcurrency: dict[int,
|
|
229
|
+
dictionaryConcurrency: dict[int, ConcurrentFuture[ComputationState]] = {}
|
|
210
230
|
with ProcessPoolExecutor(state.concurrencyLimit) as concurrencyManager:
|
|
211
231
|
for indexSherpa in range(state.taskDivisions):
|
|
212
|
-
stateParallel =
|
|
232
|
+
stateParallel = deepcopy(state)
|
|
213
233
|
stateParallel.taskIndex = indexSherpa
|
|
214
234
|
dictionaryConcurrency[indexSherpa] = concurrencyManager.submit(countParallel, stateParallel)
|
|
215
235
|
for indexSherpa in range(state.taskDivisions):
|
|
216
236
|
state.foldGroups[indexSherpa] = dictionaryConcurrency[indexSherpa].result().foldGroups[indexSherpa]
|
|
217
|
-
return state
|
|
218
237
|
else:
|
|
219
|
-
|
|
238
|
+
state = countSequential(state)
|
|
239
|
+
|
|
240
|
+
return state
|
mapFolding/theSSOT.py
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Single Source of Truth module for configuration, types, and computational state management.
|
|
3
|
+
|
|
4
|
+
This module defines the core data structures, type definitions, and configuration settings
|
|
5
|
+
used throughout the mapFolding package. It implements the Single Source of Truth (SSOT)
|
|
6
|
+
principle to ensure consistency across the package's components.
|
|
7
|
+
|
|
8
|
+
Key features:
|
|
9
|
+
1. The ComputationState dataclass, which encapsulates the state of the folding computation
|
|
10
|
+
2. Unified type definitions for integers and arrays used in the computation
|
|
11
|
+
3. Configuration settings for synthetic module generation and dispatching
|
|
12
|
+
4. Path resolution and management for package resources and job output
|
|
13
|
+
5. Dynamic dispatch functionality for algorithm implementations
|
|
14
|
+
|
|
15
|
+
The module differentiates between "the" identifiers (package defaults) and other identifiers
|
|
16
|
+
to avoid namespace collisions when transforming algorithms.
|
|
17
|
+
"""
|
|
18
|
+
|
|
1
19
|
from collections.abc import Callable
|
|
2
20
|
from importlib import import_module as importlib_import_module
|
|
3
21
|
from inspect import getfile as inspect_getfile
|
|
@@ -20,12 +38,11 @@ Identifiers: scope and resolution, LEGB (Local, Enclosing, Global, Builtin)
|
|
|
20
38
|
"""
|
|
21
39
|
|
|
22
40
|
# I _think_, in theSSOT, I have abstracted the flow settings to only these couple of lines:
|
|
41
|
+
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
23
42
|
packageFlowSynthetic = 'numba'
|
|
24
|
-
#
|
|
25
|
-
Z0Z_packageFlow =
|
|
26
|
-
|
|
27
|
-
# Z0Z_packageFlow = packageFlowSynthetic
|
|
28
|
-
|
|
43
|
+
# Z0Z_packageFlow = 'algorithm'
|
|
44
|
+
Z0Z_packageFlow = packageFlowSynthetic
|
|
45
|
+
Z0Z_concurrencyPackage = 'multiprocessing'
|
|
29
46
|
# =============================================================================
|
|
30
47
|
# The Wrong Way The Wrong Way The Wrong Way The Wrong Way The Wrong Way
|
|
31
48
|
# Evaluate When Packaging Evaluate When Packaging Evaluate When Packaging
|
|
@@ -38,8 +55,7 @@ moduleOfSyntheticModulesPACKAGING: Final[str] = 'syntheticModules'
|
|
|
38
55
|
dataclassModulePACKAGING: str = 'theSSOT'
|
|
39
56
|
dataclassIdentifierPACKAGING: str = 'ComputationState'
|
|
40
57
|
dataclassInstancePACKAGING: str = 'state'
|
|
41
|
-
|
|
42
|
-
dataclassInstance_Post_ParallelPACKAGING = dataclassInstancePACKAGING + 'COMPLETE'
|
|
58
|
+
dataclassInstanceTaskDistributionPACKAGING = dataclassInstancePACKAGING + 'Parallel'
|
|
43
59
|
|
|
44
60
|
sourceInitializeCallablePACKAGING = 'countInitialize'
|
|
45
61
|
sourceSequentialCallablePACKAGING = 'countSequential'
|
|
@@ -48,7 +64,7 @@ sourceParallelCallablePACKAGING = 'countParallel'
|
|
|
48
64
|
try:
|
|
49
65
|
thePackageNamePACKAGING: str = tomli_load(Path("../pyproject.toml").open('rb'))["project"]["name"]
|
|
50
66
|
except Exception:
|
|
51
|
-
thePackageNamePACKAGING
|
|
67
|
+
thePackageNamePACKAGING = "mapFolding"
|
|
52
68
|
|
|
53
69
|
# =============================================================================
|
|
54
70
|
# The Wrong Way The Wrong Way The Wrong Way The Wrong Way The Wrong Way
|
|
@@ -62,14 +78,9 @@ def getPathPackageINSTALLING() -> Path:
|
|
|
62
78
|
pathPackage = pathPackage.parent
|
|
63
79
|
return pathPackage
|
|
64
80
|
|
|
65
|
-
# =============================================================================
|
|
66
|
-
# The Wrong Way The Wrong Way The Wrong Way The Wrong Way The Wrong Way
|
|
67
|
-
# Hardcoding Hardcoding Hardcoding Hardcoding Hardcoding Hardcoding Hardcoding
|
|
68
|
-
|
|
69
81
|
# =============================================================================
|
|
70
82
|
# The right way, perhaps.
|
|
71
83
|
|
|
72
|
-
# =====================
|
|
73
84
|
# Create enduring identifiers from the hopefully transient identifiers above.
|
|
74
85
|
thePackageName: Final[str] = thePackageNamePACKAGING
|
|
75
86
|
thePathPackage: Path = getPathPackageINSTALLING()
|
|
@@ -94,16 +105,17 @@ theDispatcherCallable: str = dispatcherCallablePACKAGING
|
|
|
94
105
|
theDataclassModule: str = dataclassModulePACKAGING
|
|
95
106
|
theDataclassIdentifier: str = dataclassIdentifierPACKAGING
|
|
96
107
|
theDataclassInstance: str = dataclassInstancePACKAGING
|
|
97
|
-
|
|
98
|
-
theDataclassInstance_Post_Parallel: str = dataclassInstance_Post_ParallelPACKAGING
|
|
108
|
+
theDataclassInstanceTaskDistribution: str = dataclassInstanceTaskDistributionPACKAGING
|
|
99
109
|
|
|
100
110
|
theFileExtension: str = fileExtensionINSTALLING
|
|
101
111
|
|
|
102
112
|
theModuleOfSyntheticModules: Final[str] = moduleOfSyntheticModulesPACKAGING
|
|
103
113
|
|
|
104
114
|
# =============================================================================
|
|
105
|
-
|
|
115
|
+
|
|
116
|
+
# Figure out dynamic flow control to synthesized modules https://github.com/hunterhogan/mapFolding/issues/4
|
|
106
117
|
concurrencyPackage: str = Z0Z_packageFlow
|
|
118
|
+
concurrencyPackage = Z0Z_concurrencyPackage
|
|
107
119
|
|
|
108
120
|
# =============================================================================
|
|
109
121
|
# The relatively flexible type system needs a different paradigm, but I don't
|
|
@@ -141,30 +153,30 @@ class ComputationState:
|
|
|
141
153
|
taskDivisions: DatatypeLeavesTotal
|
|
142
154
|
concurrencyLimit: DatatypeElephino
|
|
143
155
|
|
|
144
|
-
connectionGraph: Array3D = dataclasses.field(init=False
|
|
156
|
+
connectionGraph: Array3D = dataclasses.field(init=False)
|
|
145
157
|
dimensionsTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
|
|
146
158
|
|
|
147
|
-
countDimensionsGapped: Array1DLeavesTotal = dataclasses.field(default=None) #
|
|
148
|
-
dimensionsUnconstrained: DatatypeLeavesTotal = dataclasses.field(default=None) #
|
|
149
|
-
gapRangeStart: Array1DElephino = dataclasses.field(default=None) #
|
|
150
|
-
gapsWhere: Array1DLeavesTotal = dataclasses.field(default=None) #
|
|
151
|
-
leafAbove: Array1DLeavesTotal = dataclasses.field(default=None) #
|
|
152
|
-
leafBelow: Array1DLeavesTotal = dataclasses.field(default=None) #
|
|
153
|
-
foldGroups: Array1DFoldsTotal = dataclasses.field(default=None) #
|
|
159
|
+
countDimensionsGapped: Array1DLeavesTotal = dataclasses.field(default=None, init=True) # type: ignore[arg-type, reportAssignmentType]
|
|
160
|
+
dimensionsUnconstrained: DatatypeLeavesTotal = dataclasses.field(default=None, init=True) # type: ignore[assignment, reportAssignmentType]
|
|
161
|
+
gapRangeStart: Array1DElephino = dataclasses.field(default=None, init=True) # type: ignore[arg-type, reportAssignmentType]
|
|
162
|
+
gapsWhere: Array1DLeavesTotal = dataclasses.field(default=None, init=True) # type: ignore[arg-type, reportAssignmentType]
|
|
163
|
+
leafAbove: Array1DLeavesTotal = dataclasses.field(default=None, init=True) # type: ignore[arg-type, reportAssignmentType]
|
|
164
|
+
leafBelow: Array1DLeavesTotal = dataclasses.field(default=None, init=True) # type: ignore[arg-type, reportAssignmentType]
|
|
165
|
+
foldGroups: Array1DFoldsTotal = dataclasses.field(default=None, init=True) # type: ignore[arg-type, reportAssignmentType]
|
|
154
166
|
|
|
155
167
|
foldsTotal: DatatypeFoldsTotal = DatatypeFoldsTotal(0)
|
|
156
168
|
gap1ndex: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
|
|
157
169
|
gap1ndexCeiling: DatatypeElephino = DatatypeElephino(0)
|
|
158
|
-
groupsOfFolds: DatatypeFoldsTotal = DatatypeFoldsTotal(0)
|
|
170
|
+
groupsOfFolds: DatatypeFoldsTotal = dataclasses.field(default=DatatypeFoldsTotal(0), metadata={'theCountingIdentifier': True})
|
|
159
171
|
indexDimension: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
|
|
160
172
|
indexLeaf: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
|
|
161
173
|
indexMiniGap: DatatypeElephino = DatatypeElephino(0)
|
|
162
174
|
leaf1ndex: DatatypeElephino = DatatypeElephino(1)
|
|
163
175
|
leafConnectee: DatatypeElephino = DatatypeElephino(0)
|
|
164
|
-
taskIndex: DatatypeLeavesTotal =
|
|
165
|
-
#
|
|
176
|
+
taskIndex: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
|
|
177
|
+
# Efficient translation of Python scalar types to Numba types https://github.com/hunterhogan/mapFolding/issues/8
|
|
166
178
|
|
|
167
|
-
def __post_init__(self):
|
|
179
|
+
def __post_init__(self) -> None:
|
|
168
180
|
from mapFolding.beDRY import makeConnectionGraph, makeDataContainer
|
|
169
181
|
self.dimensionsTotal = DatatypeLeavesTotal(len(self.mapShape))
|
|
170
182
|
self.connectionGraph = makeConnectionGraph(self.mapShape, self.leavesTotal, numpyLeavesTotal)
|
|
@@ -189,14 +201,9 @@ class ComputationState:
|
|
|
189
201
|
if self.leafBelow is None:
|
|
190
202
|
self.leafBelow = makeDataContainer(leavesTotalAsInt + 1, numpyLeavesTotal)
|
|
191
203
|
|
|
192
|
-
def getFoldsTotal(self):
|
|
204
|
+
def getFoldsTotal(self) -> None:
|
|
193
205
|
self.foldsTotal = DatatypeFoldsTotal(self.foldGroups[0:-1].sum() * self.leavesTotal)
|
|
194
206
|
|
|
195
|
-
# factory? constructor?
|
|
196
|
-
# state.taskIndex = state.taskIndex.type(indexSherpa)
|
|
197
|
-
# self.fieldName = self.fieldName.fieldType(indexSherpa)
|
|
198
|
-
# state.taskIndex.toMyType(indexSherpa)
|
|
199
|
-
|
|
200
207
|
# =============================================================================
|
|
201
208
|
# The most right way I know how to implement.
|
|
202
209
|
|
|
@@ -208,8 +215,7 @@ def getSourceAlgorithm() -> ModuleType:
|
|
|
208
215
|
moduleImported: ModuleType = importlib_import_module(theLogicalPathModuleSourceAlgorithm)
|
|
209
216
|
return moduleImported
|
|
210
217
|
|
|
211
|
-
|
|
212
|
-
def getAlgorithmDispatcher():
|
|
218
|
+
def getAlgorithmDispatcher() -> Callable[[ComputationState], ComputationState]:
|
|
213
219
|
moduleImported: ModuleType = getSourceAlgorithm()
|
|
214
220
|
dispatcherCallable = getattr(moduleImported, theDispatcherCallable)
|
|
215
221
|
return dispatcherCallable
|
|
@@ -238,7 +244,7 @@ def getNumpyDtypeDefault() -> type[signedinteger[Any]]:
|
|
|
238
244
|
# =============================================================================
|
|
239
245
|
# The coping way.
|
|
240
246
|
|
|
241
|
-
class
|
|
247
|
+
class raiseIfNoneGitHubIssueNumber3(Exception): pass
|
|
242
248
|
|
|
243
249
|
# =============================================================================
|
|
244
250
|
# Temporary or transient or something; probably still the wrong way
|
|
@@ -266,13 +272,8 @@ def getPackageDispatcher() -> Callable[[ComputationState], ComputationState]:
|
|
|
266
272
|
# NOTE but this part, if the package flow is synthetic, probably needs to be delegated
|
|
267
273
|
# to the authority for creating _that_ synthetic flow.
|
|
268
274
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
# dispatcherCallable = getattr(moduleImported, theDispatcherCallable)
|
|
272
|
-
|
|
273
|
-
# Hardcoded while I am refactoring "someAssemblyRequired"
|
|
274
|
-
from mapFolding.syntheticModules.numbaCountSequential import flattenData
|
|
275
|
-
dispatcherCallable = flattenData
|
|
275
|
+
moduleImported: ModuleType = importlib_import_module(theLogicalPathModuleDispatcher)
|
|
276
|
+
dispatcherCallable = getattr(moduleImported, theDispatcherCallable)
|
|
276
277
|
return dispatcherCallable
|
|
277
278
|
|
|
278
279
|
"""Technical concepts I am likely using and likely want to use more effectively:
|
|
@@ -281,8 +282,10 @@ def getPackageDispatcher() -> Callable[[ComputationState], ComputationState]:
|
|
|
281
282
|
- Lazy Initialization
|
|
282
283
|
- Separate configuration from business logic
|
|
283
284
|
|
|
285
|
+
----
|
|
284
286
|
theSSOT and yourSSOT
|
|
285
287
|
|
|
288
|
+
----
|
|
286
289
|
delay realization/instantiation until a concrete value is desired
|
|
287
290
|
moment of truth: when the value is needed, not when the value is defined
|
|
288
291
|
"""
|