mapFolding 0.15.4__py3-none-any.whl → 0.16.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.
- easyRun/A000682.py +25 -0
- easyRun/A005316.py +21 -0
- easyRun/NOTcountingFolds.py +36 -0
- easyRun/__init__.py +0 -0
- easyRun/countFolds.py +41 -0
- easyRun/meanders.py +71 -0
- mapFolding/__init__.py +10 -55
- mapFolding/_dataPacking.py +68 -0
- mapFolding/_theSSOT.py +33 -36
- mapFolding/_theTypes.py +21 -4
- mapFolding/algorithms/daoOfMapFolding.py +1 -2
- mapFolding/algorithms/matrixMeanders.py +101 -348
- mapFolding/algorithms/matrixMeandersBeDry.py +264 -0
- mapFolding/algorithms/matrixMeandersNumPy.py +286 -0
- mapFolding/algorithms/matrixMeandersPandas.py +351 -0
- mapFolding/algorithms/oeisIDbyFormula.py +320 -76
- mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +92 -0
- mapFolding/basecamp.py +261 -113
- mapFolding/beDRY.py +2 -30
- mapFolding/dataBaskets.py +120 -4
- mapFolding/oeis.py +13 -33
- mapFolding/reference/A000682facts.py +1276 -0
- mapFolding/reference/A005316facts.py +985 -0
- mapFolding/reference/matrixMeandersAnalysis/__init__.py +1 -0
- mapFolding/reference/matrixMeandersAnalysis/prefixNotationNotes.py +15 -0
- mapFolding/reference/meandersDumpingGround/A005316JavaPort.py +1 -1
- mapFolding/reference/meandersDumpingGround/A005316imperative.py +1 -1
- mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +424 -0
- mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +54 -0
- mapFolding/someAssemblyRequired/A007822/__init__.py +0 -0
- mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +197 -0
- mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +74 -0
- mapFolding/someAssemblyRequired/RecipeJob.py +4 -4
- mapFolding/someAssemblyRequired/__init__.py +9 -2
- mapFolding/someAssemblyRequired/_toolIfThis.py +4 -3
- mapFolding/someAssemblyRequired/_toolkitContainers.py +8 -8
- mapFolding/someAssemblyRequired/infoBooth.py +27 -30
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +6 -5
- mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +6 -4
- mapFolding/someAssemblyRequired/makingModules_count.py +294 -0
- mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +117 -0
- mapFolding/someAssemblyRequired/mapFolding/__init__.py +0 -0
- mapFolding/someAssemblyRequired/mapFolding/makeMapFoldingModules.py +220 -0
- mapFolding/someAssemblyRequired/meanders/__init__.py +0 -0
- mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +64 -0
- mapFolding/someAssemblyRequired/toolkitMakeModules.py +152 -0
- mapFolding/someAssemblyRequired/toolkitNumba.py +1 -1
- mapFolding/someAssemblyRequired/transformationTools.py +1 -0
- mapFolding/syntheticModules/A007822/__init__.py +1 -0
- mapFolding/syntheticModules/{algorithmA007822.py → A007822/algorithm.py} +2 -3
- mapFolding/syntheticModules/{algorithmA007822Numba.py → A007822/algorithmNumba.py} +3 -6
- mapFolding/syntheticModules/A007822/asynchronous.py +148 -0
- mapFolding/syntheticModules/A007822/asynchronousAnnex.py +66 -0
- mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +85 -0
- mapFolding/syntheticModules/A007822/asynchronousNumba.py +52 -0
- mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +53 -0
- mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +47 -0
- mapFolding/syntheticModules/{initializeStateA007822.py → A007822/initializeState.py} +1 -2
- mapFolding/syntheticModules/{theorem2A007822.py → A007822/theorem2.py} +1 -2
- mapFolding/syntheticModules/{theorem2A007822Numba.py → A007822/theorem2Numba.py} +6 -4
- mapFolding/syntheticModules/{theorem2A007822Trimmed.py → A007822/theorem2Trimmed.py} +1 -2
- mapFolding/syntheticModules/countParallelNumba.py +5 -2
- mapFolding/syntheticModules/daoOfMapFoldingNumba.py +4 -2
- mapFolding/syntheticModules/dataPacking.py +4 -2
- mapFolding/syntheticModules/dataPackingA007822.py +92 -26
- mapFolding/syntheticModules/meanders/__init__.py +1 -0
- mapFolding/syntheticModules/meanders/bigInt.py +62 -0
- mapFolding/syntheticModules/theorem2Numba.py +3 -2
- mapFolding/tests/conftest.py +28 -13
- mapFolding/tests/test_computations.py +69 -62
- mapFolding/tests/test_oeis.py +6 -6
- mapFolding/zCuzDocStoopid/__init__.py +4 -0
- mapFolding/zCuzDocStoopid/makeDocstrings.py +68 -0
- mapfolding-0.16.1.dist-info/METADATA +99 -0
- mapfolding-0.16.1.dist-info/RECORD +114 -0
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/top_level.txt +1 -0
- mapFolding/someAssemblyRequired/A007822rawMaterials.py +0 -46
- mapFolding/someAssemblyRequired/makeAllModules.py +0 -764
- mapfolding-0.15.4.dist-info/METADATA +0 -78
- mapfolding-0.15.4.dist-info/RECORD +0 -78
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/WHEEL +0 -0
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""makeMeandersModules."""
|
|
2
|
+
from astToolkit import (
|
|
3
|
+
astModuleToIngredientsFunction, Be, Grab, identifierDotAttribute, Make, NodeChanger, NodeTourist, Then)
|
|
4
|
+
from hunterMakesPy import raiseIfNone
|
|
5
|
+
from mapFolding import packageSettings
|
|
6
|
+
from mapFolding.someAssemblyRequired import (
|
|
7
|
+
identifierCallableSourceDEFAULT, identifierCallableSourceDispatcherDEFAULT, IfThis, logicalPathInfixDEFAULT)
|
|
8
|
+
from mapFolding.someAssemblyRequired.toolkitMakeModules import (
|
|
9
|
+
findDataclass, getModule, getPathFilename, write_astModule)
|
|
10
|
+
from os import PathLike
|
|
11
|
+
from pathlib import PurePath
|
|
12
|
+
import ast
|
|
13
|
+
|
|
14
|
+
identifierDataclassNumPyHARDCODED = 'MatrixMeandersNumPyState'
|
|
15
|
+
|
|
16
|
+
logicalPathInfixMeanders: str = logicalPathInfixDEFAULT + '.meanders'
|
|
17
|
+
|
|
18
|
+
def makeCountBigInt(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
|
|
19
|
+
"""Make `countBigInt` module for meanders using `MatrixMeandersNumPyState` dataclass."""
|
|
20
|
+
identifierDataclassNumPy: str = identifierDataclassNumPyHARDCODED
|
|
21
|
+
_logicalPathDataclass, identifierDataclassOld, identifierDataclassInstance = findDataclass(astModuleToIngredientsFunction(astModule, raiseIfNone(sourceCallableDispatcher)))
|
|
22
|
+
|
|
23
|
+
NodeChanger(findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(identifierCallableSourceDEFAULT))
|
|
24
|
+
, doThat=Grab.nameAttribute(Then.replaceWith(raiseIfNone(callableIdentifier)))
|
|
25
|
+
).visit(astModule)
|
|
26
|
+
|
|
27
|
+
# Remove `doTheNeedful`
|
|
28
|
+
NodeChanger(Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableDispatcher)), Then.removeIt).visit(astModule)
|
|
29
|
+
|
|
30
|
+
# Change to `MatrixMeandersNumPyState`
|
|
31
|
+
NodeChanger(Be.Name.idIs(IfThis.isIdentifier(identifierDataclassOld))
|
|
32
|
+
, Grab.idAttribute(Then.replaceWith(identifierDataclassNumPy))
|
|
33
|
+
).visit(astModule)
|
|
34
|
+
|
|
35
|
+
NodeChanger(Be.alias.nameIs(IfThis.isIdentifier(identifierDataclassOld))
|
|
36
|
+
, Grab.nameAttribute(Then.replaceWith(identifierDataclassNumPy))
|
|
37
|
+
).visit(astModule)
|
|
38
|
+
|
|
39
|
+
# while (state.kOfMatrix > 0 and areIntegersWide(state)): # noqa: ERA001
|
|
40
|
+
Call_areIntegersWide: ast.Call = Make.Call(Make.Name('areIntegersWide'), listParameters=[Make.Name('state')])
|
|
41
|
+
astCompare: ast.Compare = raiseIfNone(NodeTourist(
|
|
42
|
+
findThis=IfThis.isAttributeNamespaceIdentifierGreaterThan0(identifierDataclassInstance, 'kOfMatrix')
|
|
43
|
+
, doThat=Then.extractIt
|
|
44
|
+
).captureLastMatch(astModule))
|
|
45
|
+
newTest: ast.expr = Make.And.join([astCompare, Call_areIntegersWide])
|
|
46
|
+
|
|
47
|
+
NodeChanger(IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0(identifierDataclassInstance, 'kOfMatrix')
|
|
48
|
+
, Grab.testAttribute(Then.replaceWith(newTest))
|
|
49
|
+
).visit(astModule)
|
|
50
|
+
|
|
51
|
+
# from mapFolding.algorithms.matrixMeandersBeDry import areIntegersWide # noqa: ERA001
|
|
52
|
+
astModule.body.insert(0, Make.ImportFrom('mapFolding.algorithms.matrixMeandersBeDry', list_alias=[Make.alias('areIntegersWide')]))
|
|
53
|
+
|
|
54
|
+
pathFilename = getPathFilename(logicalPathInfix=logicalPathInfix, moduleIdentifier=moduleIdentifier)
|
|
55
|
+
|
|
56
|
+
write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
|
|
57
|
+
|
|
58
|
+
return pathFilename
|
|
59
|
+
|
|
60
|
+
if __name__ == '__main__':
|
|
61
|
+
astModule = getModule(logicalPathInfix='algorithms', moduleIdentifier='matrixMeanders')
|
|
62
|
+
pathFilename = makeCountBigInt(astModule, 'bigInt', 'countBigInt', logicalPathInfixMeanders, identifierCallableSourceDispatcherDEFAULT)
|
|
63
|
+
|
|
64
|
+
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Map folding AST transformation system: Comprehensive transformation orchestration and module generation.
|
|
3
|
+
|
|
4
|
+
This module provides the orchestration layer of the map folding AST transformation system,
|
|
5
|
+
implementing comprehensive tools that coordinate all transformation stages to generate optimized
|
|
6
|
+
implementations with diverse computational strategies and performance characteristics. Building
|
|
7
|
+
upon the foundational pattern recognition, structural decomposition, core transformation tools,
|
|
8
|
+
Numba integration, and configuration management established in previous layers, this module
|
|
9
|
+
executes complete transformation processes that convert high-level dataclass-based algorithms
|
|
10
|
+
into specialized variants optimized for specific execution contexts.
|
|
11
|
+
|
|
12
|
+
The transformation orchestration addresses the full spectrum of optimization requirements for
|
|
13
|
+
map folding computational research through systematic application of the complete transformation
|
|
14
|
+
toolkit. The comprehensive approach decomposes dataclass parameters into primitive values for
|
|
15
|
+
Numba compatibility while removing object-oriented overhead and preserving computational logic,
|
|
16
|
+
generates concurrent execution variants using ProcessPoolExecutor with task division and result
|
|
17
|
+
aggregation, creates dedicated modules for counting variable setup with transformed loop conditions,
|
|
18
|
+
and provides theorem-specific transformations with configurable optimization levels including
|
|
19
|
+
trimmed variants and Numba-accelerated implementations.
|
|
20
|
+
|
|
21
|
+
The orchestration process operates through systematic AST manipulation that analyzes source
|
|
22
|
+
algorithms to extract dataclass dependencies, transforms data access patterns, applies performance
|
|
23
|
+
optimizations, and generates specialized modules with consistent naming conventions and filesystem
|
|
24
|
+
organization. The comprehensive transformation process coordinates pattern recognition for structural
|
|
25
|
+
analysis, dataclass decomposition for parameter optimization, function transformation for signature
|
|
26
|
+
adaptation, Numba integration for compilation optimization, and configuration management for
|
|
27
|
+
systematic generation control.
|
|
28
|
+
|
|
29
|
+
Generated modules maintain algorithmic correctness while providing significant performance
|
|
30
|
+
improvements through just-in-time compilation, parallel execution, and optimized data structures
|
|
31
|
+
tailored for specific computational requirements essential to large-scale map folding research.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from astToolkit import (
|
|
35
|
+
Be, DOT, identifierDotAttribute, IngredientsFunction, NodeTourist, parseLogicalPath2astModule, Then)
|
|
36
|
+
from autoflake import fix_code as autoflake_fix_code
|
|
37
|
+
from hunterMakesPy import raiseIfNone, writeStringToHere
|
|
38
|
+
from mapFolding import packageSettings
|
|
39
|
+
from mapFolding.someAssemblyRequired import identifierModuleSourceAlgorithmDEFAULT, logicalPathInfixDEFAULT
|
|
40
|
+
from os import PathLike
|
|
41
|
+
from pathlib import PurePath
|
|
42
|
+
from typing import Any
|
|
43
|
+
import ast
|
|
44
|
+
import io
|
|
45
|
+
import isort
|
|
46
|
+
|
|
47
|
+
def findDataclass(ingredientsFunction: IngredientsFunction) -> tuple[identifierDotAttribute, str, str]:
|
|
48
|
+
"""Dynamically extract information about a `dataclass`: the instance identifier, the identifier, and the logical path module.
|
|
49
|
+
|
|
50
|
+
Like many things in the "IngredientsFunction/IngredientsModule" ecosystem, this has specific requirements.
|
|
51
|
+
`ingredientsFunction` must have the dataclass as its first parameter. The `LedgerOfImports` in `ingredientsFunction` must have
|
|
52
|
+
the import information for the dataclass. If you are not using `IngredientsFunction`, you can still use this function to get
|
|
53
|
+
the information you want.
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from astToolkit import astModuleToIngredientsFunction
|
|
57
|
+
|
|
58
|
+
tupleInformation = findDataclass(astModuleToIngredientsFunction(astAST, identifier))
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
ingredientsFunction : IngredientsFunction
|
|
64
|
+
Function container with AST and import information.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
logicalPathDataclass : identifierDotAttribute
|
|
69
|
+
Logical path from which the `dataclass` is imported, which might not be the real source of the `dataclass`.
|
|
70
|
+
identifierDataclass : str
|
|
71
|
+
Identifier of the `dataclass`.
|
|
72
|
+
identifierDataclassInstance : str
|
|
73
|
+
Identifier of the `dataclass` instance.
|
|
74
|
+
"""
|
|
75
|
+
dataclassName: ast.expr = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.annotation)).captureLastMatch(ingredientsFunction.astFunctionDef))
|
|
76
|
+
identifierDataclass: str = raiseIfNone(NodeTourist(Be.Name, Then.extractIt(DOT.id)).captureLastMatch(dataclassName))
|
|
77
|
+
logicalPathDataclass = None
|
|
78
|
+
for moduleWithLogicalPath, listNameTuples in ingredientsFunction.imports._dictionaryImportFrom.items(): # noqa: SLF001
|
|
79
|
+
for nameTuple in listNameTuples:
|
|
80
|
+
if nameTuple[0] == identifierDataclass:
|
|
81
|
+
logicalPathDataclass = moduleWithLogicalPath
|
|
82
|
+
break
|
|
83
|
+
if logicalPathDataclass:
|
|
84
|
+
break
|
|
85
|
+
identifierDataclassInstance: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
|
|
86
|
+
return raiseIfNone(logicalPathDataclass), identifierDataclass, identifierDataclassInstance
|
|
87
|
+
|
|
88
|
+
def getLogicalPath(identifierPackage: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, *moduleIdentifier: str | None) -> identifierDotAttribute:
|
|
89
|
+
"""Get logical path from components."""
|
|
90
|
+
listLogicalPathParts: list[str] = []
|
|
91
|
+
if identifierPackage:
|
|
92
|
+
listLogicalPathParts.append(identifierPackage)
|
|
93
|
+
if logicalPathInfix:
|
|
94
|
+
listLogicalPathParts.append(logicalPathInfix)
|
|
95
|
+
if moduleIdentifier:
|
|
96
|
+
listLogicalPathParts.extend([module for module in moduleIdentifier if module is not None])
|
|
97
|
+
return '.'.join(listLogicalPathParts)
|
|
98
|
+
|
|
99
|
+
def getModule(identifierPackage: str | None = packageSettings.identifierPackage, logicalPathInfix: identifierDotAttribute | None = logicalPathInfixDEFAULT, moduleIdentifier: str | None = identifierModuleSourceAlgorithmDEFAULT) -> ast.Module:
|
|
100
|
+
"""Get Module."""
|
|
101
|
+
logicalPathSourceModule: identifierDotAttribute = getLogicalPath(identifierPackage, logicalPathInfix, moduleIdentifier)
|
|
102
|
+
astModule: ast.Module = parseLogicalPath2astModule(logicalPathSourceModule)
|
|
103
|
+
return astModule
|
|
104
|
+
|
|
105
|
+
def getPathFilename(pathRoot: PathLike[str] | PurePath | None = packageSettings.pathPackage, logicalPathInfix: PathLike[str] | PurePath | str | None = None, moduleIdentifier: str = '', fileExtension: str = packageSettings.fileExtension) -> PurePath:
|
|
106
|
+
"""Construct filesystem path from logical path.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
pathRoot : PathLike[str] | PurePath | None = packageSettings.pathPackage
|
|
111
|
+
Base directory for the package structure.
|
|
112
|
+
logicalPathInfix : PathLike[str] | PurePath | str | None = None
|
|
113
|
+
Subdirectory for organizing generated modules.
|
|
114
|
+
moduleIdentifier : str = ''
|
|
115
|
+
Name of the specific module file.
|
|
116
|
+
fileExtension : str = packageSettings.fileExtension
|
|
117
|
+
File extension for Python modules.
|
|
118
|
+
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
pathFilename : PurePath
|
|
122
|
+
Complete filesystem path for the generated module file.
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
pathFilename = PurePath(moduleIdentifier + fileExtension)
|
|
126
|
+
if logicalPathInfix:
|
|
127
|
+
pathFilename = PurePath(*(str(logicalPathInfix).split('.')), pathFilename)
|
|
128
|
+
if pathRoot:
|
|
129
|
+
pathFilename = PurePath(pathRoot, pathFilename)
|
|
130
|
+
return pathFilename
|
|
131
|
+
|
|
132
|
+
def write_astModule(astModule: ast.Module, pathFilename: PathLike[Any] | PurePath | io.TextIOBase, packageName: str | None = None) -> None:
|
|
133
|
+
"""Prototype that will likely be moved to astToolkit.
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
astModule : ast.Module
|
|
138
|
+
The AST module to be written to a file.
|
|
139
|
+
pathFilename : PathLike[Any] | PurePath
|
|
140
|
+
The file path where the module should be written.
|
|
141
|
+
packageName : str | None = None
|
|
142
|
+
Optional package name to preserve in import optimization.
|
|
143
|
+
"""
|
|
144
|
+
ast.fix_missing_locations(astModule)
|
|
145
|
+
pythonSource: str = ast.unparse(astModule)
|
|
146
|
+
autoflake_additional_imports: list[str] = []
|
|
147
|
+
if packageName:
|
|
148
|
+
autoflake_additional_imports.append(packageName)
|
|
149
|
+
pythonSource = autoflake_fix_code(pythonSource, autoflake_additional_imports, expand_star_imports=False, remove_all_unused_imports=True, remove_duplicate_keys = False, remove_unused_variables = False)
|
|
150
|
+
pythonSource = isort.code(pythonSource)
|
|
151
|
+
writeStringToHere(pythonSource + '\n', pathFilename)
|
|
152
|
+
|
|
@@ -136,7 +136,7 @@ While Numba offers multiple decorators (`@jit`, `@njit`, `@vectorize`), this too
|
|
|
136
136
|
on the general-purpose `@jit` decorator with configurable parameters for flexibility.
|
|
137
137
|
"""
|
|
138
138
|
|
|
139
|
-
def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, parametersNumba: ParametersNumba | None = None) -> IngredientsFunction:
|
|
139
|
+
def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, parametersNumba: ParametersNumba | None = None) -> IngredientsFunction:
|
|
140
140
|
"""Transform a Python function into a Numba-accelerated version with appropriate decorators.
|
|
141
141
|
|
|
142
142
|
(AI generated docstring)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Everything in this directory is synthesized by other modules in the package."""
|
|
@@ -18,8 +18,7 @@ def filterAsymmetricFolds(state: MapFoldingState) -> MapFoldingState:
|
|
|
18
18
|
ImaSymmetricFold = False
|
|
19
19
|
break
|
|
20
20
|
leafConnectee += 1
|
|
21
|
-
|
|
22
|
-
state.groupsOfFolds += 1
|
|
21
|
+
state.groupsOfFolds += ImaSymmetricFold
|
|
23
22
|
state.indexMiniGap += 1
|
|
24
23
|
return state
|
|
25
24
|
|
|
@@ -163,4 +162,4 @@ def count(state: MapFoldingState) -> MapFoldingState:
|
|
|
163
162
|
|
|
164
163
|
def doTheNeedful(state: MapFoldingState) -> MapFoldingState:
|
|
165
164
|
state = count(state)
|
|
166
|
-
return state
|
|
165
|
+
return state
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
from mapFolding.dataBaskets import
|
|
2
|
-
Array1DElephino, Array1DLeavesTotal, Array3DLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal,
|
|
3
|
-
MapFoldingState)
|
|
1
|
+
from mapFolding.dataBaskets import Array1DElephino, Array1DLeavesTotal, Array3DLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal, MapFoldingState
|
|
4
2
|
from numba import jit
|
|
5
3
|
|
|
6
4
|
@jit(cache=True, error_model='numpy', fastmath=True, forceinline=True)
|
|
@@ -25,8 +23,7 @@ def count(groupsOfFolds: DatatypeFoldsTotal, gap1ndex: DatatypeElephino, gap1nde
|
|
|
25
23
|
ImaSymmetricFold = False
|
|
26
24
|
break
|
|
27
25
|
leafConnectee += 1
|
|
28
|
-
|
|
29
|
-
groupsOfFolds += 1
|
|
26
|
+
groupsOfFolds += ImaSymmetricFold
|
|
30
27
|
indexMiniGap += 1
|
|
31
28
|
else:
|
|
32
29
|
dimensionsUnconstrained = dimensionsTotal
|
|
@@ -94,4 +91,4 @@ def doTheNeedful(state: MapFoldingState) -> MapFoldingState:
|
|
|
94
91
|
leavesTotal: DatatypeLeavesTotal = state.leavesTotal
|
|
95
92
|
groupsOfFolds, gap1ndex, gap1ndexCeiling, indexDimension, indexLeaf, indexMiniGap, leaf1ndex, leafConnectee, dimensionsUnconstrained, countDimensionsGapped, gapRangeStart, gapsWhere, leafAbove, leafBelow, leafComparison, connectionGraph, dimensionsTotal, leavesTotal = count(groupsOfFolds, gap1ndex, gap1ndexCeiling, indexDimension, indexLeaf, indexMiniGap, leaf1ndex, leafConnectee, dimensionsUnconstrained, countDimensionsGapped, gapRangeStart, gapsWhere, leafAbove, leafBelow, leafComparison, connectionGraph, dimensionsTotal, leavesTotal)
|
|
96
93
|
state = MapFoldingState(mapShape=mapShape, groupsOfFolds=groupsOfFolds, gap1ndex=gap1ndex, gap1ndexCeiling=gap1ndexCeiling, indexDimension=indexDimension, indexLeaf=indexLeaf, indexMiniGap=indexMiniGap, leaf1ndex=leaf1ndex, leafConnectee=leafConnectee, dimensionsUnconstrained=dimensionsUnconstrained, countDimensionsGapped=countDimensionsGapped, gapRangeStart=gapRangeStart, gapsWhere=gapsWhere, leafAbove=leafAbove, leafBelow=leafBelow, leafComparison=leafComparison)
|
|
97
|
-
return state
|
|
94
|
+
return state
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from mapFolding.dataBaskets import MapFoldingState
|
|
2
|
+
from mapFolding.syntheticModules.A007822.asynchronousAnnex import (
|
|
3
|
+
filterAsymmetricFolds, getAsymmetricFoldsTotal, initializeConcurrencyManager)
|
|
4
|
+
|
|
5
|
+
def activeLeafGreaterThan0(state: MapFoldingState) -> bool:
|
|
6
|
+
return state.leaf1ndex > 0
|
|
7
|
+
|
|
8
|
+
def activeLeafGreaterThanLeavesTotal(state: MapFoldingState) -> bool:
|
|
9
|
+
return state.leaf1ndex > state.leavesTotal
|
|
10
|
+
|
|
11
|
+
def activeLeafIsTheFirstLeaf(state: MapFoldingState) -> bool:
|
|
12
|
+
return state.leaf1ndex <= 1
|
|
13
|
+
|
|
14
|
+
def activeLeafIsUnconstrainedInAllDimensions(state: MapFoldingState) -> bool:
|
|
15
|
+
return not state.dimensionsUnconstrained
|
|
16
|
+
|
|
17
|
+
def activeLeafUnconstrainedInThisDimension(state: MapFoldingState) -> MapFoldingState:
|
|
18
|
+
state.dimensionsUnconstrained -= 1
|
|
19
|
+
return state
|
|
20
|
+
|
|
21
|
+
def filterCommonGaps(state: MapFoldingState) -> MapFoldingState:
|
|
22
|
+
state.gapsWhere[state.gap1ndex] = state.gapsWhere[state.indexMiniGap]
|
|
23
|
+
if state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] == state.dimensionsUnconstrained:
|
|
24
|
+
state = incrementActiveGap(state)
|
|
25
|
+
state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] = 0
|
|
26
|
+
return state
|
|
27
|
+
|
|
28
|
+
def gapAvailable(state: MapFoldingState) -> bool:
|
|
29
|
+
return state.leaf1ndex > 0
|
|
30
|
+
|
|
31
|
+
def incrementActiveGap(state: MapFoldingState) -> MapFoldingState:
|
|
32
|
+
state.gap1ndex += 1
|
|
33
|
+
return state
|
|
34
|
+
|
|
35
|
+
def incrementGap1ndexCeiling(state: MapFoldingState) -> MapFoldingState:
|
|
36
|
+
state.gap1ndexCeiling += 1
|
|
37
|
+
return state
|
|
38
|
+
|
|
39
|
+
def incrementIndexMiniGap(state: MapFoldingState) -> MapFoldingState:
|
|
40
|
+
state.indexMiniGap += 1
|
|
41
|
+
return state
|
|
42
|
+
|
|
43
|
+
def initializeIndexMiniGap(state: MapFoldingState) -> MapFoldingState:
|
|
44
|
+
state.indexMiniGap = state.gap1ndex
|
|
45
|
+
return state
|
|
46
|
+
|
|
47
|
+
def initializeVariablesToFindGaps(state: MapFoldingState) -> MapFoldingState:
|
|
48
|
+
state.dimensionsUnconstrained = state.dimensionsTotal
|
|
49
|
+
state.gap1ndexCeiling = state.gapRangeStart[state.leaf1ndex - 1]
|
|
50
|
+
state.indexDimension = 0
|
|
51
|
+
return state
|
|
52
|
+
|
|
53
|
+
def insertActiveLeaf(state: MapFoldingState) -> MapFoldingState:
|
|
54
|
+
state.indexLeaf = 0
|
|
55
|
+
while state.indexLeaf < state.leaf1ndex:
|
|
56
|
+
state.gapsWhere[state.gap1ndexCeiling] = state.indexLeaf
|
|
57
|
+
state.gap1ndexCeiling += 1
|
|
58
|
+
state.indexLeaf += 1
|
|
59
|
+
return state
|
|
60
|
+
|
|
61
|
+
def insertActiveLeafAtGap(state: MapFoldingState) -> MapFoldingState:
|
|
62
|
+
state.gap1ndex -= 1
|
|
63
|
+
state.leafAbove[state.leaf1ndex] = state.gapsWhere[state.gap1ndex]
|
|
64
|
+
state.leafBelow[state.leaf1ndex] = state.leafBelow[state.leafAbove[state.leaf1ndex]]
|
|
65
|
+
state.leafBelow[state.leafAbove[state.leaf1ndex]] = state.leaf1ndex
|
|
66
|
+
state.leafAbove[state.leafBelow[state.leaf1ndex]] = state.leaf1ndex
|
|
67
|
+
state.gapRangeStart[state.leaf1ndex] = state.gap1ndex
|
|
68
|
+
state.leaf1ndex += 1
|
|
69
|
+
return state
|
|
70
|
+
|
|
71
|
+
def leafBelowSentinelIs1(state: MapFoldingState) -> bool:
|
|
72
|
+
return state.leafBelow[0] == 1
|
|
73
|
+
|
|
74
|
+
def leafConnecteeIsActiveLeaf(state: MapFoldingState) -> bool:
|
|
75
|
+
return state.leafConnectee == state.leaf1ndex
|
|
76
|
+
|
|
77
|
+
def lookForGaps(state: MapFoldingState) -> MapFoldingState:
|
|
78
|
+
state.gapsWhere[state.gap1ndexCeiling] = state.leafConnectee
|
|
79
|
+
if state.countDimensionsGapped[state.leafConnectee] == 0:
|
|
80
|
+
state = incrementGap1ndexCeiling(state)
|
|
81
|
+
state.countDimensionsGapped[state.leafConnectee] += 1
|
|
82
|
+
return state
|
|
83
|
+
|
|
84
|
+
def lookupLeafConnecteeInConnectionGraph(state: MapFoldingState) -> MapFoldingState:
|
|
85
|
+
state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leaf1ndex]
|
|
86
|
+
return state
|
|
87
|
+
|
|
88
|
+
def loopingLeavesConnectedToActiveLeaf(state: MapFoldingState) -> bool:
|
|
89
|
+
return state.leafConnectee != state.leaf1ndex
|
|
90
|
+
|
|
91
|
+
def loopingThroughTheDimensions(state: MapFoldingState) -> bool:
|
|
92
|
+
return state.indexDimension < state.dimensionsTotal
|
|
93
|
+
|
|
94
|
+
def loopingToActiveGapCeiling(state: MapFoldingState) -> bool:
|
|
95
|
+
return state.indexMiniGap < state.gap1ndexCeiling
|
|
96
|
+
|
|
97
|
+
def noGapsHere(state: MapFoldingState) -> bool:
|
|
98
|
+
return state.leaf1ndex > 0 and state.gap1ndex == state.gapRangeStart[state.leaf1ndex - 1]
|
|
99
|
+
|
|
100
|
+
def tryAnotherLeafConnectee(state: MapFoldingState) -> MapFoldingState:
|
|
101
|
+
state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leafBelow[state.leafConnectee]]
|
|
102
|
+
return state
|
|
103
|
+
|
|
104
|
+
def tryNextDimension(state: MapFoldingState) -> MapFoldingState:
|
|
105
|
+
state.indexDimension += 1
|
|
106
|
+
return state
|
|
107
|
+
|
|
108
|
+
def undoLastLeafPlacement(state: MapFoldingState) -> MapFoldingState:
|
|
109
|
+
state.leaf1ndex -= 1
|
|
110
|
+
state.leafBelow[state.leafAbove[state.leaf1ndex]] = state.leafBelow[state.leaf1ndex]
|
|
111
|
+
state.leafAbove[state.leafBelow[state.leaf1ndex]] = state.leafAbove[state.leaf1ndex]
|
|
112
|
+
return state
|
|
113
|
+
|
|
114
|
+
def count(state: MapFoldingState) -> MapFoldingState:
|
|
115
|
+
while activeLeafGreaterThan0(state):
|
|
116
|
+
if activeLeafIsTheFirstLeaf(state) or leafBelowSentinelIs1(state):
|
|
117
|
+
if activeLeafGreaterThanLeavesTotal(state):
|
|
118
|
+
filterAsymmetricFolds(state.leafBelow)
|
|
119
|
+
else:
|
|
120
|
+
state = initializeVariablesToFindGaps(state)
|
|
121
|
+
while loopingThroughTheDimensions(state):
|
|
122
|
+
state = lookupLeafConnecteeInConnectionGraph(state)
|
|
123
|
+
if leafConnecteeIsActiveLeaf(state):
|
|
124
|
+
state = activeLeafUnconstrainedInThisDimension(state)
|
|
125
|
+
else:
|
|
126
|
+
while loopingLeavesConnectedToActiveLeaf(state):
|
|
127
|
+
state = lookForGaps(state)
|
|
128
|
+
state = tryAnotherLeafConnectee(state)
|
|
129
|
+
state = tryNextDimension(state)
|
|
130
|
+
if activeLeafIsUnconstrainedInAllDimensions(state):
|
|
131
|
+
state = insertActiveLeaf(state)
|
|
132
|
+
state = initializeIndexMiniGap(state)
|
|
133
|
+
while loopingToActiveGapCeiling(state):
|
|
134
|
+
state = filterCommonGaps(state)
|
|
135
|
+
state = incrementIndexMiniGap(state)
|
|
136
|
+
while noGapsHere(state):
|
|
137
|
+
state = undoLastLeafPlacement(state)
|
|
138
|
+
if gapAvailable(state):
|
|
139
|
+
state = insertActiveLeafAtGap(state)
|
|
140
|
+
else:
|
|
141
|
+
state.groupsOfFolds = getAsymmetricFoldsTotal()
|
|
142
|
+
state.groupsOfFolds = (state.groupsOfFolds + 1) // 2
|
|
143
|
+
return state
|
|
144
|
+
|
|
145
|
+
def doTheNeedful(state: MapFoldingState) -> MapFoldingState:
|
|
146
|
+
initializeConcurrencyManager()
|
|
147
|
+
state = count(state)
|
|
148
|
+
return state
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from concurrent.futures import Future as ConcurrentFuture, ThreadPoolExecutor
|
|
2
|
+
from hunterMakesPy import raiseIfNone
|
|
3
|
+
from mapFolding import Array1DLeavesTotal
|
|
4
|
+
from queue import Empty, Queue
|
|
5
|
+
from threading import Thread
|
|
6
|
+
import numpy
|
|
7
|
+
|
|
8
|
+
concurrencyManager = None
|
|
9
|
+
groupsOfFoldsTotal: int = 0
|
|
10
|
+
processingThread = None
|
|
11
|
+
queueFutures: Queue[ConcurrentFuture[int]] = Queue()
|
|
12
|
+
|
|
13
|
+
def initializeConcurrencyManager(maxWorkers: int | None=None, groupsOfFolds: int=0) -> None:
|
|
14
|
+
global concurrencyManager, queueFutures, groupsOfFoldsTotal, processingThread
|
|
15
|
+
concurrencyManager = ThreadPoolExecutor(max_workers=maxWorkers)
|
|
16
|
+
queueFutures = Queue()
|
|
17
|
+
groupsOfFoldsTotal = groupsOfFolds
|
|
18
|
+
processingThread = Thread(target=_processCompletedFutures)
|
|
19
|
+
processingThread.start()
|
|
20
|
+
|
|
21
|
+
def _processCompletedFutures() -> None:
|
|
22
|
+
global queueFutures, groupsOfFoldsTotal
|
|
23
|
+
while True:
|
|
24
|
+
try:
|
|
25
|
+
claimTicket: ConcurrentFuture[int] = queueFutures.get(timeout=1)
|
|
26
|
+
if claimTicket is None:
|
|
27
|
+
break
|
|
28
|
+
groupsOfFoldsTotal += claimTicket.result()
|
|
29
|
+
except Empty:
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
def _filterAsymmetricFolds(leafBelow: Array1DLeavesTotal) -> int:
|
|
33
|
+
groupsOfFolds = 0
|
|
34
|
+
leafComparison: Array1DLeavesTotal = numpy.zeros_like(leafBelow)
|
|
35
|
+
leavesTotal = leafBelow.size - 1
|
|
36
|
+
indexLeaf = 0
|
|
37
|
+
leafConnectee = 0
|
|
38
|
+
while leafConnectee < leavesTotal + 1:
|
|
39
|
+
leafNumber = int(leafBelow[indexLeaf])
|
|
40
|
+
leafComparison[leafConnectee] = (leafNumber - indexLeaf + leavesTotal) % leavesTotal
|
|
41
|
+
indexLeaf = leafNumber
|
|
42
|
+
leafConnectee += 1
|
|
43
|
+
indexInMiddle = leavesTotal // 2
|
|
44
|
+
indexDistance = 0
|
|
45
|
+
while indexDistance < leavesTotal + 1:
|
|
46
|
+
ImaSymmetricFold = True
|
|
47
|
+
leafConnectee = 0
|
|
48
|
+
while leafConnectee < indexInMiddle:
|
|
49
|
+
if leafComparison[(indexDistance + leafConnectee) % (leavesTotal + 1)] != leafComparison[(indexDistance + leavesTotal - 1 - leafConnectee) % (leavesTotal + 1)]:
|
|
50
|
+
ImaSymmetricFold = False
|
|
51
|
+
break
|
|
52
|
+
leafConnectee += 1
|
|
53
|
+
groupsOfFolds += ImaSymmetricFold
|
|
54
|
+
indexDistance += 1
|
|
55
|
+
return groupsOfFolds
|
|
56
|
+
|
|
57
|
+
def filterAsymmetricFolds(leafBelow: Array1DLeavesTotal) -> None:
|
|
58
|
+
global concurrencyManager, queueFutures
|
|
59
|
+
queueFutures.put_nowait(raiseIfNone(concurrencyManager).submit(_filterAsymmetricFolds, leafBelow.copy()))
|
|
60
|
+
|
|
61
|
+
def getAsymmetricFoldsTotal() -> int:
|
|
62
|
+
global concurrencyManager, queueFutures, processingThread
|
|
63
|
+
raiseIfNone(concurrencyManager).shutdown(wait=True)
|
|
64
|
+
queueFutures.put(None)
|
|
65
|
+
raiseIfNone(processingThread).join()
|
|
66
|
+
return groupsOfFoldsTotal
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from mapFolding import Array1DLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal
|
|
2
|
+
from queue import Queue
|
|
3
|
+
from threading import Lock, Thread
|
|
4
|
+
import numba
|
|
5
|
+
import numpy
|
|
6
|
+
|
|
7
|
+
listThreads: list[Thread] = []
|
|
8
|
+
queueFutures: Queue[Array1DLeavesTotal] = Queue()
|
|
9
|
+
groupsOfFoldsTotal: int = 0
|
|
10
|
+
groupsOfFoldsTotalLock = Lock()
|
|
11
|
+
sentinelStop = object()
|
|
12
|
+
|
|
13
|
+
def initializeConcurrencyManager(maxWorkers: int, groupsOfFolds: int=0) -> None:
|
|
14
|
+
global listThreads, groupsOfFoldsTotal, queueFutures # noqa: PLW0603
|
|
15
|
+
listThreads = []
|
|
16
|
+
queueFutures = Queue()
|
|
17
|
+
groupsOfFoldsTotal = groupsOfFolds
|
|
18
|
+
indexThread = 0
|
|
19
|
+
while indexThread < maxWorkers:
|
|
20
|
+
thread = Thread(target=_threadDoesSomething, name=f"thread{indexThread}", daemon=True)
|
|
21
|
+
thread.start()
|
|
22
|
+
listThreads.append(thread)
|
|
23
|
+
indexThread += 1
|
|
24
|
+
|
|
25
|
+
def _threadDoesSomething() -> None:
|
|
26
|
+
global groupsOfFoldsTotal # noqa: PLW0603
|
|
27
|
+
while True:
|
|
28
|
+
leafBelow = queueFutures.get()
|
|
29
|
+
if leafBelow is sentinelStop: # pyright: ignore[reportUnnecessaryComparison]
|
|
30
|
+
break
|
|
31
|
+
symmetricFolds = _filterAsymmetricFolds(leafBelow)
|
|
32
|
+
with groupsOfFoldsTotalLock:
|
|
33
|
+
groupsOfFoldsTotal += symmetricFolds
|
|
34
|
+
|
|
35
|
+
@numba.jit(cache=True, error_model='numpy', fastmath=True)
|
|
36
|
+
def _filterAsymmetricFolds(leafBelow: Array1DLeavesTotal) -> int:
|
|
37
|
+
groupsOfFolds = 0
|
|
38
|
+
leafComparison: Array1DLeavesTotal = numpy.zeros_like(leafBelow)
|
|
39
|
+
leavesTotal = leafBelow.size - 1
|
|
40
|
+
indexLeaf = 0
|
|
41
|
+
leafConnectee = 0
|
|
42
|
+
while leafConnectee < leavesTotal + 1:
|
|
43
|
+
leafNumber = int(leafBelow[indexLeaf])
|
|
44
|
+
leafComparison[leafConnectee] = (leafNumber - indexLeaf + leavesTotal) % leavesTotal
|
|
45
|
+
indexLeaf = leafNumber
|
|
46
|
+
leafConnectee += 1
|
|
47
|
+
indexInMiddle = leavesTotal // 2
|
|
48
|
+
indexDistance = 0
|
|
49
|
+
while indexDistance < leavesTotal + 1:
|
|
50
|
+
ImaSymmetricFold = True
|
|
51
|
+
leafConnectee = 0
|
|
52
|
+
while leafConnectee < indexInMiddle:
|
|
53
|
+
if leafComparison[(indexDistance + leafConnectee) % (leavesTotal + 1)] != leafComparison[(indexDistance + leavesTotal - 1 - leafConnectee) % (leavesTotal + 1)]:
|
|
54
|
+
ImaSymmetricFold = False
|
|
55
|
+
break
|
|
56
|
+
leafConnectee += 1
|
|
57
|
+
groupsOfFolds += ImaSymmetricFold
|
|
58
|
+
indexDistance += 1
|
|
59
|
+
return groupsOfFolds
|
|
60
|
+
|
|
61
|
+
def _go(leafBelow: Array1DLeavesTotal) -> None:
|
|
62
|
+
queueFutures.put_nowait(leafBelow.copy())
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# @numba.jit(numba.int64(numba.int64[:]), cache=True, error_model='numpy', fastmath=True)
|
|
66
|
+
def filterAsymmetricFolds(leafBelow: Array1DLeavesTotal) -> int: # non-blocking submission
|
|
67
|
+
# Must not block caller; enqueue for background processing
|
|
68
|
+
_go(leafBelow)
|
|
69
|
+
return 60 # GO
|
|
70
|
+
|
|
71
|
+
def _stop() -> DatatypeFoldsTotal:
|
|
72
|
+
global listThreads # noqa: PLW0602
|
|
73
|
+
# Signal all workers to stop after queue drained
|
|
74
|
+
for _thread in listThreads:
|
|
75
|
+
queueFutures.put(sentinelStop) # pyright: ignore[reportArgumentType]
|
|
76
|
+
for thread in listThreads:
|
|
77
|
+
thread.join()
|
|
78
|
+
return groupsOfFoldsTotal
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@numba.jit(numba.uint64(), cache=True, error_model='numpy', fastmath=True, forceobj=True)
|
|
83
|
+
def getAsymmetricFoldsTotal() -> DatatypeFoldsTotal:
|
|
84
|
+
total = _stop()
|
|
85
|
+
return total
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from mapFolding.dataBaskets import (
|
|
2
|
+
Array1DElephino, Array1DLeavesTotal, Array3DLeavesTotal, DatatypeElephino, DatatypeFoldsTotal, DatatypeLeavesTotal)
|
|
3
|
+
from mapFolding.syntheticModules.A007822.asynchronousAnnexNumba import filterAsymmetricFolds, getAsymmetricFoldsTotal
|
|
4
|
+
from mapFolding.syntheticModules.dataPackingA007822 import unRePackDataclassAsynchronous
|
|
5
|
+
from numba import jit
|
|
6
|
+
|
|
7
|
+
@unRePackDataclassAsynchronous
|
|
8
|
+
@jit(cache=True, error_model='numpy', fastmath=True, forceinline=True)
|
|
9
|
+
def count(groupsOfFolds: DatatypeFoldsTotal, gap1ndex: DatatypeElephino, gap1ndexCeiling: DatatypeElephino, indexDimension: DatatypeLeavesTotal, indexMiniGap: DatatypeElephino, leaf1ndex: DatatypeLeavesTotal, leafConnectee: DatatypeLeavesTotal, dimensionsUnconstrained: DatatypeLeavesTotal, countDimensionsGapped: Array1DLeavesTotal, gapRangeStart: Array1DElephino, gapsWhere: Array1DLeavesTotal, leafAbove: Array1DLeavesTotal, leafBelow: Array1DLeavesTotal, connectionGraph: Array3DLeavesTotal, dimensionsTotal: DatatypeLeavesTotal, leavesTotal: DatatypeLeavesTotal) -> tuple[DatatypeFoldsTotal, DatatypeElephino, DatatypeElephino, DatatypeLeavesTotal, DatatypeElephino, DatatypeLeavesTotal, DatatypeLeavesTotal, DatatypeLeavesTotal, Array1DLeavesTotal, Array1DElephino, Array1DLeavesTotal, Array1DLeavesTotal, Array1DLeavesTotal, Array3DLeavesTotal, DatatypeLeavesTotal, DatatypeLeavesTotal]:
|
|
10
|
+
while leaf1ndex > 4:
|
|
11
|
+
if leafBelow[0] == 1:
|
|
12
|
+
if leaf1ndex > leavesTotal:
|
|
13
|
+
filterAsymmetricFolds(leafBelow)
|
|
14
|
+
else:
|
|
15
|
+
dimensionsUnconstrained = dimensionsTotal
|
|
16
|
+
gap1ndexCeiling = gapRangeStart[leaf1ndex - 1]
|
|
17
|
+
indexDimension = 0
|
|
18
|
+
while indexDimension < dimensionsTotal:
|
|
19
|
+
leafConnectee = connectionGraph[indexDimension, leaf1ndex, leaf1ndex]
|
|
20
|
+
if leafConnectee == leaf1ndex:
|
|
21
|
+
dimensionsUnconstrained -= 1
|
|
22
|
+
else:
|
|
23
|
+
while leafConnectee != leaf1ndex:
|
|
24
|
+
gapsWhere[gap1ndexCeiling] = leafConnectee
|
|
25
|
+
if countDimensionsGapped[leafConnectee] == 0:
|
|
26
|
+
gap1ndexCeiling += 1
|
|
27
|
+
countDimensionsGapped[leafConnectee] += 1
|
|
28
|
+
leafConnectee = connectionGraph[indexDimension, leaf1ndex, leafBelow[leafConnectee]]
|
|
29
|
+
indexDimension += 1
|
|
30
|
+
indexMiniGap = gap1ndex
|
|
31
|
+
while indexMiniGap < gap1ndexCeiling:
|
|
32
|
+
gapsWhere[gap1ndex] = gapsWhere[indexMiniGap]
|
|
33
|
+
if countDimensionsGapped[gapsWhere[indexMiniGap]] == dimensionsUnconstrained:
|
|
34
|
+
gap1ndex += 1
|
|
35
|
+
countDimensionsGapped[gapsWhere[indexMiniGap]] = 0
|
|
36
|
+
indexMiniGap += 1
|
|
37
|
+
while gap1ndex == gapRangeStart[leaf1ndex - 1]:
|
|
38
|
+
leaf1ndex -= 1
|
|
39
|
+
leafBelow[leafAbove[leaf1ndex]] = leafBelow[leaf1ndex]
|
|
40
|
+
leafAbove[leafBelow[leaf1ndex]] = leafAbove[leaf1ndex]
|
|
41
|
+
gap1ndex -= 1
|
|
42
|
+
leafAbove[leaf1ndex] = gapsWhere[gap1ndex]
|
|
43
|
+
leafBelow[leaf1ndex] = leafBelow[leafAbove[leaf1ndex]]
|
|
44
|
+
leafBelow[leafAbove[leaf1ndex]] = leaf1ndex
|
|
45
|
+
leafAbove[leafBelow[leaf1ndex]] = leaf1ndex
|
|
46
|
+
gapRangeStart[leaf1ndex] = gap1ndex
|
|
47
|
+
leaf1ndex += 1
|
|
48
|
+
else:
|
|
49
|
+
groupsOfFolds = getAsymmetricFoldsTotal()
|
|
50
|
+
groupsOfFolds *= 2
|
|
51
|
+
groupsOfFolds = (groupsOfFolds + 1) // 2
|
|
52
|
+
return (groupsOfFolds, gap1ndex, gap1ndexCeiling, indexDimension, indexMiniGap, leaf1ndex, leafConnectee, dimensionsUnconstrained, countDimensionsGapped, gapRangeStart, gapsWhere, leafAbove, leafBelow, connectionGraph, dimensionsTotal, leavesTotal)
|