mapFolding 0.16.2__py3-none-any.whl → 0.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- easyRun/A000682.py +2 -2
- easyRun/NOTcountingFolds.py +16 -8
- easyRun/countFolds.py +9 -2
- easyRun/generateAllModules.py +14 -0
- easyRun/meanders.py +4 -4
- mapFolding/__init__.py +1 -0
- mapFolding/_theSSOT.py +3 -2
- mapFolding/_theTypes.py +3 -0
- mapFolding/algorithms/A000136constraintPropagation.py +95 -0
- mapFolding/algorithms/A000136elimination.py +163 -0
- mapFolding/algorithms/A000136eliminationParallel.py +77 -0
- mapFolding/algorithms/A086345.py +75 -0
- mapFolding/algorithms/matrixMeanders.py +59 -18
- mapFolding/algorithms/matrixMeandersNumPyndas.py +841 -0
- mapFolding/algorithms/oeisIDbyFormula.py +2 -2
- mapFolding/algorithms/symmetricFolds.py +35 -0
- mapFolding/basecamp.py +100 -153
- mapFolding/dataBaskets.py +142 -65
- mapFolding/filesystemToolkit.py +4 -32
- mapFolding/oeis.py +5 -12
- mapFolding/reference/A086345Wu.py +25 -0
- mapFolding/reference/irvineJavaPort.py +3 -3
- mapFolding/reference/matrixMeandersAnalysis/signatures.py +3 -0
- mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +1 -1
- mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +10 -45
- mapFolding/someAssemblyRequired/A007822/_asynchronousAnnex.py +51 -0
- mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +39 -196
- mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +57 -43
- mapFolding/someAssemblyRequired/RecipeJob.py +84 -34
- mapFolding/someAssemblyRequired/__init__.py +4 -8
- mapFolding/someAssemblyRequired/_toolkitContainers.py +38 -7
- mapFolding/someAssemblyRequired/infoBooth.py +41 -23
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +140 -164
- mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +63 -96
- mapFolding/someAssemblyRequired/makingModules_count.py +26 -30
- mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +10 -72
- mapFolding/someAssemblyRequired/{mapFolding → mapFoldingModules}/makeMapFoldingModules.py +30 -35
- mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +13 -11
- mapFolding/someAssemblyRequired/toolkitMakeModules.py +5 -31
- mapFolding/someAssemblyRequired/toolkitNumba.py +3 -2
- mapFolding/someAssemblyRequired/transformationTools.py +12 -15
- mapFolding/syntheticModules/A007822/algorithm.py +45 -50
- mapFolding/syntheticModules/A007822/asynchronous.py +92 -36
- mapFolding/syntheticModules/A007822/initializeState.py +19 -23
- mapFolding/syntheticModules/A007822/theorem2.py +20 -24
- mapFolding/syntheticModules/A007822/theorem2Numba.py +23 -25
- mapFolding/syntheticModules/A007822/theorem2Trimmed.py +19 -23
- mapFolding/syntheticModules/countParallelNumba.py +1 -2
- mapFolding/syntheticModules/daoOfMapFoldingNumba.py +5 -4
- mapFolding/syntheticModules/initializeState.py +1 -1
- mapFolding/syntheticModules/meanders/bigInt.py +59 -22
- mapFolding/syntheticModules/theorem2.py +1 -1
- mapFolding/syntheticModules/theorem2Numba.py +30 -9
- mapFolding/syntheticModules/theorem2Trimmed.py +2 -2
- mapFolding/tests/test_computations.py +29 -3
- {mapfolding-0.16.2.dist-info → mapfolding-0.17.0.dist-info}/METADATA +11 -8
- mapfolding-0.17.0.dist-info/RECORD +107 -0
- mapFolding/_dataPacking.py +0 -68
- mapFolding/algorithms/matrixMeandersBeDry.py +0 -182
- mapFolding/algorithms/matrixMeandersNumPy.py +0 -333
- mapFolding/algorithms/matrixMeandersPandas.py +0 -334
- mapFolding/reference/meandersDumpingGround/A005316intOptimized.py +0 -122
- mapFolding/reference/meandersDumpingGround/A005316optimized128bit.py +0 -79
- mapFolding/reference/meandersDumpingGround/matrixMeandersBaseline.py +0 -65
- mapFolding/reference/meandersDumpingGround/matrixMeandersBaselineAnnex.py +0 -84
- mapFolding/reference/meandersDumpingGround/matrixMeandersSimpleQueue.py +0 -90
- mapFolding/syntheticModules/A007822/algorithmNumba.py +0 -94
- mapFolding/syntheticModules/A007822/asynchronousAnnex.py +0 -66
- mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +0 -70
- mapFolding/syntheticModules/A007822/asynchronousNumba.py +0 -79
- mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +0 -65
- mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +0 -56
- mapFolding/syntheticModules/dataPacking.py +0 -26
- mapFolding/syntheticModules/dataPackingA007822.py +0 -92
- mapfolding-0.16.2.dist-info/RECORD +0 -115
- /mapFolding/someAssemblyRequired/{mapFolding → mapFoldingModules}/__init__.py +0 -0
- {mapfolding-0.16.2.dist-info → mapfolding-0.17.0.dist-info}/WHEEL +0 -0
- {mapfolding-0.16.2.dist-info → mapfolding-0.17.0.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.16.2.dist-info → mapfolding-0.17.0.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.16.2.dist-info → mapfolding-0.17.0.dist-info}/top_level.txt +0 -0
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
"""makeMapFoldingModules."""
|
|
2
2
|
from astToolkit import (
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Be, DOT, extractClassDef, Grab, hasDOTbody, identifierDotAttribute, Make, NodeChanger, NodeTourist,
|
|
4
|
+
parseLogicalPath2astModule, parsePathFilename2astModule, Then)
|
|
5
|
+
from astToolkit.containers import (
|
|
6
|
+
astModuleToIngredientsFunction, IngredientsFunction, IngredientsModule, LedgerOfImports)
|
|
6
7
|
from astToolkit.transformationTools import inlineFunctionDef, removeUnusedParameters, write_astModule
|
|
7
8
|
from hunterMakesPy import importLogicalPath2Identifier, raiseIfNone
|
|
8
9
|
from mapFolding import packageSettings
|
|
9
|
-
from mapFolding.someAssemblyRequired import
|
|
10
|
-
DeReConstructField2ast, identifierCallableSourceDEFAULT, identifierCallableSourceDispatcherDEFAULT, IfThis,
|
|
11
|
-
logicalPathInfixDEFAULT, ShatteredDataclass)
|
|
10
|
+
from mapFolding.someAssemblyRequired import default, DeReConstructField2ast, IfThis, ShatteredDataclass
|
|
12
11
|
from mapFolding.someAssemblyRequired.makingModules_count import (
|
|
13
12
|
makeMapFoldingNumba, makeTheorem2, numbaOnTheorem2, trimTheorem2)
|
|
14
|
-
from mapFolding.someAssemblyRequired.makingModules_doTheNeedful import makeInitializeState
|
|
15
|
-
from mapFolding.someAssemblyRequired.toolkitMakeModules import
|
|
13
|
+
from mapFolding.someAssemblyRequired.makingModules_doTheNeedful import makeInitializeState
|
|
14
|
+
from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename
|
|
16
15
|
from mapFolding.someAssemblyRequired.toolkitNumba import decorateCallableWithNumba, parametersNumbaLight
|
|
17
16
|
from mapFolding.someAssemblyRequired.transformationTools import (
|
|
18
17
|
removeDataclassFromFunction, shatter_dataclassesDOTdataclass, unpackDataclassCallFunctionRepackDataclass)
|
|
19
|
-
from os import PathLike
|
|
20
18
|
from pathlib import PurePath
|
|
21
19
|
from typing import Any, TYPE_CHECKING
|
|
22
20
|
import ast
|
|
@@ -25,7 +23,7 @@ import dataclasses
|
|
|
25
23
|
if TYPE_CHECKING:
|
|
26
24
|
from collections.abc import Sequence
|
|
27
25
|
|
|
28
|
-
def makeDaoOfMapFoldingParallelNumba(astModule: ast.Module,
|
|
26
|
+
def makeDaoOfMapFoldingParallelNumba(astModule: ast.Module, identifierModule: str, identifierCallable: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
|
|
29
27
|
"""Generate parallel implementation with concurrent execution and task division.
|
|
30
28
|
|
|
31
29
|
Parameters
|
|
@@ -47,11 +45,11 @@ def makeDaoOfMapFoldingParallelNumba(astModule: ast.Module, moduleIdentifier: st
|
|
|
47
45
|
Filesystem path where the parallel module was written.
|
|
48
46
|
|
|
49
47
|
"""
|
|
50
|
-
sourceCallableIdentifier =
|
|
51
|
-
if
|
|
52
|
-
|
|
48
|
+
sourceCallableIdentifier = default['function']['counting']
|
|
49
|
+
if identifierCallable is None:
|
|
50
|
+
identifierCallable = sourceCallableIdentifier
|
|
53
51
|
ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
|
|
54
|
-
ingredientsFunction.astFunctionDef.name =
|
|
52
|
+
ingredientsFunction.astFunctionDef.name = identifierCallable
|
|
55
53
|
|
|
56
54
|
dataclassName: ast.expr = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.annotation)).captureLastMatch(ingredientsFunction.astFunctionDef))
|
|
57
55
|
dataclassIdentifier: str = raiseIfNone(NodeTourist(Be.Name, Then.extractIt(DOT.id)).captureLastMatch(dataclassName))
|
|
@@ -69,10 +67,10 @@ def makeDaoOfMapFoldingParallelNumba(astModule: ast.Module, moduleIdentifier: st
|
|
|
69
67
|
dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
|
|
70
68
|
shatteredDataclass: ShatteredDataclass = shatter_dataclassesDOTdataclass(dataclassLogicalPathModule, dataclassIdentifier, dataclassInstanceIdentifier)
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
dataclassBaseFields: tuple[dataclasses.Field[Any], ...] = dataclasses.fields(importLogicalPath2Identifier(dataclassLogicalPathModule, dataclassIdentifier))
|
|
70
|
+
# START add the parallel state fields to the count function ------------------------------------------------
|
|
71
|
+
dataclassBaseFields: tuple[dataclasses.Field[Any], ...] = dataclasses.fields(importLogicalPath2Identifier(dataclassLogicalPathModule, dataclassIdentifier))
|
|
74
72
|
dataclassIdentifierParallel: identifierDotAttribute = 'Parallel' + dataclassIdentifier
|
|
75
|
-
dataclassFieldsParallel: tuple[dataclasses.Field[Any], ...] = dataclasses.fields(importLogicalPath2Identifier(dataclassLogicalPathModule, dataclassIdentifierParallel))
|
|
73
|
+
dataclassFieldsParallel: tuple[dataclasses.Field[Any], ...] = dataclasses.fields(importLogicalPath2Identifier(dataclassLogicalPathModule, dataclassIdentifierParallel))
|
|
76
74
|
onlyParallelFields: list[dataclasses.Field[Any]] = [field for field in dataclassFieldsParallel if field.name not in [fieldBase.name for fieldBase in dataclassBaseFields]]
|
|
77
75
|
|
|
78
76
|
Official_fieldOrder: list[str] = []
|
|
@@ -108,12 +106,12 @@ def makeDaoOfMapFoldingParallelNumba(astModule: ast.Module, moduleIdentifier: st
|
|
|
108
106
|
shatteredDataclassParallel.imports.update(shatteredDataclass.imports)
|
|
109
107
|
shatteredDataclassParallel.imports.removeImportFrom(dataclassLogicalPathModule, dataclassIdentifier)
|
|
110
108
|
|
|
111
|
-
|
|
109
|
+
# END add the parallel state fields to the count function ------------------------------------------------
|
|
112
110
|
|
|
113
111
|
ingredientsFunction.imports.update(shatteredDataclassParallel.imports)
|
|
114
112
|
ingredientsFunction: IngredientsFunction = removeDataclassFromFunction(ingredientsFunction, shatteredDataclassParallel)
|
|
115
113
|
|
|
116
|
-
|
|
114
|
+
# START add the parallel logic to the count function ------------------------------------------------
|
|
117
115
|
|
|
118
116
|
findThis = Be.While.testIs(Be.Compare.leftIs(IfThis.isNameIdentifier('leafConnectee')))
|
|
119
117
|
captureCountGapsCodeBlock: NodeTourist[ast.While, Sequence[ast.stmt]] = NodeTourist(findThis, doThat = Then.extractIt(DOT.body))
|
|
@@ -127,20 +125,20 @@ def makeDaoOfMapFoldingParallelNumba(astModule: ast.Module, moduleIdentifier: st
|
|
|
127
125
|
countGapsCodeBlockNew: list[ast.stmt] = [thisIsMyTaskIndexCodeBlock, countGapsCodeBlock[-1]]
|
|
128
126
|
NodeChanger[ast.While, hasDOTbody](findThis, doThat = Grab.bodyAttribute(Then.replaceWith(countGapsCodeBlockNew))).visit(ingredientsFunction.astFunctionDef)
|
|
129
127
|
|
|
130
|
-
|
|
128
|
+
# END add the parallel logic to the count function ------------------------------------------------
|
|
131
129
|
|
|
132
|
-
ingredientsFunction
|
|
130
|
+
ingredientsFunction.removeUnusedParameters()
|
|
133
131
|
|
|
134
132
|
ingredientsFunction = decorateCallableWithNumba(ingredientsFunction, parametersNumbaLight)
|
|
135
133
|
|
|
136
|
-
|
|
137
|
-
sourceCallableIdentifier =
|
|
134
|
+
# START unpack/repack the dataclass function ------------------------------------------------
|
|
135
|
+
sourceCallableIdentifier = default['function']['dispatcher']
|
|
138
136
|
|
|
139
137
|
unRepackDataclass: IngredientsFunction = astModuleToIngredientsFunction(astModule, sourceCallableIdentifier)
|
|
140
138
|
unRepackDataclass.astFunctionDef.name = 'unRepack' + dataclassIdentifierParallel
|
|
141
139
|
unRepackDataclass.imports.update(shatteredDataclassParallel.imports)
|
|
142
140
|
NodeChanger(
|
|
143
|
-
findThis = Be.arg.annotationIs(Be.Name.idIs(lambda thisAttribute: thisAttribute == dataclassIdentifier))
|
|
141
|
+
findThis = Be.arg.annotationIs(Be.Name.idIs(lambda thisAttribute: thisAttribute == dataclassIdentifier))
|
|
144
142
|
, doThat = Grab.annotationAttribute(Grab.idAttribute(Then.replaceWith(dataclassIdentifierParallel)))
|
|
145
143
|
).visit(unRepackDataclass.astFunctionDef)
|
|
146
144
|
unRepackDataclass.astFunctionDef.returns = Make.Name(dataclassIdentifierParallel)
|
|
@@ -187,34 +185,31 @@ def makeDaoOfMapFoldingParallelNumba(astModule: ast.Module, moduleIdentifier: st
|
|
|
187
185
|
)
|
|
188
186
|
ingredientsModule.removeImportFromModule('numpy')
|
|
189
187
|
|
|
190
|
-
pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix,
|
|
188
|
+
pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule)
|
|
191
189
|
|
|
192
|
-
write_astModule(
|
|
190
|
+
ingredientsModule.write_astModule(pathFilename, packageSettings.identifierPackage)
|
|
193
191
|
|
|
194
192
|
return pathFilename
|
|
195
193
|
|
|
196
194
|
def makeMapFoldingModules() -> None:
|
|
197
195
|
"""Make multidimensional map folding modules."""
|
|
198
196
|
astModule = getModule(logicalPathInfix='algorithms')
|
|
199
|
-
pathFilename: PurePath = makeMapFoldingNumba(astModule, 'daoOfMapFoldingNumba', None,
|
|
197
|
+
pathFilename: PurePath = makeMapFoldingNumba(astModule, 'daoOfMapFoldingNumba', None, default['logicalPath']['synthetic'], default['function']['dispatcher'])
|
|
200
198
|
|
|
201
199
|
astModule = getModule(logicalPathInfix='algorithms')
|
|
202
|
-
pathFilename = makeDaoOfMapFoldingParallelNumba(astModule, 'countParallelNumba', None,
|
|
200
|
+
pathFilename = makeDaoOfMapFoldingParallelNumba(astModule, 'countParallelNumba', None, default['logicalPath']['synthetic'], default['function']['dispatcher'])
|
|
203
201
|
|
|
204
202
|
astModule: ast.Module = getModule(logicalPathInfix='algorithms')
|
|
205
|
-
makeInitializeState(astModule, 'initializeState', '
|
|
203
|
+
makeInitializeState(astModule, default['module']['initializeState'], default['function']['initializeState'], default['logicalPath']['synthetic'])
|
|
206
204
|
|
|
207
205
|
astModule = getModule(logicalPathInfix='algorithms')
|
|
208
|
-
pathFilename = makeTheorem2(astModule, 'theorem2', None,
|
|
206
|
+
pathFilename = makeTheorem2(astModule, 'theorem2', None, default['logicalPath']['synthetic'], default['function']['dispatcher'])
|
|
209
207
|
|
|
210
208
|
astModule = parsePathFilename2astModule(pathFilename)
|
|
211
|
-
pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', None,
|
|
209
|
+
pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', None, default['logicalPath']['synthetic'], default['function']['dispatcher'])
|
|
212
210
|
|
|
213
211
|
astModule = parsePathFilename2astModule(pathFilename)
|
|
214
|
-
pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', None,
|
|
215
|
-
|
|
216
|
-
astImportFrom: ast.ImportFrom = Make.ImportFrom(getLogicalPath(packageSettings.identifierPackage, logicalPathInfixDEFAULT, 'theorem2Numba'), list_alias=[Make.alias(identifierCallableSourceDEFAULT)])
|
|
217
|
-
makeUnRePackDataclass(astImportFrom)
|
|
212
|
+
pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', None, default['logicalPath']['synthetic'], default['function']['dispatcher'])
|
|
218
213
|
|
|
219
214
|
if __name__ == '__main__':
|
|
220
215
|
makeMapFoldingModules()
|
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
"""makeMeandersModules."""
|
|
2
|
-
from astToolkit import
|
|
3
|
-
|
|
2
|
+
from astToolkit import Be, Grab, identifierDotAttribute, Make, NodeChanger, NodeTourist, Then
|
|
3
|
+
from astToolkit.containers import astModuleToIngredientsFunction
|
|
4
|
+
from astToolkit.transformationTools import write_astModule
|
|
4
5
|
from hunterMakesPy import raiseIfNone
|
|
5
6
|
from mapFolding import packageSettings
|
|
6
|
-
from mapFolding.someAssemblyRequired import
|
|
7
|
-
|
|
8
|
-
from mapFolding.someAssemblyRequired.toolkitMakeModules import (
|
|
9
|
-
findDataclass, getModule, getPathFilename, write_astModule)
|
|
7
|
+
from mapFolding.someAssemblyRequired import default, IfThis
|
|
8
|
+
from mapFolding.someAssemblyRequired.toolkitMakeModules import findDataclass, getModule, getPathFilename
|
|
10
9
|
from pathlib import PurePath
|
|
11
10
|
import ast
|
|
12
11
|
|
|
13
12
|
identifierDataclassNumPyHARDCODED = 'MatrixMeandersNumPyState'
|
|
14
13
|
|
|
15
|
-
logicalPathInfixMeanders: str =
|
|
14
|
+
logicalPathInfixMeanders: str = default['logicalPath']['synthetic'] + '.meanders'
|
|
16
15
|
|
|
17
16
|
def makeCountBigInt(astModule: ast.Module, identifierModule: str, callableIdentifier: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
|
|
18
17
|
"""Make `countBigInt` module for meanders using `MatrixMeandersNumPyState` dataclass."""
|
|
19
18
|
identifierDataclassNumPy: str = identifierDataclassNumPyHARDCODED
|
|
20
19
|
_logicalPathDataclass, identifierDataclassOld, identifierDataclassInstance = findDataclass(astModuleToIngredientsFunction(astModule, raiseIfNone(sourceCallableDispatcher)))
|
|
21
20
|
|
|
22
|
-
NodeChanger(findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(
|
|
21
|
+
NodeChanger(findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(default['function']['counting']))
|
|
23
22
|
, doThat=Grab.nameAttribute(Then.replaceWith(raiseIfNone(callableIdentifier)))
|
|
24
23
|
).visit(astModule)
|
|
25
24
|
|
|
@@ -52,12 +51,15 @@ def makeCountBigInt(astModule: ast.Module, identifierModule: str, callableIdenti
|
|
|
52
51
|
|
|
53
52
|
pathFilename: PurePath = getPathFilename(logicalPathInfix=logicalPathInfix, identifierModule=identifierModule)
|
|
54
53
|
|
|
55
|
-
write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
|
|
54
|
+
write_astModule(astModule, pathFilename, identifierPackage=packageSettings.identifierPackage)
|
|
56
55
|
|
|
57
56
|
return pathFilename
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
def makeMeandersModules() -> None:
|
|
59
|
+
"""Make meanders modules."""
|
|
60
60
|
astModule: ast.Module = getModule(logicalPathInfix='algorithms', identifierModule='matrixMeanders')
|
|
61
|
-
pathFilename: PurePath = makeCountBigInt(astModule, 'bigInt', 'countBigInt', logicalPathInfixMeanders,
|
|
61
|
+
pathFilename: PurePath = makeCountBigInt(astModule, 'bigInt', 'countBigInt', logicalPathInfixMeanders, default['function']['dispatcher']) # pyright: ignore[reportUnusedVariable] # noqa: F841
|
|
62
62
|
|
|
63
|
+
if __name__ == '__main__':
|
|
64
|
+
makeMeandersModules()
|
|
63
65
|
|
|
@@ -31,18 +31,14 @@ improvements through just-in-time compilation, parallel execution, and optimized
|
|
|
31
31
|
tailored for specific computational requirements essential to large-scale map folding research.
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
|
-
from astToolkit import
|
|
35
|
-
|
|
36
|
-
from
|
|
37
|
-
from hunterMakesPy import raiseIfNone, writeStringToHere
|
|
34
|
+
from astToolkit import Be, DOT, identifierDotAttribute, NodeTourist, parseLogicalPath2astModule, Then
|
|
35
|
+
from astToolkit.containers import IngredientsFunction
|
|
36
|
+
from hunterMakesPy import raiseIfNone
|
|
38
37
|
from mapFolding import packageSettings
|
|
39
|
-
from mapFolding.someAssemblyRequired import
|
|
38
|
+
from mapFolding.someAssemblyRequired import default
|
|
40
39
|
from os import PathLike
|
|
41
40
|
from pathlib import PurePath
|
|
42
|
-
from typing import Any
|
|
43
41
|
import ast
|
|
44
|
-
import io
|
|
45
|
-
import isort
|
|
46
42
|
|
|
47
43
|
def findDataclass(ingredientsFunction: IngredientsFunction) -> tuple[identifierDotAttribute, str, str]:
|
|
48
44
|
"""Dynamically extract information about a `dataclass`: the instance identifier, the identifier, and the logical path module.
|
|
@@ -96,7 +92,7 @@ def getLogicalPath(identifierPackage: str | None = None, logicalPathInfix: ident
|
|
|
96
92
|
listLogicalPathParts.extend([module for module in identifierModule if module is not None])
|
|
97
93
|
return '.'.join(listLogicalPathParts)
|
|
98
94
|
|
|
99
|
-
def getModule(identifierPackage: str | None = packageSettings.identifierPackage, logicalPathInfix: identifierDotAttribute | None =
|
|
95
|
+
def getModule(identifierPackage: str | None = packageSettings.identifierPackage, logicalPathInfix: identifierDotAttribute | None = default['logicalPath']['synthetic'], identifierModule: str | None = default['module']['algorithm']) -> ast.Module:
|
|
100
96
|
"""Get Module."""
|
|
101
97
|
logicalPathSourceModule: identifierDotAttribute = getLogicalPath(identifierPackage, logicalPathInfix, identifierModule)
|
|
102
98
|
astModule: ast.Module = parseLogicalPath2astModule(logicalPathSourceModule)
|
|
@@ -128,25 +124,3 @@ def getPathFilename(pathRoot: PathLike[str] | PurePath | None = packageSettings.
|
|
|
128
124
|
if pathRoot:
|
|
129
125
|
pathFilename = PurePath(pathRoot, pathFilename)
|
|
130
126
|
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
|
-
|
|
@@ -25,7 +25,8 @@ computational modules. The compilation layer integrates seamlessly with the broa
|
|
|
25
25
|
system to produce standalone modules optimized for specific map dimensions and computational contexts.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
from astToolkit import identifierDotAttribute,
|
|
28
|
+
from astToolkit import identifierDotAttribute, Make
|
|
29
|
+
from astToolkit.containers import IngredientsFunction
|
|
29
30
|
from collections.abc import Callable
|
|
30
31
|
from numba.core.compiler import CompilerBase as numbaCompilerBase
|
|
31
32
|
from typing import Any, Final, NotRequired, TYPE_CHECKING, TypedDict
|
|
@@ -281,7 +282,7 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
|
|
|
281
282
|
return ingredientsFunction
|
|
282
283
|
|
|
283
284
|
@dataclasses.dataclass
|
|
284
|
-
class SpicesJobNumba:
|
|
285
|
+
class SpicesJobNumba: # slots?
|
|
285
286
|
"""Configuration container for Numba-specific job processing options.
|
|
286
287
|
|
|
287
288
|
(AI generated docstring)
|
|
@@ -25,9 +25,8 @@ This approach enables seamless integration between high-level dataclass-based in
|
|
|
25
25
|
low-level optimized implementations, maintaining code clarity while achieving performance gains
|
|
26
26
|
through specialized compilation paths essential for computationally intensive map folding research.
|
|
27
27
|
"""
|
|
28
|
-
|
|
29
|
-
from astToolkit import
|
|
30
|
-
Be, extractClassDef, identifierDotAttribute, IngredientsFunction, Make, NodeChanger, parseLogicalPath2astModule, Then)
|
|
28
|
+
from astToolkit import Be, extractClassDef, identifierDotAttribute, Make, NodeChanger, parseLogicalPath2astModule, Then
|
|
29
|
+
from astToolkit.containers import IngredientsFunction, LedgerOfImports
|
|
31
30
|
from astToolkit.transformationTools import unparseFindReplace
|
|
32
31
|
from hunterMakesPy import importLogicalPath2Identifier
|
|
33
32
|
from mapFolding.someAssemblyRequired import DeReConstructField2ast, IfThis, ShatteredDataclass
|
|
@@ -79,10 +78,10 @@ def shatter_dataclassesDOTdataclass(logicalPathDataclass: identifierDotAttribute
|
|
|
79
78
|
|
|
80
79
|
dataclassClassDef: ast.ClassDef | None = extractClassDef(parseLogicalPath2astModule(logicalPathDataclass), identifierDataclass)
|
|
81
80
|
if not dataclassClassDef:
|
|
82
|
-
message = f"I could not find `{identifierDataclass = }` in `{logicalPathDataclass = }`."
|
|
81
|
+
message: str = f"I could not find `{identifierDataclass = }` in `{logicalPathDataclass = }`."
|
|
83
82
|
raise ValueError(message)
|
|
84
83
|
|
|
85
|
-
countingVariable = None
|
|
84
|
+
countingVariable: str | None = None
|
|
86
85
|
for aField in dataclasses.fields(importLogicalPath2Identifier(logicalPathDataclass, identifierDataclass)): # pyright: ignore [reportArgumentType]
|
|
87
86
|
Official_fieldOrder.append(aField.name)
|
|
88
87
|
dictionaryDeReConstruction[aField.name] = DeReConstructField2ast(logicalPathDataclass, dataclassClassDef, identifierDataclassInstance, aField)
|
|
@@ -99,6 +98,7 @@ def shatter_dataclassesDOTdataclass(logicalPathDataclass: identifierDotAttribute
|
|
|
99
98
|
Z0Z_field2AnnAssign={dictionaryDeReConstruction[field].name: dictionaryDeReConstruction[field].Z0Z_hack for field in Official_fieldOrder},
|
|
100
99
|
list_argAnnotated4ArgumentsSpecification=[dictionaryDeReConstruction[field].ast_argAnnotated for field in Official_fieldOrder],
|
|
101
100
|
list_keyword_field__field4init=[dictionaryDeReConstruction[field].ast_keyword_field__field for field in Official_fieldOrder if dictionaryDeReConstruction[field].init],
|
|
101
|
+
listIdentifiersStaticScalars=[dictionaryDeReConstruction[field].name for field in Official_fieldOrder if (dictionaryDeReConstruction[field].Z0Z_hack[1] == 'scalar' and not dictionaryDeReConstruction[field].init)],
|
|
102
102
|
listAnnotations=[dictionaryDeReConstruction[field].astAnnotation for field in Official_fieldOrder],
|
|
103
103
|
listName4Parameters=[dictionaryDeReConstruction[field].astName for field in Official_fieldOrder],
|
|
104
104
|
listUnpack=[Make.AnnAssign(dictionaryDeReConstruction[field].astName, dictionaryDeReConstruction[field].astAnnotation, dictionaryDeReConstruction[field].ast_nameDOTname) for field in Official_fieldOrder],
|
|
@@ -145,12 +145,11 @@ def removeDataclassFromFunction(ingredientsTarget: IngredientsFunction, shattere
|
|
|
145
145
|
"""
|
|
146
146
|
ingredientsTarget.astFunctionDef.args = Make.arguments(list_arg=shatteredDataclass.list_argAnnotated4ArgumentsSpecification)
|
|
147
147
|
ingredientsTarget.astFunctionDef.returns = shatteredDataclass.signatureReturnAnnotation
|
|
148
|
-
|
|
149
|
-
changeReturnCallable.visit(ingredientsTarget.astFunctionDef)
|
|
148
|
+
NodeChanger(Be.Return, Then.replaceWith(Make.Return(shatteredDataclass.fragments4AssignmentOrParameters))).visit(ingredientsTarget.astFunctionDef)
|
|
150
149
|
ingredientsTarget.astFunctionDef = unparseFindReplace(ingredientsTarget.astFunctionDef, shatteredDataclass.map_stateDOTfield2Name)
|
|
151
150
|
return ingredientsTarget
|
|
152
151
|
|
|
153
|
-
def unpackDataclassCallFunctionRepackDataclass(ingredientsCaller: IngredientsFunction,
|
|
152
|
+
def unpackDataclassCallFunctionRepackDataclass(ingredientsCaller: IngredientsFunction, identifierCallee: str, shatteredDataclass: ShatteredDataclass) -> IngredientsFunction:
|
|
154
153
|
"""Transform a caller function to interface with a dataclass-free target function.
|
|
155
154
|
|
|
156
155
|
(AI generated docstring)
|
|
@@ -184,12 +183,10 @@ def unpackDataclassCallFunctionRepackDataclass(ingredientsCaller: IngredientsFun
|
|
|
184
183
|
The modified caller function with appropriate unpacking and repacking around the target call.
|
|
185
184
|
|
|
186
185
|
"""
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
replaceAssignTargetCallable.visit(ingredientsCaller.astFunctionDef)
|
|
192
|
-
unpack4targetCallable.visit(ingredientsCaller.astFunctionDef)
|
|
193
|
-
repack4targetCallable.visit(ingredientsCaller.astFunctionDef)
|
|
186
|
+
AssignAndCall: ast.Assign = Make.Assign([shatteredDataclass.fragments4AssignmentOrParameters], value=Make.Call(Make.Name(identifierCallee), shatteredDataclass.listName4Parameters))
|
|
187
|
+
NodeChanger(Be.Assign.valueIs(IfThis.isCallIdentifier(identifierCallee)), Then.replaceWith(AssignAndCall)).visit(ingredientsCaller.astFunctionDef)
|
|
188
|
+
NodeChanger(Be.Assign.valueIs(IfThis.isCallIdentifier(identifierCallee)), Then.insertThisAbove(shatteredDataclass.listUnpack)).visit(ingredientsCaller.astFunctionDef)
|
|
189
|
+
NodeChanger(Be.Assign.valueIs(IfThis.isCallIdentifier(identifierCallee)), Then.insertThisBelow([shatteredDataclass.repack])).visit(ingredientsCaller.astFunctionDef)
|
|
194
190
|
return ingredientsCaller
|
|
195
191
|
|
|
192
|
+
|
|
@@ -1,77 +1,72 @@
|
|
|
1
|
-
from mapFolding.dataBaskets import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
state.
|
|
6
|
-
leafConnectee =
|
|
7
|
-
while leafConnectee < state.leavesTotal + 1:
|
|
8
|
-
|
|
9
|
-
state.leafComparison[leafConnectee] = (
|
|
10
|
-
state.indexLeaf =
|
|
11
|
-
leafConnectee += 1
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
while leafConnectee < indexInMiddle:
|
|
18
|
-
if state.leafComparison[(state.indexMiniGap + leafConnectee) % (state.leavesTotal + 1)] != state.leafComparison[(state.indexMiniGap + state.leavesTotal - 1 - leafConnectee) % (state.leavesTotal + 1)]:
|
|
19
|
-
ImaSymmetricFold = False
|
|
1
|
+
from mapFolding.dataBaskets import SymmetricFoldsState
|
|
2
|
+
|
|
3
|
+
def filterAsymmetricFolds(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
4
|
+
state.indexLeaf = 1
|
|
5
|
+
state.leafComparison[0] = 1
|
|
6
|
+
state.leafConnectee = 1
|
|
7
|
+
while state.leafConnectee < state.leavesTotal + 1:
|
|
8
|
+
state.indexMiniGap = state.leafBelow[state.indexLeaf]
|
|
9
|
+
state.leafComparison[state.leafConnectee] = (state.indexMiniGap - state.indexLeaf + state.leavesTotal) % state.leavesTotal
|
|
10
|
+
state.indexLeaf = state.indexMiniGap
|
|
11
|
+
state.leafConnectee += 1
|
|
12
|
+
for listTuples in state.indices:
|
|
13
|
+
state.leafConnectee = 1
|
|
14
|
+
for indexLeft, indexRight in listTuples:
|
|
15
|
+
if state.leafComparison[indexLeft] != state.leafComparison[indexRight]:
|
|
16
|
+
state.leafConnectee = 0
|
|
20
17
|
break
|
|
21
|
-
|
|
22
|
-
state.groupsOfFolds += ImaSymmetricFold
|
|
23
|
-
state.indexMiniGap += 1
|
|
18
|
+
state.symmetricFolds += state.leafConnectee
|
|
24
19
|
return state
|
|
25
20
|
|
|
26
|
-
def activeLeafGreaterThan0(state:
|
|
21
|
+
def activeLeafGreaterThan0(state: SymmetricFoldsState) -> bool:
|
|
27
22
|
return state.leaf1ndex > 0
|
|
28
23
|
|
|
29
|
-
def activeLeafGreaterThanLeavesTotal(state:
|
|
24
|
+
def activeLeafGreaterThanLeavesTotal(state: SymmetricFoldsState) -> bool:
|
|
30
25
|
return state.leaf1ndex > state.leavesTotal
|
|
31
26
|
|
|
32
|
-
def activeLeafIsTheFirstLeaf(state:
|
|
27
|
+
def activeLeafIsTheFirstLeaf(state: SymmetricFoldsState) -> bool:
|
|
33
28
|
return state.leaf1ndex <= 1
|
|
34
29
|
|
|
35
|
-
def activeLeafIsUnconstrainedInAllDimensions(state:
|
|
30
|
+
def activeLeafIsUnconstrainedInAllDimensions(state: SymmetricFoldsState) -> bool:
|
|
36
31
|
return not state.dimensionsUnconstrained
|
|
37
32
|
|
|
38
|
-
def activeLeafUnconstrainedInThisDimension(state:
|
|
33
|
+
def activeLeafUnconstrainedInThisDimension(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
39
34
|
state.dimensionsUnconstrained -= 1
|
|
40
35
|
return state
|
|
41
36
|
|
|
42
|
-
def filterCommonGaps(state:
|
|
37
|
+
def filterCommonGaps(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
43
38
|
state.gapsWhere[state.gap1ndex] = state.gapsWhere[state.indexMiniGap]
|
|
44
39
|
if state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] == state.dimensionsUnconstrained:
|
|
45
40
|
state = incrementActiveGap(state)
|
|
46
41
|
state.countDimensionsGapped[state.gapsWhere[state.indexMiniGap]] = 0
|
|
47
42
|
return state
|
|
48
43
|
|
|
49
|
-
def gapAvailable(state:
|
|
44
|
+
def gapAvailable(state: SymmetricFoldsState) -> bool:
|
|
50
45
|
return state.leaf1ndex > 0
|
|
51
46
|
|
|
52
|
-
def incrementActiveGap(state:
|
|
47
|
+
def incrementActiveGap(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
53
48
|
state.gap1ndex += 1
|
|
54
49
|
return state
|
|
55
50
|
|
|
56
|
-
def incrementGap1ndexCeiling(state:
|
|
51
|
+
def incrementGap1ndexCeiling(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
57
52
|
state.gap1ndexCeiling += 1
|
|
58
53
|
return state
|
|
59
54
|
|
|
60
|
-
def incrementIndexMiniGap(state:
|
|
55
|
+
def incrementIndexMiniGap(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
61
56
|
state.indexMiniGap += 1
|
|
62
57
|
return state
|
|
63
58
|
|
|
64
|
-
def initializeIndexMiniGap(state:
|
|
59
|
+
def initializeIndexMiniGap(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
65
60
|
state.indexMiniGap = state.gap1ndex
|
|
66
61
|
return state
|
|
67
62
|
|
|
68
|
-
def initializeVariablesToFindGaps(state:
|
|
63
|
+
def initializeVariablesToFindGaps(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
69
64
|
state.dimensionsUnconstrained = state.dimensionsTotal
|
|
70
65
|
state.gap1ndexCeiling = state.gapRangeStart[state.leaf1ndex - 1]
|
|
71
66
|
state.indexDimension = 0
|
|
72
67
|
return state
|
|
73
68
|
|
|
74
|
-
def insertActiveLeaf(state:
|
|
69
|
+
def insertActiveLeaf(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
75
70
|
state.indexLeaf = 0
|
|
76
71
|
while state.indexLeaf < state.leaf1ndex:
|
|
77
72
|
state.gapsWhere[state.gap1ndexCeiling] = state.indexLeaf
|
|
@@ -79,7 +74,7 @@ def insertActiveLeaf(state: MapFoldingState) -> MapFoldingState:
|
|
|
79
74
|
state.indexLeaf += 1
|
|
80
75
|
return state
|
|
81
76
|
|
|
82
|
-
def insertActiveLeafAtGap(state:
|
|
77
|
+
def insertActiveLeafAtGap(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
83
78
|
state.gap1ndex -= 1
|
|
84
79
|
state.leafAbove[state.leaf1ndex] = state.gapsWhere[state.gap1ndex]
|
|
85
80
|
state.leafBelow[state.leaf1ndex] = state.leafBelow[state.leafAbove[state.leaf1ndex]]
|
|
@@ -89,50 +84,50 @@ def insertActiveLeafAtGap(state: MapFoldingState) -> MapFoldingState:
|
|
|
89
84
|
state.leaf1ndex += 1
|
|
90
85
|
return state
|
|
91
86
|
|
|
92
|
-
def leafBelowSentinelIs1(state:
|
|
87
|
+
def leafBelowSentinelIs1(state: SymmetricFoldsState) -> bool:
|
|
93
88
|
return state.leafBelow[0] == 1
|
|
94
89
|
|
|
95
|
-
def leafConnecteeIsActiveLeaf(state:
|
|
90
|
+
def leafConnecteeIsActiveLeaf(state: SymmetricFoldsState) -> bool:
|
|
96
91
|
return state.leafConnectee == state.leaf1ndex
|
|
97
92
|
|
|
98
|
-
def lookForGaps(state:
|
|
93
|
+
def lookForGaps(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
99
94
|
state.gapsWhere[state.gap1ndexCeiling] = state.leafConnectee
|
|
100
95
|
if state.countDimensionsGapped[state.leafConnectee] == 0:
|
|
101
96
|
state = incrementGap1ndexCeiling(state)
|
|
102
97
|
state.countDimensionsGapped[state.leafConnectee] += 1
|
|
103
98
|
return state
|
|
104
99
|
|
|
105
|
-
def lookupLeafConnecteeInConnectionGraph(state:
|
|
100
|
+
def lookupLeafConnecteeInConnectionGraph(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
106
101
|
state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leaf1ndex]
|
|
107
102
|
return state
|
|
108
103
|
|
|
109
|
-
def loopingLeavesConnectedToActiveLeaf(state:
|
|
104
|
+
def loopingLeavesConnectedToActiveLeaf(state: SymmetricFoldsState) -> bool:
|
|
110
105
|
return state.leafConnectee != state.leaf1ndex
|
|
111
106
|
|
|
112
|
-
def loopingThroughTheDimensions(state:
|
|
107
|
+
def loopingThroughTheDimensions(state: SymmetricFoldsState) -> bool:
|
|
113
108
|
return state.indexDimension < state.dimensionsTotal
|
|
114
109
|
|
|
115
|
-
def loopingToActiveGapCeiling(state:
|
|
110
|
+
def loopingToActiveGapCeiling(state: SymmetricFoldsState) -> bool:
|
|
116
111
|
return state.indexMiniGap < state.gap1ndexCeiling
|
|
117
112
|
|
|
118
|
-
def noGapsHere(state:
|
|
113
|
+
def noGapsHere(state: SymmetricFoldsState) -> bool:
|
|
119
114
|
return state.leaf1ndex > 0 and state.gap1ndex == state.gapRangeStart[state.leaf1ndex - 1]
|
|
120
115
|
|
|
121
|
-
def tryAnotherLeafConnectee(state:
|
|
116
|
+
def tryAnotherLeafConnectee(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
122
117
|
state.leafConnectee = state.connectionGraph[state.indexDimension, state.leaf1ndex, state.leafBelow[state.leafConnectee]]
|
|
123
118
|
return state
|
|
124
119
|
|
|
125
|
-
def tryNextDimension(state:
|
|
120
|
+
def tryNextDimension(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
126
121
|
state.indexDimension += 1
|
|
127
122
|
return state
|
|
128
123
|
|
|
129
|
-
def undoLastLeafPlacement(state:
|
|
124
|
+
def undoLastLeafPlacement(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
130
125
|
state.leaf1ndex -= 1
|
|
131
126
|
state.leafBelow[state.leafAbove[state.leaf1ndex]] = state.leafBelow[state.leaf1ndex]
|
|
132
127
|
state.leafAbove[state.leafBelow[state.leaf1ndex]] = state.leafAbove[state.leaf1ndex]
|
|
133
128
|
return state
|
|
134
129
|
|
|
135
|
-
def count(state:
|
|
130
|
+
def count(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
136
131
|
while activeLeafGreaterThan0(state):
|
|
137
132
|
if activeLeafIsTheFirstLeaf(state) or leafBelowSentinelIs1(state):
|
|
138
133
|
if activeLeafGreaterThanLeavesTotal(state):
|
|
@@ -158,9 +153,9 @@ def count(state: MapFoldingState) -> MapFoldingState:
|
|
|
158
153
|
state = undoLastLeafPlacement(state)
|
|
159
154
|
if gapAvailable(state):
|
|
160
155
|
state = insertActiveLeafAtGap(state)
|
|
161
|
-
state.
|
|
156
|
+
state.symmetricFolds = (state.symmetricFolds + 1) // 2
|
|
162
157
|
return state
|
|
163
158
|
|
|
164
|
-
def doTheNeedful(state:
|
|
159
|
+
def doTheNeedful(state: SymmetricFoldsState) -> SymmetricFoldsState:
|
|
165
160
|
state = count(state)
|
|
166
161
|
return state
|