mapFolding 0.11.2__py3-none-any.whl → 0.11.4__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.
@@ -1,315 +0,0 @@
1
- """
2
- Job-specific Numba Code Generation for Map Folding Calculations
3
-
4
- This module specializes in generating highly-optimized, single-purpose Numba modules
5
- for specific map folding calculation jobs. Unlike the general-purpose transformation
6
- in toolboxNumba.py, this module creates standalone Python modules optimized for a
7
- single map shape with statically-encoded parameters.
8
-
9
- The code generation assembly line focuses on:
10
-
11
- 1. Converting function parameters to initialized variables with concrete values.
12
- 2. Replacing dynamic computations with statically-known values.
13
- 3. Eliminating unused code paths and variables.
14
- 4. Adding progress tracking for long-running calculations.
15
- 5. Applying appropriate Numba optimizations for the specific calculation.
16
-
17
- This creates extremely fast, specialized implementations that can be run directly
18
- as Python scripts or further compiled into standalone executables.
19
- """
20
-
21
- from astToolkit import ClassIsAndAttribute
22
- from mapFolding import getPathFilenameFoldsTotal, raiseIfNoneGitHubIssueNumber3, The
23
- from mapFolding.someAssemblyRequired import (
24
- ast_Identifier,
25
- Be,
26
- extractFunctionDef,
27
- IfThis,
28
- IngredientsFunction,
29
- IngredientsModule,
30
- LedgerOfImports,
31
- Make,
32
- NodeChanger,
33
- NodeTourist,
34
- str_nameDOTname,
35
- Then,
36
- write_astModule,
37
- )
38
- from mapFolding.someAssemblyRequired.RecipeJob import RecipeJob
39
- from mapFolding.someAssemblyRequired.toolkitNumba import parametersNumbaLight, SpicesJobNumba, decorateCallableWithNumba
40
- from mapFolding.someAssemblyRequired.transformationTools import dictionaryEstimates, makeInitializedComputationState
41
- from pathlib import PurePosixPath
42
- from typing import cast, NamedTuple
43
- from Z0Z_tools import autoDecodingRLE
44
- import ast
45
- """Synthesize one file to compute `foldsTotal` of `mapShape`."""
46
-
47
- list_IdentifiersNotUsedAllHARDCODED = ['concurrencyLimit', 'foldsTotal', 'mapShape',]
48
- list_IdentifiersNotUsedParallelSequentialHARDCODED = ['indexLeaf']
49
- list_IdentifiersNotUsedSequentialHARDCODED = ['foldGroups', 'taskDivisions', 'taskIndex',]
50
-
51
- list_IdentifiersReplacedHARDCODED = ['groupsOfFolds',]
52
-
53
- list_IdentifiersStaticValuesHARDCODED = ['dimensionsTotal', 'leavesTotal',]
54
-
55
- list_IdentifiersNotUsedHARDCODED = list_IdentifiersStaticValuesHARDCODED + list_IdentifiersReplacedHARDCODED + list_IdentifiersNotUsedAllHARDCODED + list_IdentifiersNotUsedParallelSequentialHARDCODED + list_IdentifiersNotUsedSequentialHARDCODED
56
-
57
- def addLauncherNumbaProgress(ingredientsModule: IngredientsModule, ingredientsFunction: IngredientsFunction, job: RecipeJob, spices: SpicesJobNumba) -> tuple[IngredientsModule, IngredientsFunction]:
58
- """
59
- Add progress tracking capabilities to a Numba-optimized function.
60
-
61
- This function modifies both the module and the function to integrate Numba-compatible
62
- progress tracking for long-running calculations. It performs several key transformations:
63
-
64
- 1. Adds a progress bar parameter to the function signature
65
- 2. Replaces counting increments with progress bar updates
66
- 3. Creates a launcher section that displays and updates progress
67
- 4. Configures file output to save results upon completion
68
-
69
- The progress tracking is particularly important for map folding calculations
70
- which can take hours or days to complete, providing visual feedback and
71
- estimated completion times.
72
-
73
- Parameters:
74
- ingredientsModule: The module where the function is defined.
75
- ingredientsFunction: The function to modify with progress tracking.
76
- job: Configuration specifying shape details and output paths.
77
- spices: Configuration specifying progress bar details.
78
-
79
- Returns:
80
- A tuple containing the modified module and function with progress tracking.
81
- """
82
- linesLaunch: str = f"""
83
- if __name__ == '__main__':
84
- with ProgressBar(total={job.foldsTotalEstimated}, update_interval=2) as statusUpdate:
85
- {job.countCallable}(statusUpdate)
86
- foldsTotal = statusUpdate.n * {job.state.leavesTotal}
87
- print('\\nmap {job.state.mapShape} =', foldsTotal)
88
- writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
89
- writeStream.write(str(foldsTotal))
90
- writeStream.close()
91
- """
92
- numba_progressPythonClass: ast_Identifier = 'ProgressBar'
93
- numba_progressNumbaType: ast_Identifier = 'ProgressBarType'
94
- ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressPythonClass)
95
- ingredientsModule.imports.addImportFrom_asStr('numba_progress', numba_progressNumbaType)
96
-
97
- ast_argNumbaProgress = ast.arg(arg=spices.numbaProgressBarIdentifier, annotation=ast.Name(id=numba_progressPythonClass, ctx=ast.Load()))
98
- ingredientsFunction.astFunctionDef.args.args.append(ast_argNumbaProgress)
99
-
100
- findThis = ClassIsAndAttribute.targetIs(ast.AugAssign, IfThis.isName_Identifier(job.shatteredDataclass.countingVariableName.id)) # type: ignore
101
- doThat = Then.replaceWith(Make.Expr(Make.Call(Make.Attribute(Make.Name(spices.numbaProgressBarIdentifier),'update'),[Make.Constant(1)])))
102
- countWithProgressBar = NodeChanger(findThis, doThat)
103
- countWithProgressBar.visit(ingredientsFunction.astFunctionDef)
104
-
105
- removeReturnStatement = NodeChanger(Be.Return, Then.removeIt)
106
- removeReturnStatement.visit(ingredientsFunction.astFunctionDef)
107
- ingredientsFunction.astFunctionDef.returns = Make.Constant(value=None)
108
-
109
- ingredientsModule.appendLauncher(ast.parse(linesLaunch))
110
-
111
- return ingredientsModule, ingredientsFunction
112
-
113
- def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job: RecipeJob) -> IngredientsFunction:
114
- """
115
- Convert function parameters into initialized variables with concrete values.
116
-
117
- This function implements a critical transformation that converts function parameters
118
- into statically initialized variables in the function body. This enables several
119
- optimizations:
120
-
121
- 1. Eliminating parameter passing overhead.
122
- 2. Embedding concrete values directly in the code.
123
- 3. Allowing Numba to optimize based on known value characteristics.
124
- 4. Simplifying function signatures for specialized use cases.
125
-
126
- The function handles different data types (scalars, arrays, custom types) appropriately,
127
- replacing abstract parameter references with concrete values from the computation state.
128
- It also removes unused parameters and variables to eliminate dead code.
129
-
130
- Parameters:
131
- ingredientsFunction: The function to transform.
132
- job: Recipe containing concrete values for parameters and field metadata.
133
-
134
- Returns:
135
- The modified function with parameters converted to initialized variables.
136
- """
137
- ingredientsFunction.imports.update(job.shatteredDataclass.imports)
138
-
139
- list_argCuzMyBrainRefusesToThink = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
140
- list_arg_arg: list[ast_Identifier] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
141
- listName: list[ast.Name] = []
142
- NodeTourist(Be.Name, Then.appendTo(listName)).visit(ingredientsFunction.astFunctionDef)
143
- list_Identifiers: list[ast_Identifier] = [astName.id for astName in listName]
144
- list_IdentifiersNotUsed: list[ast_Identifier] = list(set(list_arg_arg) - set(list_Identifiers))
145
-
146
- for ast_arg in list_argCuzMyBrainRefusesToThink:
147
- if ast_arg.arg in job.shatteredDataclass.field2AnnAssign:
148
- if ast_arg.arg in list_IdentifiersNotUsed:
149
- pass
150
- else:
151
- ImaAnnAssign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
152
- match elementConstructor:
153
- case 'scalar':
154
- cast(ast.Constant, cast(ast.Call, ImaAnnAssign.value).args[0]).value = int(job.state.__dict__[ast_arg.arg])
155
- case 'array':
156
- dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], True)
157
- dataAs_astExpr: ast.expr = cast(ast.Expr, ast.parse(dataAsStrRLE).body[0]).value
158
- cast(ast.Call, ImaAnnAssign.value).args = [dataAs_astExpr]
159
- case _:
160
- list_exprDOTannotation: list[ast.expr] = []
161
- list_exprDOTvalue: list[ast.expr] = []
162
- for dimension in job.state.mapShape:
163
- list_exprDOTannotation.append(Make.Name(elementConstructor))
164
- list_exprDOTvalue.append(Make.Call(Make.Name(elementConstructor), [Make.Constant(dimension)]))
165
- cast(ast.Tuple, cast(ast.Subscript, cast(ast.AnnAssign, ImaAnnAssign).annotation).slice).elts = list_exprDOTannotation
166
- cast(ast.Tuple, ImaAnnAssign.value).elts = list_exprDOTvalue
167
-
168
- ingredientsFunction.astFunctionDef.body.insert(0, ImaAnnAssign)
169
-
170
- findThis = IfThis.is_arg_Identifier(ast_arg.arg)
171
- remove_arg = NodeChanger(findThis, Then.removeIt)
172
- remove_arg.visit(ingredientsFunction.astFunctionDef)
173
-
174
- ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
175
- return ingredientsFunction
176
-
177
- def makeJobNumba(job: RecipeJob, spices: SpicesJobNumba) -> None:
178
- """
179
- Generate a highly-optimized, single-purpose Numba module for a specific map shape.
180
-
181
- This function implements the complete transformation assembly line for creating a
182
- standalone, specialized implementation for calculating map folding solutions for
183
- a specific shape. The process includes:
184
-
185
- 1. Extracting the counting function from the source module
186
- 2. Removing unused code paths based on static analysis
187
- 3. Replacing dynamic variables with concrete values
188
- 4. Converting parameters to initialized variables
189
- 5. Adding progress tracking if requested
190
- 6. Applying Numba optimizations and type specifications
191
- 7. Writing the final module to the filesystem
192
-
193
- The resulting Python module is both human-readable and extraordinarily efficient,
194
- with all shape-specific optimizations statically encoded. This creates specialized
195
- implementations that can be orders of magnitude faster than general-purpose code.
196
-
197
- Parameters:
198
- job: Configuration specifying the target shape, paths, and computation state.
199
- spices: Configuration specifying Numba and progress tracking options.
200
- """
201
- astFunctionDef = extractFunctionDef(job.source_astModule, job.countCallable)
202
- if not astFunctionDef: raise raiseIfNoneGitHubIssueNumber3
203
- ingredientsCount: IngredientsFunction = IngredientsFunction(astFunctionDef, LedgerOfImports())
204
-
205
- # Remove `foldGroups` and any other unused statements, so you can dynamically determine which variables are not used
206
- findThis = IfThis.isAssignAndTargets0Is(IfThis.isSubscript_Identifier('foldGroups'))
207
- doThat = Then.removeIt
208
- remove_foldGroups = NodeChanger(findThis, doThat)
209
- remove_foldGroups.visit(ingredientsCount.astFunctionDef)
210
-
211
- # replace identifiers with static values with their values, so you can dynamically determine which variables are not used
212
- list_IdentifiersStaticValues = list_IdentifiersStaticValuesHARDCODED
213
- for identifier in list_IdentifiersStaticValues:
214
- findThis = IfThis.isName_Identifier(identifier)
215
- doThat = Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
216
- NodeChanger(findThis, doThat).visit(ingredientsCount.astFunctionDef)
217
-
218
- ingredientsModule = IngredientsModule()
219
- # This launcher eliminates the use of one identifier, so run it now and you can dynamically determine which variables are not used
220
- if spices.useNumbaProgressBar:
221
- ingredientsModule, ingredientsCount = addLauncherNumbaProgress(ingredientsModule, ingredientsCount, job, spices)
222
- spices.parametersNumba['nogil'] = True
223
- else:
224
- linesLaunch: str = f"""
225
- if __name__ == '__main__':
226
- import time
227
- timeStart = time.perf_counter()
228
- foldsTotal = {job.countCallable}() * {job.state.leavesTotal}
229
- print(time.perf_counter() - timeStart)
230
- print('\\nmap {job.state.mapShape} =', foldsTotal)
231
- writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
232
- writeStream.write(str(foldsTotal))
233
- writeStream.close()
234
- """
235
- # from mapFolding.oeis import getFoldsTotalKnown
236
- # print(foldsTotal == getFoldsTotalKnown({job.state.mapShape}))
237
- ingredientsModule.appendLauncher(ast.parse(linesLaunch))
238
- changeReturnParallelCallable = NodeChanger(Be.Return, Then.replaceWith(Make.Return(job.shatteredDataclass.countingVariableName)))
239
- changeReturnParallelCallable.visit(ingredientsCount.astFunctionDef)
240
- ingredientsCount.astFunctionDef.returns = job.shatteredDataclass.countingVariableAnnotation
241
-
242
- ingredientsCount = move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsCount, job)
243
-
244
- class DatatypeConfig(NamedTuple):
245
- Z0Z_module: str_nameDOTname
246
- fml: ast_Identifier
247
- Z0Z_type_name: ast_Identifier
248
- Z0Z_asname: ast_Identifier | None = None
249
-
250
- listDatatypeConfigs = [
251
- DatatypeConfig(fml='DatatypeLeavesTotal', Z0Z_module='numba', Z0Z_type_name='uint8'),
252
- DatatypeConfig(fml='DatatypeElephino', Z0Z_module='numba', Z0Z_type_name='uint16'),
253
- DatatypeConfig(fml='DatatypeFoldsTotal', Z0Z_module='numba', Z0Z_type_name='uint64'),
254
- ]
255
-
256
- for datatypeConfig in listDatatypeConfigs:
257
- ingredientsModule.imports.addImportFrom_asStr(datatypeConfig.Z0Z_module, datatypeConfig.Z0Z_type_name)
258
- statement = Make.Assign(
259
- [Make.Name(datatypeConfig.fml, ast.Store())],
260
- Make.Name(datatypeConfig.Z0Z_type_name)
261
- )
262
- ingredientsModule.appendPrologue(statement=statement)
263
-
264
- ingredientsCount.imports.removeImportFromModule('mapFolding.theSSOT')
265
-
266
- listNumPyTypeConfigs = [
267
- DatatypeConfig(fml='Array1DLeavesTotal', Z0Z_module='numpy', Z0Z_type_name='uint8', Z0Z_asname='Array1DLeavesTotal'),
268
- DatatypeConfig(fml='Array1DElephino', Z0Z_module='numpy', Z0Z_type_name='uint16', Z0Z_asname='Array1DElephino'),
269
- DatatypeConfig(fml='Array3D', Z0Z_module='numpy', Z0Z_type_name='uint8', Z0Z_asname='Array3D'),
270
- ]
271
-
272
- for typeConfig in listNumPyTypeConfigs:
273
- ingredientsCount.imports.removeImportFrom(typeConfig.Z0Z_module, None, typeConfig.fml)
274
- ingredientsCount.imports.addImportFrom_asStr(typeConfig.Z0Z_module, typeConfig.Z0Z_type_name, typeConfig.Z0Z_asname)
275
-
276
- ingredientsCount.astFunctionDef.decorator_list = [] # TODO low-priority, handle this more elegantly
277
- # TODO when I add the function signature in numba style back to the decorator, the logic needs to handle `ProgressBarType:`
278
- ingredientsCount = decorateCallableWithNumba(ingredientsCount, spices.parametersNumba)
279
-
280
- ingredientsModule.appendIngredientsFunction(ingredientsCount)
281
- write_astModule(ingredientsModule, job.pathFilenameModule, job.packageIdentifier)
282
-
283
- """
284
- Overview
285
- - the code starts life in theDao.py, which has many optimizations;
286
- - `makeNumbaOptimizedFlow` increase optimization especially by using numba;
287
- - `makeJobNumba` increases optimization especially by limiting its capabilities to just one set of parameters
288
- - the synthesized module must run well as a standalone interpreted-Python script
289
- - the next major optimization step will (probably) be to use the module synthesized by `makeJobNumba` to compile a standalone executable
290
- - Nevertheless, at each major optimization step, the code is constantly being improved and optimized, so everything must be well organized (read: semantic) and able to handle a range of arbitrary upstream and not disrupt downstream transformations
291
-
292
- Necessary
293
- - Move the function's parameters to the function body,
294
- - initialize identifiers with their state types and values,
295
-
296
- Optimizations
297
- - replace static-valued identifiers with their values
298
- - narrowly focused imports
299
-
300
- Minutia
301
- - do not use `with` statement inside numba jitted code, except to use numba's obj mode
302
- """
303
-
304
- if __name__ == '__main__':
305
- mapShape = (1,46)
306
- state = makeInitializedComputationState(mapShape)
307
- # foldsTotalEstimated = getFoldsTotalKnown(state.mapShape) // state.leavesTotal
308
- # foldsTotalEstimated = dictionaryEstimates[state.mapShape] // state.leavesTotal
309
- foldsTotalEstimated = 0
310
- pathModule = PurePosixPath(The.pathPackage, 'jobs')
311
- pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
312
- aJob = RecipeJob(state, foldsTotalEstimated, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
313
- spices = SpicesJobNumba(useNumbaProgressBar=False, parametersNumba=parametersNumbaLight)
314
- # spices = SpicesJobNumba()
315
- makeJobNumba(aJob, spices)
@@ -1,202 +0,0 @@
1
- from concurrent.futures import Future as ConcurrentFuture, ProcessPoolExecutor
2
- from copy import deepcopy
3
- from mapFolding import ComputationState
4
- from mapFolding import Array1DElephino, Array1DFoldsTotal, Array1DLeavesTotal, Array3D, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal
5
- from numba import jit
6
-
7
- def countInitialize(state: ComputationState) -> ComputationState:
8
- while state.gap1ndex == 0:
9
- if state.leaf1ndex <= 1 or state.leafBelow[0] == 1:
10
- state.dimensionsUnconstrained = state.dimensionsTotal
11
- state.gap1ndexCeiling = state.gapRangeStart[state.leaf1ndex - 1]
12
- state.indexDimension = 0
13
- while state.indexDimension < state.dimensionsTotal:
14
- state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leaf1ndex]
15
- if state.leafConnectee == state.leaf1ndex:
16
- state.dimensionsUnconstrained -= 1
17
- else:
18
- while state.leafConnectee != state.leaf1ndex:
19
- state.gapsWhere[state.gap1ndexCeiling] = state.leafConnectee
20
- if state.countDimensionsGapped[state.leafConnectee] == 0:
21
- state.gap1ndexCeiling += 1
22
- state.countDimensionsGapped[state.leafConnectee] += 1
23
- state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leafBelow[state.leafConnectee]]
24
- state.indexDimension += 1
25
- if not state.dimensionsUnconstrained:
26
- state.indexLeaf = 0
27
- while state.indexLeaf < state.leaf1ndex:
28
- state.gapsWhere[state.gap1ndexCeiling] = state.indexLeaf
29
- state.gap1ndexCeiling += 1
30
- state.indexLeaf += 1
31
- state.indexMiniGap = state.gap1ndex
32
- while state.indexMiniGap < state.gap1ndexCeiling:
33
- state.gapsWhere[state.gap1ndex] = state.gapsWhere[state.indexMiniGap]
34
- if state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] == state.dimensionsUnconstrained:
35
- state.gap1ndex += 1
36
- state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] = 0
37
- state.indexMiniGap += 1
38
- if state.leaf1ndex > 0:
39
- state.gap1ndex -= 1
40
- state.leafAbove[state.leaf1ndex] = state.gapsWhere[state.gap1ndex]
41
- state.leafBelow[state.leaf1ndex] = state.leafBelow[state.leafAbove[state.leaf1ndex]]
42
- state.leafBelow[state.leafAbove[state.leaf1ndex]] = state.leaf1ndex
43
- state.leafAbove[state.leafBelow[state.leaf1ndex]] = state.leaf1ndex
44
- state.gapRangeStart[state.leaf1ndex] = state.gap1ndex
45
- state.leaf1ndex += 1
46
- return state
47
-
48
- @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)
49
- def countParallel(leavesTotal: DatatypeLeavesTotal, taskDivisions: DatatypeLeavesTotal, connectionGraph: Array3D, dimensionsTotal: DatatypeLeavesTotal, countDimensionsGapped: Array1DLeavesTotal, dimensionsUnconstrained: DatatypeLeavesTotal, gapRangeStart: Array1DElephino, gapsWhere: Array1DLeavesTotal, leafAbove: Array1DLeavesTotal, leafBelow: Array1DLeavesTotal, foldGroups: Array1DFoldsTotal, gap1ndex: DatatypeElephino, gap1ndexCeiling: DatatypeElephino, groupsOfFolds: DatatypeFoldsTotal, indexDimension: DatatypeLeavesTotal, indexMiniGap: DatatypeElephino, leaf1ndex: DatatypeLeavesTotal, leafConnectee: DatatypeLeavesTotal, taskIndex: DatatypeLeavesTotal) -> DatatypeFoldsTotal:
50
- while leaf1ndex > 0:
51
- if leaf1ndex <= 1 or leafBelow[0] == 1:
52
- if leaf1ndex > leavesTotal:
53
- groupsOfFolds += 1
54
- else:
55
- dimensionsUnconstrained = dimensionsTotal
56
- gap1ndexCeiling = gapRangeStart[leaf1ndex - 1]
57
- indexDimension = 0
58
- while indexDimension < dimensionsTotal:
59
- if connectionGraph[indexDimension, leaf1ndex, leaf1ndex] == leaf1ndex:
60
- dimensionsUnconstrained -= 1
61
- else:
62
- leafConnectee = connectionGraph[indexDimension, leaf1ndex, leaf1ndex]
63
- while leafConnectee != leaf1ndex:
64
- if leaf1ndex != taskDivisions or leafConnectee % taskDivisions == taskIndex:
65
- gapsWhere[gap1ndexCeiling] = leafConnectee
66
- if countDimensionsGapped[leafConnectee] == 0:
67
- gap1ndexCeiling += 1
68
- countDimensionsGapped[leafConnectee] += 1
69
- leafConnectee = connectionGraph[indexDimension, leaf1ndex, leafBelow[leafConnectee]]
70
- indexDimension += 1
71
- indexMiniGap = gap1ndex
72
- while indexMiniGap < gap1ndexCeiling:
73
- gapsWhere[gap1ndex] = gapsWhere[indexMiniGap]
74
- if countDimensionsGapped[gapsWhere[indexMiniGap]] == dimensionsUnconstrained:
75
- gap1ndex += 1
76
- countDimensionsGapped[gapsWhere[indexMiniGap]] = 0
77
- indexMiniGap += 1
78
- while leaf1ndex > 0 and gap1ndex == gapRangeStart[leaf1ndex - 1]:
79
- leaf1ndex -= 1
80
- leafBelow[leafAbove[leaf1ndex]] = leafBelow[leaf1ndex]
81
- leafAbove[leafBelow[leaf1ndex]] = leafAbove[leaf1ndex]
82
- if leaf1ndex > 0:
83
- gap1ndex -= 1
84
- leafAbove[leaf1ndex] = gapsWhere[gap1ndex]
85
- leafBelow[leaf1ndex] = leafBelow[leafAbove[leaf1ndex]]
86
- leafBelow[leafAbove[leaf1ndex]] = leaf1ndex
87
- leafAbove[leafBelow[leaf1ndex]] = leaf1ndex
88
- gapRangeStart[leaf1ndex] = gap1ndex
89
- leaf1ndex += 1
90
- foldGroups[taskIndex] = groupsOfFolds
91
- return groupsOfFolds
92
-
93
- @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)
94
- 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: DatatypeElephino, gap1ndexCeiling: DatatypeElephino, groupsOfFolds: DatatypeFoldsTotal, indexDimension: DatatypeLeavesTotal, indexLeaf: DatatypeLeavesTotal, indexMiniGap: DatatypeElephino, leaf1ndex: DatatypeLeavesTotal, leafConnectee: DatatypeLeavesTotal, taskIndex: DatatypeLeavesTotal) -> tuple[tuple[DatatypeLeavesTotal, ...], DatatypeLeavesTotal, DatatypeLeavesTotal, DatatypeElephino, Array3D, DatatypeLeavesTotal, Array1DLeavesTotal, DatatypeLeavesTotal, Array1DElephino, Array1DLeavesTotal, Array1DLeavesTotal, Array1DLeavesTotal, Array1DFoldsTotal, DatatypeFoldsTotal, DatatypeElephino, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal, DatatypeLeavesTotal, DatatypeElephino, DatatypeLeavesTotal, DatatypeLeavesTotal, DatatypeLeavesTotal]:
95
- while leaf1ndex > 0:
96
- if leaf1ndex <= 1 or leafBelow[0] == 1:
97
- if leaf1ndex > leavesTotal:
98
- groupsOfFolds += 1
99
- else:
100
- dimensionsUnconstrained = dimensionsTotal
101
- gap1ndexCeiling = gapRangeStart[leaf1ndex - 1]
102
- indexDimension = 0
103
- while indexDimension < dimensionsTotal:
104
- leafConnectee = connectionGraph[indexDimension, leaf1ndex, leaf1ndex]
105
- if leafConnectee == leaf1ndex:
106
- dimensionsUnconstrained -= 1
107
- else:
108
- while leafConnectee != leaf1ndex:
109
- gapsWhere[gap1ndexCeiling] = leafConnectee
110
- if countDimensionsGapped[leafConnectee] == 0:
111
- gap1ndexCeiling += 1
112
- countDimensionsGapped[leafConnectee] += 1
113
- leafConnectee = connectionGraph[indexDimension, leaf1ndex, leafBelow[leafConnectee]]
114
- indexDimension += 1
115
- indexMiniGap = gap1ndex
116
- while indexMiniGap < gap1ndexCeiling:
117
- gapsWhere[gap1ndex] = gapsWhere[indexMiniGap]
118
- if countDimensionsGapped[gapsWhere[indexMiniGap]] == dimensionsUnconstrained:
119
- gap1ndex += 1
120
- countDimensionsGapped[gapsWhere[indexMiniGap]] = 0
121
- indexMiniGap += 1
122
- while leaf1ndex > 0 and gap1ndex == gapRangeStart[leaf1ndex - 1]:
123
- leaf1ndex -= 1
124
- leafBelow[leafAbove[leaf1ndex]] = leafBelow[leaf1ndex]
125
- leafAbove[leafBelow[leaf1ndex]] = leafAbove[leaf1ndex]
126
- if leaf1ndex == 3 and groupsOfFolds:
127
- groupsOfFolds *= 2
128
- break
129
- if leaf1ndex > 0:
130
- gap1ndex -= 1
131
- leafAbove[leaf1ndex] = gapsWhere[gap1ndex]
132
- leafBelow[leaf1ndex] = leafBelow[leafAbove[leaf1ndex]]
133
- leafBelow[leafAbove[leaf1ndex]] = leaf1ndex
134
- leafAbove[leafBelow[leaf1ndex]] = leaf1ndex
135
- gapRangeStart[leaf1ndex] = gap1ndex
136
- leaf1ndex += 1
137
- foldGroups[taskIndex] = groupsOfFolds
138
- return (mapShape, leavesTotal, taskDivisions, concurrencyLimit, connectionGraph, dimensionsTotal, countDimensionsGapped, dimensionsUnconstrained, gapRangeStart, gapsWhere, leafAbove, leafBelow, foldGroups, foldsTotal, gap1ndex, gap1ndexCeiling, groupsOfFolds, indexDimension, indexLeaf, indexMiniGap, leaf1ndex, leafConnectee, taskIndex)
139
-
140
- def doTheNeedful(state: ComputationState) -> ComputationState:
141
- state = countInitialize(state)
142
- if state.taskDivisions > 0:
143
- dictionaryConcurrency: dict[int, ConcurrentFuture[ComputationState]] = {}
144
- stateParallel = deepcopy(state)
145
- with ProcessPoolExecutor(stateParallel.concurrencyLimit) as concurrencyManager:
146
- for indexSherpa in range(stateParallel.taskDivisions):
147
- state = deepcopy(stateParallel)
148
- state.taskIndex = indexSherpa
149
- mapShape: tuple[DatatypeLeavesTotal, ...] = state.mapShape
150
- leavesTotal: DatatypeLeavesTotal = state.leavesTotal
151
- taskDivisions: DatatypeLeavesTotal = state.taskDivisions
152
- concurrencyLimit: DatatypeElephino = state.concurrencyLimit
153
- connectionGraph: Array3D = state.connectionGraph
154
- dimensionsTotal: DatatypeLeavesTotal = state.dimensionsTotal
155
- countDimensionsGapped: Array1DLeavesTotal = state.countDimensionsGapped
156
- dimensionsUnconstrained: DatatypeLeavesTotal = state.dimensionsUnconstrained
157
- gapRangeStart: Array1DElephino = state.gapRangeStart
158
- gapsWhere: Array1DLeavesTotal = state.gapsWhere
159
- leafAbove: Array1DLeavesTotal = state.leafAbove
160
- leafBelow: Array1DLeavesTotal = state.leafBelow
161
- foldGroups: Array1DFoldsTotal = state.foldGroups
162
- foldsTotal: DatatypeFoldsTotal = state.foldsTotal
163
- gap1ndex: DatatypeElephino = state.gap1ndex
164
- gap1ndexCeiling: DatatypeElephino = state.gap1ndexCeiling
165
- groupsOfFolds: DatatypeFoldsTotal = state.groupsOfFolds
166
- indexDimension: DatatypeLeavesTotal = state.indexDimension
167
- indexLeaf: DatatypeLeavesTotal = state.indexLeaf
168
- indexMiniGap: DatatypeElephino = state.indexMiniGap
169
- leaf1ndex: DatatypeLeavesTotal = state.leaf1ndex
170
- leafConnectee: DatatypeLeavesTotal = state.leafConnectee
171
- taskIndex: DatatypeLeavesTotal = state.taskIndex
172
- dictionaryConcurrency[indexSherpa] = concurrencyManager.submit(countParallel, leavesTotal, taskDivisions, connectionGraph, dimensionsTotal, countDimensionsGapped, dimensionsUnconstrained, gapRangeStart, gapsWhere, leafAbove, leafBelow, foldGroups, gap1ndex, gap1ndexCeiling, groupsOfFolds, indexDimension, indexMiniGap, leaf1ndex, leafConnectee, taskIndex)
173
- for indexSherpa in range(stateParallel.taskDivisions):
174
- stateParallel.foldGroups[indexSherpa] = dictionaryConcurrency[indexSherpa].result()
175
- state = stateParallel
176
- else:
177
- mapShape: tuple[DatatypeLeavesTotal, ...] = state.mapShape
178
- leavesTotal: DatatypeLeavesTotal = state.leavesTotal
179
- taskDivisions: DatatypeLeavesTotal = state.taskDivisions
180
- concurrencyLimit: DatatypeElephino = state.concurrencyLimit
181
- connectionGraph: Array3D = state.connectionGraph
182
- dimensionsTotal: DatatypeLeavesTotal = state.dimensionsTotal
183
- countDimensionsGapped: Array1DLeavesTotal = state.countDimensionsGapped
184
- dimensionsUnconstrained: DatatypeLeavesTotal = state.dimensionsUnconstrained
185
- gapRangeStart: Array1DElephino = state.gapRangeStart
186
- gapsWhere: Array1DLeavesTotal = state.gapsWhere
187
- leafAbove: Array1DLeavesTotal = state.leafAbove
188
- leafBelow: Array1DLeavesTotal = state.leafBelow
189
- foldGroups: Array1DFoldsTotal = state.foldGroups
190
- foldsTotal: DatatypeFoldsTotal = state.foldsTotal
191
- gap1ndex: DatatypeElephino = state.gap1ndex
192
- gap1ndexCeiling: DatatypeElephino = state.gap1ndexCeiling
193
- groupsOfFolds: DatatypeFoldsTotal = state.groupsOfFolds
194
- indexDimension: DatatypeLeavesTotal = state.indexDimension
195
- indexLeaf: DatatypeLeavesTotal = state.indexLeaf
196
- indexMiniGap: DatatypeElephino = state.indexMiniGap
197
- leaf1ndex: DatatypeLeavesTotal = state.leaf1ndex
198
- leafConnectee: DatatypeLeavesTotal = state.leafConnectee
199
- taskIndex: DatatypeLeavesTotal = state.taskIndex
200
- 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)
201
- 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)
202
- return state