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.
Files changed (83) hide show
  1. easyRun/A000682.py +25 -0
  2. easyRun/A005316.py +21 -0
  3. easyRun/NOTcountingFolds.py +36 -0
  4. easyRun/__init__.py +0 -0
  5. easyRun/countFolds.py +41 -0
  6. easyRun/meanders.py +71 -0
  7. mapFolding/__init__.py +10 -55
  8. mapFolding/_dataPacking.py +68 -0
  9. mapFolding/_theSSOT.py +33 -36
  10. mapFolding/_theTypes.py +21 -4
  11. mapFolding/algorithms/daoOfMapFolding.py +1 -2
  12. mapFolding/algorithms/matrixMeanders.py +101 -348
  13. mapFolding/algorithms/matrixMeandersBeDry.py +264 -0
  14. mapFolding/algorithms/matrixMeandersNumPy.py +286 -0
  15. mapFolding/algorithms/matrixMeandersPandas.py +351 -0
  16. mapFolding/algorithms/oeisIDbyFormula.py +320 -76
  17. mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +92 -0
  18. mapFolding/basecamp.py +261 -113
  19. mapFolding/beDRY.py +2 -30
  20. mapFolding/dataBaskets.py +120 -4
  21. mapFolding/oeis.py +13 -33
  22. mapFolding/reference/A000682facts.py +1276 -0
  23. mapFolding/reference/A005316facts.py +985 -0
  24. mapFolding/reference/matrixMeandersAnalysis/__init__.py +1 -0
  25. mapFolding/reference/matrixMeandersAnalysis/prefixNotationNotes.py +15 -0
  26. mapFolding/reference/meandersDumpingGround/A005316JavaPort.py +1 -1
  27. mapFolding/reference/meandersDumpingGround/A005316imperative.py +1 -1
  28. mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +424 -0
  29. mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +54 -0
  30. mapFolding/someAssemblyRequired/A007822/__init__.py +0 -0
  31. mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +197 -0
  32. mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +74 -0
  33. mapFolding/someAssemblyRequired/RecipeJob.py +4 -4
  34. mapFolding/someAssemblyRequired/__init__.py +9 -2
  35. mapFolding/someAssemblyRequired/_toolIfThis.py +4 -3
  36. mapFolding/someAssemblyRequired/_toolkitContainers.py +8 -8
  37. mapFolding/someAssemblyRequired/infoBooth.py +27 -30
  38. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +6 -5
  39. mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +6 -4
  40. mapFolding/someAssemblyRequired/makingModules_count.py +294 -0
  41. mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +117 -0
  42. mapFolding/someAssemblyRequired/mapFolding/__init__.py +0 -0
  43. mapFolding/someAssemblyRequired/mapFolding/makeMapFoldingModules.py +220 -0
  44. mapFolding/someAssemblyRequired/meanders/__init__.py +0 -0
  45. mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +64 -0
  46. mapFolding/someAssemblyRequired/toolkitMakeModules.py +152 -0
  47. mapFolding/someAssemblyRequired/toolkitNumba.py +1 -1
  48. mapFolding/someAssemblyRequired/transformationTools.py +1 -0
  49. mapFolding/syntheticModules/A007822/__init__.py +1 -0
  50. mapFolding/syntheticModules/{algorithmA007822.py → A007822/algorithm.py} +2 -3
  51. mapFolding/syntheticModules/{algorithmA007822Numba.py → A007822/algorithmNumba.py} +3 -6
  52. mapFolding/syntheticModules/A007822/asynchronous.py +148 -0
  53. mapFolding/syntheticModules/A007822/asynchronousAnnex.py +66 -0
  54. mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +85 -0
  55. mapFolding/syntheticModules/A007822/asynchronousNumba.py +52 -0
  56. mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +53 -0
  57. mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +47 -0
  58. mapFolding/syntheticModules/{initializeStateA007822.py → A007822/initializeState.py} +1 -2
  59. mapFolding/syntheticModules/{theorem2A007822.py → A007822/theorem2.py} +1 -2
  60. mapFolding/syntheticModules/{theorem2A007822Numba.py → A007822/theorem2Numba.py} +6 -4
  61. mapFolding/syntheticModules/{theorem2A007822Trimmed.py → A007822/theorem2Trimmed.py} +1 -2
  62. mapFolding/syntheticModules/countParallelNumba.py +5 -2
  63. mapFolding/syntheticModules/daoOfMapFoldingNumba.py +4 -2
  64. mapFolding/syntheticModules/dataPacking.py +4 -2
  65. mapFolding/syntheticModules/dataPackingA007822.py +92 -26
  66. mapFolding/syntheticModules/meanders/__init__.py +1 -0
  67. mapFolding/syntheticModules/meanders/bigInt.py +62 -0
  68. mapFolding/syntheticModules/theorem2Numba.py +3 -2
  69. mapFolding/tests/conftest.py +28 -13
  70. mapFolding/tests/test_computations.py +69 -62
  71. mapFolding/tests/test_oeis.py +6 -6
  72. mapFolding/zCuzDocStoopid/__init__.py +4 -0
  73. mapFolding/zCuzDocStoopid/makeDocstrings.py +68 -0
  74. mapfolding-0.16.1.dist-info/METADATA +99 -0
  75. mapfolding-0.16.1.dist-info/RECORD +114 -0
  76. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/top_level.txt +1 -0
  77. mapFolding/someAssemblyRequired/A007822rawMaterials.py +0 -46
  78. mapFolding/someAssemblyRequired/makeAllModules.py +0 -764
  79. mapfolding-0.15.4.dist-info/METADATA +0 -78
  80. mapfolding-0.15.4.dist-info/RECORD +0 -78
  81. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/WHEEL +0 -0
  82. {mapfolding-0.15.4.dist-info → mapfolding-0.16.1.dist-info}/entry_points.txt +0 -0
  83. {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: # noqa: C901
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)
@@ -192,3 +192,4 @@ def unpackDataclassCallFunctionRepackDataclass(ingredientsCaller: IngredientsFun
192
192
  unpack4targetCallable.visit(ingredientsCaller.astFunctionDef)
193
193
  repack4targetCallable.visit(ingredientsCaller.astFunctionDef)
194
194
  return ingredientsCaller
195
+
@@ -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
- if ImaSymmetricFold:
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
- if ImaSymmetricFold:
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)