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.
Files changed (48) hide show
  1. mapFolding/__init__.py +33 -4
  2. mapFolding/basecamp.py +14 -0
  3. mapFolding/beDRY.py +93 -82
  4. mapFolding/filesystem.py +124 -90
  5. mapFolding/noHomeYet.py +14 -2
  6. mapFolding/oeis.py +18 -3
  7. mapFolding/reference/flattened.py +46 -45
  8. mapFolding/reference/hunterNumba.py +4 -4
  9. mapFolding/reference/irvineJavaPort.py +1 -1
  10. mapFolding/reference/lunnanNumpy.py +3 -4
  11. mapFolding/reference/lunnanWhile.py +5 -7
  12. mapFolding/reference/rotatedEntryPoint.py +2 -3
  13. mapFolding/someAssemblyRequired/__init__.py +33 -3
  14. mapFolding/someAssemblyRequired/getLLVMforNoReason.py +32 -15
  15. mapFolding/someAssemblyRequired/ingredientsNumba.py +108 -2
  16. mapFolding/someAssemblyRequired/synthesizeNumbaFlow.py +196 -0
  17. mapFolding/someAssemblyRequired/{synthesizeNumbaJob.py → synthesizeNumbaJobVESTIGIAL.py} +19 -23
  18. mapFolding/someAssemblyRequired/transformDataStructures.py +162 -0
  19. mapFolding/someAssemblyRequired/transformationTools.py +607 -252
  20. mapFolding/syntheticModules/numbaCount_doTheNeedful.py +197 -12
  21. mapFolding/theDao.py +37 -16
  22. mapFolding/theSSOT.py +47 -44
  23. {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info}/METADATA +51 -46
  24. mapfolding-0.8.1.dist-info/RECORD +39 -0
  25. {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info}/WHEEL +1 -1
  26. tests/conftest.py +2 -3
  27. tests/test_filesystem.py +0 -2
  28. tests/test_other.py +2 -3
  29. tests/test_tasks.py +0 -4
  30. mapFolding/reference/lunnan.py +0 -153
  31. mapFolding/someAssemblyRequired/Z0Z_workbench.py +0 -33
  32. mapFolding/someAssemblyRequired/synthesizeCountingFunctions.py +0 -7
  33. mapFolding/someAssemblyRequired/synthesizeDataConverters.py +0 -135
  34. mapFolding/someAssemblyRequired/synthesizeNumba.py +0 -91
  35. mapFolding/someAssemblyRequired/synthesizeNumbaModules.py +0 -91
  36. mapFolding/someAssemblyRequired/whatWillBe.py +0 -357
  37. mapFolding/syntheticModules/dataNamespaceFlattened.py +0 -30
  38. mapFolding/syntheticModules/multiprocessingCount_doTheNeedful.py +0 -216
  39. mapFolding/syntheticModules/numbaCount.py +0 -90
  40. mapFolding/syntheticModules/numbaCountExample.py +0 -158
  41. mapFolding/syntheticModules/numbaCountSequential.py +0 -111
  42. mapFolding/syntheticModules/numba_doTheNeedful.py +0 -12
  43. mapFolding/syntheticModules/numba_doTheNeedfulExample.py +0 -13
  44. mapfolding-0.7.1.dist-info/RECORD +0 -51
  45. /mapFolding/{syntheticModules → reference}/__init__.py +0 -0
  46. {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info}/entry_points.txt +0 -0
  47. {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info/licenses}/LICENSE +0 -0
  48. {mapfolding-0.7.1.dist-info → mapfolding-0.8.1.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,198 @@
1
- from mapFolding import indexMy
2
- from mapFolding.syntheticModules.numbaCount import countInitialize, countSequential, countParallel
3
- from numba import uint16, int64, jit
4
- from numpy import ndarray, dtype, integer
5
- from typing import Any
6
-
7
- @jit((uint16[:, :, ::1], int64[::1], uint16[::1], uint16[::1], uint16[::1], uint16[:, ::1]), _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)
8
- def doTheNeedful(connectionGraph: ndarray[tuple[int, int, int], dtype[integer[Any]]], foldGroups: ndarray[tuple[int], dtype[integer[Any]]], gapsWhere: ndarray[tuple[int], dtype[integer[Any]]], mapShape: ndarray[tuple[int], dtype[integer[Any]]], my: ndarray[tuple[int], dtype[integer[Any]]], track: ndarray[tuple[int, int], dtype[integer[Any]]]) -> None:
9
- countInitialize(connectionGraph, gapsWhere, my, track)
10
- if my[indexMy.taskDivisions] > 0:
11
- countParallel(connectionGraph, foldGroups, gapsWhere, my, track)
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
- countSequential(connectionGraph, foldGroups, gapsWhere, my, track)
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
- from concurrent.futures import ProcessPoolExecutor
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 concurrent.futures
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
- multiprocessing.set_start_method('spawn')
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 backtrack(state: ComputationState) -> ComputationState:
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 placeLeaf(state: ComputationState) -> ComputationState:
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 = placeLeaf(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 = backtrack(state)
193
+ state = undoLastLeafPlacement(state)
174
194
  if thereIsAnActiveLeaf(state):
175
- state = placeLeaf(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 = backtrack(state)
220
+ state = undoLastLeafPlacement(state)
201
221
  if thereIsAnActiveLeaf(state):
202
- state = placeLeaf(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, concurrent.futures.Future[ComputationState]] = {}
229
+ dictionaryConcurrency: dict[int, ConcurrentFuture[ComputationState]] = {}
210
230
  with ProcessPoolExecutor(state.concurrencyLimit) as concurrencyManager:
211
231
  for indexSherpa in range(state.taskDivisions):
212
- stateParallel = copy.deepcopy(state)
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
- return countSequential(state)
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
- # packageFlowSynthetic = 'multiprocessing'
25
- Z0Z_packageFlow = 'algorithm'
26
- # https://github.com/hunterhogan/mapFolding/issues/4
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
- dataclassInstance_Pre_ParallelPACKAGING = dataclassInstancePACKAGING + 'PARALLEL'
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: str = "mapFolding"
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
- theDataclassInstance_Pre_Parallel: str = dataclassInstance_Pre_ParallelPACKAGING
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
- # The right way.
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, metadata={'description': 'A 3D array representing the connection graph of the map.'})
156
+ connectionGraph: Array3D = dataclasses.field(init=False)
145
157
  dimensionsTotal: DatatypeLeavesTotal = dataclasses.field(init=False)
146
158
 
147
- countDimensionsGapped: Array1DLeavesTotal = dataclasses.field(default=None) # pyright: ignore[reportAssignmentType]
148
- dimensionsUnconstrained: DatatypeLeavesTotal = dataclasses.field(default=None) # pyright: ignore[reportAssignmentType]
149
- gapRangeStart: Array1DElephino = dataclasses.field(default=None) # pyright: ignore[reportAssignmentType]
150
- gapsWhere: Array1DLeavesTotal = dataclasses.field(default=None) # pyright: ignore[reportAssignmentType]
151
- leafAbove: Array1DLeavesTotal = dataclasses.field(default=None) # pyright: ignore[reportAssignmentType]
152
- leafBelow: Array1DLeavesTotal = dataclasses.field(default=None) # pyright: ignore[reportAssignmentType]
153
- foldGroups: Array1DFoldsTotal = dataclasses.field(default=None) # pyright: ignore[reportAssignmentType]
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 = dataclasses.field(default=DatatypeLeavesTotal(0), metadata={'myType': DatatypeLeavesTotal})
165
- # taskIndex: DatatypeLeavesTotal = DatatypeLeavesTotal(0)
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
- # dynamically set the return type https://github.com/hunterhogan/mapFolding/issues/5
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 FREAKOUT(Exception): pass
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
- # Automated system
270
- # moduleImported: ModuleType = importlib_import_module(theLogicalPathModuleDispatcher)
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
  """