mapFolding 0.16.2__py3-none-any.whl → 0.16.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. easyRun/NOTcountingFolds.py +6 -5
  2. easyRun/countFolds.py +1 -1
  3. easyRun/generateAllModules.py +14 -0
  4. easyRun/meanders.py +1 -1
  5. mapFolding/__init__.py +1 -0
  6. mapFolding/_theSSOT.py +3 -2
  7. mapFolding/_theTypes.py +3 -0
  8. mapFolding/algorithms/A086345.py +75 -0
  9. mapFolding/algorithms/oeisIDbyFormula.py +2 -2
  10. mapFolding/algorithms/symmetricFolds.py +36 -0
  11. mapFolding/basecamp.py +80 -149
  12. mapFolding/dataBaskets.py +123 -5
  13. mapFolding/filesystemToolkit.py +4 -32
  14. mapFolding/oeis.py +5 -12
  15. mapFolding/reference/A086345Wu.py +25 -0
  16. mapFolding/reference/matrixMeandersAnalysis/signatures.py +3 -0
  17. mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +10 -45
  18. mapFolding/someAssemblyRequired/A007822/_asynchronousAnnex.py +51 -0
  19. mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +36 -195
  20. mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +42 -44
  21. mapFolding/someAssemblyRequired/RecipeJob.py +78 -18
  22. mapFolding/someAssemblyRequired/__init__.py +3 -8
  23. mapFolding/someAssemblyRequired/_toolkitContainers.py +32 -3
  24. mapFolding/someAssemblyRequired/infoBooth.py +40 -23
  25. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +74 -153
  26. mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +56 -88
  27. mapFolding/someAssemblyRequired/makingModules_count.py +10 -12
  28. mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +6 -68
  29. mapFolding/someAssemblyRequired/{mapFolding → mapFoldingModules}/makeMapFoldingModules.py +24 -30
  30. mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +8 -6
  31. mapFolding/someAssemblyRequired/toolkitMakeModules.py +2 -2
  32. mapFolding/someAssemblyRequired/toolkitNumba.py +1 -1
  33. mapFolding/someAssemblyRequired/transformationTools.py +10 -12
  34. mapFolding/syntheticModules/A007822/algorithm.py +45 -50
  35. mapFolding/syntheticModules/A007822/asynchronous.py +91 -34
  36. mapFolding/syntheticModules/A007822/initializeState.py +15 -21
  37. mapFolding/syntheticModules/A007822/theorem2.py +16 -22
  38. mapFolding/syntheticModules/A007822/theorem2Numba.py +20 -26
  39. mapFolding/syntheticModules/A007822/theorem2Trimmed.py +17 -23
  40. mapFolding/syntheticModules/countParallelNumba.py +3 -7
  41. mapFolding/syntheticModules/daoOfMapFoldingNumba.py +1 -2
  42. mapFolding/syntheticModules/meanders/bigInt.py +9 -9
  43. mapFolding/syntheticModules/theorem2Numba.py +28 -9
  44. mapFolding/syntheticModules/theorem2Trimmed.py +1 -1
  45. mapFolding/tests/test_computations.py +1 -1
  46. {mapfolding-0.16.2.dist-info → mapfolding-0.16.4.dist-info}/METADATA +4 -1
  47. {mapfolding-0.16.2.dist-info → mapfolding-0.16.4.dist-info}/RECORD +52 -61
  48. mapFolding/_dataPacking.py +0 -68
  49. mapFolding/reference/meandersDumpingGround/A005316intOptimized.py +0 -122
  50. mapFolding/reference/meandersDumpingGround/A005316optimized128bit.py +0 -79
  51. mapFolding/reference/meandersDumpingGround/matrixMeandersBaseline.py +0 -65
  52. mapFolding/reference/meandersDumpingGround/matrixMeandersBaselineAnnex.py +0 -84
  53. mapFolding/reference/meandersDumpingGround/matrixMeandersSimpleQueue.py +0 -90
  54. mapFolding/syntheticModules/A007822/algorithmNumba.py +0 -94
  55. mapFolding/syntheticModules/A007822/asynchronousAnnex.py +0 -66
  56. mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +0 -70
  57. mapFolding/syntheticModules/A007822/asynchronousNumba.py +0 -79
  58. mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +0 -65
  59. mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +0 -56
  60. mapFolding/syntheticModules/dataPacking.py +0 -26
  61. mapFolding/syntheticModules/dataPackingA007822.py +0 -92
  62. /mapFolding/someAssemblyRequired/{mapFolding → mapFoldingModules}/__init__.py +0 -0
  63. {mapfolding-0.16.2.dist-info → mapfolding-0.16.4.dist-info}/WHEEL +0 -0
  64. {mapfolding-0.16.2.dist-info → mapfolding-0.16.4.dist-info}/entry_points.txt +0 -0
  65. {mapfolding-0.16.2.dist-info → mapfolding-0.16.4.dist-info}/licenses/LICENSE +0 -0
  66. {mapfolding-0.16.2.dist-info → mapfolding-0.16.4.dist-info}/top_level.txt +0 -0
@@ -1,36 +1,23 @@
1
1
  """addSymmetryCheckAsynchronous."""
2
- from astToolkit import (
3
- Be, extractFunctionDef, Grab, identifierDotAttribute, Make, NodeChanger, NodeTourist, parsePathFilename2astModule,
4
- Then)
2
+ from astToolkit import Be, Grab, identifierDotAttribute, LedgerOfImports, Make, NodeChanger, NodeTourist, Then
5
3
  from hunterMakesPy import raiseIfNone
6
4
  from mapFolding import packageSettings
7
- from mapFolding.someAssemblyRequired import (
8
- identifierCallableSourceDispatcherDEFAULT, identifierCountingDEFAULT, identifierDataclassInstanceDEFAULT, IfThis,
9
- logicalPathInfixAlgorithmDEFAULT)
10
- from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import (
11
- A007822adjustFoldsTotal, astExprCall_filterAsymmetricFoldsDataclass, identifier_filterAsymmetricFolds,
12
- identifierCounting, identifierDataclass, logicalPathInfixA007822, sourceCallableDispatcherA007822,
13
- sourceCallableIdentifierA007822)
14
- from mapFolding.someAssemblyRequired.infoBooth import identifierCallableSourceDEFAULT
15
- from mapFolding.someAssemblyRequired.makingModules_count import makeTheorem2, numbaOnTheorem2, trimTheorem2
16
- from mapFolding.someAssemblyRequired.toolkitMakeModules import (
17
- getLogicalPath, getModule, getPathFilename, write_astModule)
5
+ from mapFolding.someAssemblyRequired import defaultA007822, IfThis
6
+ from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import ExprCallFilterAsymmetricFoldsState
7
+ from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename, write_astModule
18
8
  from pathlib import PurePath
19
9
  import ast
20
10
 
21
- identifier_asynchronous = 'asynchronous'
22
- identifier_getSymmetricFoldsTotal = 'getSymmetricFoldsTotal'
23
- identifier_initializeConcurrencyManager = 'initializeConcurrencyManager'
24
- identifier_processCompletedFutures = '_processCompletedFutures'
11
+ # TODO figure out asynchronous + numba.
25
12
 
26
- astExprCall_initializeConcurrencyManager: ast.Expr = Make.Expr(Make.Call(Make.Name(identifier_initializeConcurrencyManager), listParameters=[Make.Name('maxWorkers')]))
13
+ astExprCall_initializeConcurrencyManager: ast.Expr = Make.Expr(Make.Call(Make.Name(defaultA007822['function']['initializeConcurrencyManager']), listParameters=[Make.Name('maxWorkers')]))
27
14
  AssignTotal2CountingIdentifier: ast.Assign = Make.Assign(
28
- [Make.Attribute(Make.Name(identifierDataclass), identifierCounting, context=Make.Store())]
29
- , value=Make.Call(Make.Name(identifier_getSymmetricFoldsTotal))
15
+ [Make.Attribute(Make.Name(defaultA007822['variable']['stateInstance']), defaultA007822['variable']['counting'], context=Make.Store())]
16
+ , value=Make.Call(Make.Name(defaultA007822['function']['getSymmetricFoldsTotal']))
30
17
  )
31
18
 
32
19
  def addSymmetryCheckAsynchronous(astModule: ast.Module, identifierModule: str, identifierCallable: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
33
- """Add symmetry check to the counting function.
20
+ """Make the check for symmetry in each folding pattern in a group of folds asynchronous to the rest of the symmetric map folding algorithm.
34
21
 
35
22
  To do asynchronous filtering, a few things must happen.
36
23
  1. When the algorithm finds a `groupOfFolds`, the call to `filterAsymmetricFolds` must be non-blocking.
@@ -45,16 +32,13 @@ def addSymmetryCheckAsynchronous(astModule: ast.Module, identifierModule: str, i
45
32
  Each `leafBelow` array will be 28 * 8-bits, so if the queue has only 0.3% of the total calls in it, that is 28 GiB of data.
46
33
  """
47
34
  astFunctionDef_count: ast.FunctionDef = raiseIfNone(NodeTourist(
48
- findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableIdentifierA007822))
35
+ findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(defaultA007822['function']['counting']))
49
36
  , doThat = Then.extractIt
50
37
  ).captureLastMatch(astModule))
51
38
 
52
- NodeChanger(Be.Return, Then.insertThisAbove([A007822adjustFoldsTotal])).visit(astFunctionDef_count)
53
-
54
39
  NodeChanger(
55
- findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(identifierDataclass, identifierCounting))
56
- , doThat=Then.replaceWith(astExprCall_filterAsymmetricFoldsDataclass)
57
- ).visit(astFunctionDef_count)
40
+ Be.Assign.valueIs(IfThis.isCallIdentifier(defaultA007822['function']['filterAsymmetricFolds']))
41
+ , Then.replaceWith(ExprCallFilterAsymmetricFoldsState)).visit(astFunctionDef_count)
58
42
 
59
43
  NodeChanger(
60
44
  findThis=Be.While.testIs(IfThis.isCallIdentifier('activeLeafGreaterThan0'))
@@ -62,9 +46,10 @@ def addSymmetryCheckAsynchronous(astModule: ast.Module, identifierModule: str, i
62
46
  ).visit(astFunctionDef_count)
63
47
 
64
48
  NodeChanger(
65
- findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableIdentifierA007822))
49
+ findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(defaultA007822['function']['counting']))
66
50
  , doThat=Then.replaceWith(astFunctionDef_count)
67
51
  ).visit(astModule)
52
+ del astFunctionDef_count
68
53
 
69
54
  astFunctionDef_doTheNeedful: ast.FunctionDef = raiseIfNone(NodeTourist(
70
55
  findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableDispatcher))
@@ -72,188 +57,44 @@ def addSymmetryCheckAsynchronous(astModule: ast.Module, identifierModule: str, i
72
57
  ).captureLastMatch(astModule))
73
58
 
74
59
  astFunctionDef_doTheNeedful.body.insert(0, astExprCall_initializeConcurrencyManager)
75
- astFunctionDef_doTheNeedful.args.args.append(Make.arg('maxWorkers', Make.BitOr.join([Make.Name('int'), Make.Constant(None)])))
76
- astFunctionDef_doTheNeedful.args.defaults.append(Make.Constant(None))
60
+ astFunctionDef_doTheNeedful.args.args.append(Make.arg('maxWorkers', Make.Name('int')))
77
61
 
78
62
  NodeChanger(
79
63
  findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableDispatcher))
80
64
  , doThat=Then.replaceWith(astFunctionDef_doTheNeedful)
81
65
  ).visit(astModule)
66
+ del astFunctionDef_doTheNeedful
82
67
 
83
- astImportFrom = ast.ImportFrom(getLogicalPath(packageSettings.identifierPackage, logicalPathInfix, identifierModule + 'Annex')
84
- , [Make.alias(identifier_filterAsymmetricFolds), Make.alias(identifier_getSymmetricFoldsTotal), Make.alias(identifier_initializeConcurrencyManager)], 0)
85
-
86
- astModule.body.insert(0, astImportFrom)
87
-
88
- pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule)
89
- pathFilenameAnnex: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule + 'Annex')
90
-
91
- write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
92
- del astModule
93
- # ----------------- Ingredients Module Annex ------------------------------------------------------------------------------
94
- ImaString = """from concurrent.futures import Future as ConcurrentFuture, ThreadPoolExecutor
95
- from hunterMakesPy import raiseIfNone
96
- from mapFolding import Array1DLeavesTotal
97
- from queue import Empty, Queue
98
- from threading import Thread
99
- import numpy"""
100
-
101
- astModule = ast.parse(ImaString)
102
- del ImaString
103
-
104
- ImaString = f"""concurrencyManager = None
105
- {identifierCounting}Total: int = 0
106
- processingThread = None
107
- queueFutures: Queue[ConcurrentFuture[int]] = Queue()
108
- """
109
- astModule.body.extend(ast.parse(ImaString).body)
110
- del ImaString
111
-
112
- ImaString = f"""def {identifier_initializeConcurrencyManager}(maxWorkers: int | None = None, {identifierCounting}: int = 0) -> None:
113
- global concurrencyManager, queueFutures, {identifierCounting}Total, processingThread
114
- concurrencyManager = ThreadPoolExecutor(max_workers=maxWorkers)
115
- queueFutures = Queue()
116
- {identifierCounting}Total = {identifierCounting}
117
- processingThread = Thread(target={identifier_processCompletedFutures})
118
- processingThread.start()
119
- """
120
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_initializeConcurrencyManager)))
121
- del ImaString
68
+ imports = LedgerOfImports(astModule)
69
+ removeImports = NodeChanger(IfThis.isAnyOf(Be.ImportFrom, Be.Import), Then.removeIt)
70
+ removeImports.visit(astModule)
122
71
 
123
- ImaString = f"""def {identifier_processCompletedFutures}() -> None:
124
- global queueFutures, {identifierCounting}Total
125
- while True:
126
- try:
127
- claimTicket: ConcurrentFuture[int] = queueFutures.get(timeout=1)
128
- if claimTicket is None:
129
- break
130
- {identifierCounting}Total += claimTicket.result()
131
- except Empty:
132
- continue
133
- """
134
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_processCompletedFutures)))
135
- del ImaString
136
-
137
- ImaString = f"""def _{identifier_filterAsymmetricFolds}(leafBelow: Array1DLeavesTotal) -> int:
138
- {identifierCounting} = 0
139
- leafComparison: Array1DLeavesTotal = numpy.zeros_like(leafBelow)
140
- leavesTotal = leafBelow.size - 1
141
-
142
- indexLeaf = 0
143
- leafConnectee = 0
144
- while leafConnectee < leavesTotal + 1:
145
- leafNumber = int(leafBelow[indexLeaf])
146
- leafComparison[leafConnectee] = (leafNumber - indexLeaf + leavesTotal) % leavesTotal
147
- indexLeaf = leafNumber
148
- leafConnectee += 1
149
-
150
- indexInMiddle = leavesTotal // 2
151
- indexDistance = 0
152
- while indexDistance < leavesTotal + 1:
153
- ImaSymmetricFold = True
154
- leafConnectee = 0
155
- while leafConnectee < indexInMiddle:
156
- if leafComparison[(indexDistance + leafConnectee) % (leavesTotal + 1)] != leafComparison[(indexDistance + leavesTotal - 1 - leafConnectee) % (leavesTotal + 1)]:
157
- ImaSymmetricFold = False
158
- break
159
- leafConnectee += 1
160
- {identifierCounting} += ImaSymmetricFold
161
- indexDistance += 1
162
- return {identifierCounting}
163
- """
164
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), f'_{identifier_filterAsymmetricFolds}')))
165
- del ImaString
166
-
167
- ImaString = f"""
168
- def {identifier_filterAsymmetricFolds}(leafBelow: Array1DLeavesTotal) -> None:
169
- global concurrencyManager, queueFutures
170
- queueFutures.put_nowait(raiseIfNone(concurrencyManager).submit(_{identifier_filterAsymmetricFolds}, leafBelow.copy()))
171
- """
172
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_filterAsymmetricFolds)))
173
- del ImaString
174
-
175
- ImaString = f"""
176
- def {identifier_getSymmetricFoldsTotal}() -> int:
177
- global concurrencyManager, queueFutures, processingThread
178
- raiseIfNone(concurrencyManager).shutdown(wait=True)
179
- queueFutures.put(None)
180
- raiseIfNone(processingThread).join()
181
- return {identifierCounting}Total
182
- """
183
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_getSymmetricFoldsTotal)))
184
- del ImaString
185
- write_astModule(astModule, pathFilenameAnnex, packageSettings.identifierPackage)
186
-
187
- return pathFilename
72
+ astModuleAsynchronousAnnex: ast.Module = getModule(logicalPathInfix=defaultA007822['logicalPath']['assembly'], identifierModule='_asynchronousAnnex')
73
+ imports.walkThis(astModuleAsynchronousAnnex)
74
+ removeImports.visit(astModuleAsynchronousAnnex)
188
75
 
189
- def makeAsynchronousNumbaOnTheorem2(astModule: ast.Module, identifierModule: str, identifierCallable: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
190
- """Make the asynchronous numba on theorem2 module."""
191
- pathFilename: PurePath = numbaOnTheorem2(astModule, identifierModule, identifierCallable, logicalPathInfix, sourceCallableDispatcher)
192
-
193
- astModule = parsePathFilename2astModule(pathFilename)
194
-
195
- listAssignToMove: list[ast.Assign] = []
196
-
197
- findThis = IfThis.isAnyOf(IfThis.isAssignAndTargets0Is(IfThis.isNameIdentifier(identifierCountingDEFAULT))
198
- , Be.AugAssign.targetIs(IfThis.isNameIdentifier(identifierCountingDEFAULT)))
199
- NodeTourist(findThis, Then.appendTo(listAssignToMove)).visit(astModule)
200
-
201
- NodeChanger(findThis, Then.removeIt).visit(astModule)
202
-
203
- NodeChanger(
204
- findThis=Be.Assign.valueIs(IfThis.isCallIdentifier(identifierCallableSourceDEFAULT))
205
- , doThat=Then.insertThisBelow(listAssignToMove)
206
- ).visit(astModule)
207
-
208
- write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
209
-
210
- return pathFilename
211
-
212
- def makeAsynchronousTheorem2(astModule: ast.Module, identifierModule: str, identifierCallable: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
213
- """Make the asynchronous theorem2 module."""
214
- pathFilename: PurePath = makeTheorem2(astModule, identifierModule, identifierCallable, logicalPathInfix, sourceCallableDispatcher)
215
-
216
- astModule = parsePathFilename2astModule(pathFilename)
217
-
218
- astAttribute = Make.Attribute(Make.Name(identifierDataclassInstanceDEFAULT), identifierCountingDEFAULT)
219
- astAssign = Make.Assign([astAttribute], value=Make.Constant(0))
220
-
221
- NodeChanger[ast.Call, ast.Call](
222
- findThis = IfThis.isCallIdentifier(identifier_initializeConcurrencyManager)
223
- , doThat = Grab.argsAttribute(lambda args: [*args, astAttribute]) # pyright: ignore[reportArgumentType]
224
- ).visit(astModule)
76
+ NodeChanger(Be.FunctionDef.nameIs(IfThis.isIdentifier(defaultA007822['function']['filterAsymmetricFolds']))
77
+ , Grab.nameAttribute(Then.replaceWith(f"_{defaultA007822['function']['filterAsymmetricFolds']}"))
78
+ ).visit(astModule)
225
79
 
226
- NodeChanger(
227
- findThis = Be.Expr.valueIs(IfThis.isCallIdentifier(identifier_initializeConcurrencyManager))
228
- , doThat = Then.insertThisBelow([astAssign])
229
- ).visit(astModule)
80
+ NodeChanger(Be.FunctionDef.nameIs(IfThis.isIdentifier(f"_{defaultA007822['function']['filterAsymmetricFolds']}"))
81
+ , Then.removeIt
82
+ ).visit(astModuleAsynchronousAnnex)
230
83
 
231
- identifierAnnex: identifierDotAttribute = getLogicalPath(packageSettings.identifierPackage, logicalPathInfix, identifier_asynchronous + 'Annex')
232
- identifierAnnexNumba: identifierDotAttribute = identifierAnnex + 'Numba'
84
+ astModule.body = [*imports.makeList_ast(), *astModuleAsynchronousAnnex.body, *astModule.body]
233
85
 
234
- NodeChanger(
235
- findThis=Be.ImportFrom.moduleIs(IfThis.isIdentifier(identifierAnnex))
236
- , doThat=Grab.moduleAttribute(Then.replaceWith(identifierAnnexNumba))
237
- ).visit(astModule)
86
+ pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule)
238
87
 
239
88
  write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
240
89
 
241
90
  return pathFilename
242
91
 
243
- def _makeA007822AsynchronousModules() -> None:
244
-
245
- astModule: ast.Module = getModule(logicalPathInfix=logicalPathInfixAlgorithmDEFAULT)
246
- pathFilename: PurePath = addSymmetryCheckAsynchronous(astModule, 'asynchronous', None, logicalPathInfixA007822, sourceCallableDispatcherA007822)
247
-
248
- astModule = getModule(logicalPathInfix=logicalPathInfixA007822, identifierModule='asynchronous')
249
- pathFilename = makeAsynchronousTheorem2(astModule, 'asynchronousTheorem2', None, logicalPathInfixA007822, identifierCallableSourceDispatcherDEFAULT)
250
-
251
- astModule = parsePathFilename2astModule(pathFilename)
252
- pathFilename = trimTheorem2(astModule, 'asynchronousTrimmed', None, logicalPathInfixA007822, identifierCallableSourceDispatcherDEFAULT)
253
-
254
- astModule = parsePathFilename2astModule(pathFilename)
255
- pathFilename = makeAsynchronousNumbaOnTheorem2(astModule, 'asynchronousNumba', None, logicalPathInfixA007822, identifierCallableSourceDispatcherDEFAULT)
92
+ def makeA007822AsynchronousModules() -> None:
93
+ """Make asynchronous modules for A007822."""
94
+ astModule: ast.Module = getModule(logicalPathInfix=defaultA007822['logicalPath']['synthetic'], identifierModule=defaultA007822['module']['algorithm'])
95
+ pathFilename: PurePath = addSymmetryCheckAsynchronous(astModule, defaultA007822['module']['asynchronous'], defaultA007822['function']['counting'] # noqa: F841 # pyright: ignore[reportUnusedVariable]
96
+ , defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
256
97
 
257
98
  if __name__ == '__main__':
258
- _makeA007822AsynchronousModules()
99
+ makeA007822AsynchronousModules()
259
100
 
@@ -1,42 +1,45 @@
1
1
  """addSymmetryCheck."""
2
- from astToolkit import Be, identifierDotAttribute, Make, NodeChanger, NodeTourist, parsePathFilename2astModule, Then
2
+ from astToolkit import (
3
+ Be, Grab, identifierDotAttribute, LedgerOfImports, NodeChanger, NodeTourist, parsePathFilename2astModule, Then)
3
4
  from hunterMakesPy import raiseIfNone
4
5
  from mapFolding import packageSettings
5
- from mapFolding.someAssemblyRequired import (
6
- identifierCallableSourceDEFAULT, identifierCallableSourceDispatcherDEFAULT, identifierCountingDEFAULT,
7
- identifierDataclassInstanceDEFAULT, IfThis)
6
+ from mapFolding.someAssemblyRequired import default, defaultA007822, IfThis
8
7
  from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import (
9
- A007822adjustFoldsTotal, A007822incrementCount, FunctionDef_filterAsymmetricFolds, logicalPathInfixA007822,
10
- sourceCallableDispatcherA007822, sourceCallableIdentifierA007822)
11
- from mapFolding.someAssemblyRequired.makingModules_count import (
12
- makeMapFoldingNumba, makeTheorem2, numbaOnTheorem2, trimTheorem2)
13
- from mapFolding.someAssemblyRequired.makingModules_doTheNeedful import makeInitializeState, makeUnRePackDataclass
14
- from mapFolding.someAssemblyRequired.toolkitMakeModules import (
15
- getLogicalPath, getModule, getPathFilename, write_astModule)
16
- from os import PathLike
8
+ A007822adjustFoldsTotal, A007822incrementCount, FunctionDef_filterAsymmetricFolds)
9
+ from mapFolding.someAssemblyRequired.makingModules_count import makeTheorem2, numbaOnTheorem2, trimTheorem2
10
+ from mapFolding.someAssemblyRequired.makingModules_doTheNeedful import makeInitializeState
11
+ from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename, write_astModule
17
12
  from pathlib import PurePath
18
13
  import ast
19
14
 
20
15
  def addSymmetryCheck(astModule: ast.Module, identifierModule: str, identifierCallable: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
21
- """Add logic to check for symmetric folds."""
22
- # NOTE HEY HEY! Are you trying to figure out why there is more than one copy of `filterAsymmetricFolds`? See the TODO NOTE, below.
16
+ """Modify the multidimensional map folding algorithm by checking for symmetry in each folding pattern in a group of folds."""
17
+ NodeChanger(Be.Name.idIs(IfThis.isIdentifier(default['variable']['stateDataclass']))
18
+ , Grab.idAttribute(Then.replaceWith(defaultA007822['variable']['stateDataclass']))
19
+ ).visit(astModule)
23
20
 
24
- astFunctionDef_count: ast.FunctionDef = raiseIfNone(NodeTourist(
25
- findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(identifierCallableSourceDEFAULT))
21
+ NodeChanger(Be.alias.nameIs(IfThis.isIdentifier(default['variable']['stateDataclass']))
22
+ , Grab.nameAttribute(Then.replaceWith(defaultA007822['variable']['stateDataclass']))
23
+ ).visit(astModule)
24
+
25
+ FunctionDef_count: ast.FunctionDef = raiseIfNone(NodeTourist(
26
+ findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(default['function']['counting']))
26
27
  , doThat = Then.extractIt
27
28
  ).captureLastMatch(astModule))
28
- astFunctionDef_count.name = sourceCallableIdentifierA007822
29
+ FunctionDef_count.name = identifierCallable or defaultA007822['function']['counting']
29
30
 
30
- NodeChanger(Be.Return, Then.insertThisAbove([A007822adjustFoldsTotal])).visit(astFunctionDef_count)
31
+ NodeChanger(Be.Return, Then.insertThisAbove([A007822adjustFoldsTotal])).visit(FunctionDef_count)
31
32
 
32
33
  NodeChanger(
33
- findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(identifierDataclassInstanceDEFAULT, identifierCountingDEFAULT))
34
+ findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(default['variable']['stateInstance'], default['variable']['counting']))
34
35
  , doThat=Then.replaceWith(A007822incrementCount)
35
- ).visit(astFunctionDef_count)
36
+ ).visit(FunctionDef_count)
37
+
38
+ imports = LedgerOfImports(astModule)
39
+ NodeChanger(IfThis.isAnyOf(Be.ImportFrom, Be.Import), Then.removeIt).visit(astModule)
40
+ imports.addImport_asStr('numpy')
36
41
 
37
- # TODO NOTE This will insert a copy of `filterAsymmetricFolds` for each `ast.ImportFrom` in the source module. Find or make a
38
- # system to replace the `Ingredients` paradigm.
39
- NodeChanger(Be.ImportFrom, Then.insertThisBelow([FunctionDef_filterAsymmetricFolds])).visit(astModule)
42
+ astModule.body = [*imports.makeList_ast(), FunctionDef_filterAsymmetricFolds, *astModule.body]
40
43
 
41
44
  pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule)
42
45
 
@@ -44,32 +47,27 @@ def addSymmetryCheck(astModule: ast.Module, identifierModule: str, identifierCal
44
47
 
45
48
  return pathFilename
46
49
 
47
- def _makeA007822Modules() -> None:
48
- astModule = getModule(logicalPathInfix='algorithms')
49
- pathFilename = addSymmetryCheck(astModule, 'algorithm', None, logicalPathInfixA007822, None)
50
-
51
- astModule = getModule(logicalPathInfix=logicalPathInfixA007822, identifierModule='algorithm')
52
- pathFilename: PurePath = makeMapFoldingNumba(astModule, 'algorithmNumba', None, logicalPathInfixA007822, sourceCallableDispatcherA007822)
50
+ def makeA007822Modules() -> None:
51
+ """Make."""
52
+ astModule: ast.Module = getModule(logicalPathInfix='algorithms')
53
+ pathFilename: PurePath = addSymmetryCheck(astModule, defaultA007822['module']['algorithm'], defaultA007822['function']['counting']
54
+ , defaultA007822['logicalPath']['synthetic'], None)
53
55
 
54
- # NOTE I can't handle parallel right now.
56
+ astModule = getModule(logicalPathInfix=defaultA007822['logicalPath']['synthetic'], identifierModule=defaultA007822['module']['algorithm'])
57
+ makeInitializeState(astModule, defaultA007822['module']['initializeState']
58
+ , defaultA007822['function']['initializeState'], defaultA007822['logicalPath']['synthetic'], None)
55
59
 
56
- astModule = getModule(logicalPathInfix=logicalPathInfixA007822, identifierModule='algorithm')
57
- makeInitializeState(astModule, 'initializeState', 'transitionOnGroupsOfFolds', logicalPathInfixA007822)
58
-
59
- astModule = getModule(logicalPathInfix=logicalPathInfixA007822, identifierModule='algorithm')
60
- pathFilename = makeTheorem2(astModule, 'theorem2', None, logicalPathInfixA007822, identifierCallableSourceDispatcherDEFAULT)
60
+ astModule = getModule(logicalPathInfix=defaultA007822['logicalPath']['synthetic'], identifierModule=defaultA007822['module']['algorithm'])
61
+ pathFilename = makeTheorem2(astModule, 'theorem2', defaultA007822['function']['counting']
62
+ , defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
61
63
 
62
64
  astModule = parsePathFilename2astModule(pathFilename)
63
- pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', None, logicalPathInfixA007822, identifierCallableSourceDispatcherDEFAULT)
65
+ pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', defaultA007822['function']['counting']
66
+ , defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
64
67
 
65
68
  astModule = parsePathFilename2astModule(pathFilename)
66
- pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', None, logicalPathInfixA007822, identifierCallableSourceDispatcherDEFAULT)
67
- # TODO from mapFolding.syntheticModules.dataPackingA007822 import unRePackDataclass
68
- # @unRePackDataclass
69
-
70
- # TODO Make this decorator.
71
- # astImportFrom: ast.ImportFrom = Make.ImportFrom(getLogicalPath(packageSettings.identifierPackage, logicalPathInfixA007822, 'theorem2Numba'), list_alias=[Make.alias(sourceCallableIdentifierA007822)])
72
- # makeUnRePackDataclass(astImportFrom, 'dataPackingA007822')
69
+ pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', defaultA007822['function']['counting']
70
+ , defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
73
71
 
74
72
  if __name__ == '__main__':
75
- _makeA007822Modules()
73
+ makeA007822Modules()
@@ -1,17 +1,23 @@
1
1
  """Configuration by dataclass."""
2
2
 
3
- from ast import Module
4
- from astToolkit import identifierDotAttribute, parseLogicalPath2astModule
3
+ from astToolkit import identifierDotAttribute, IngredientsFunction, IngredientsModule, parseLogicalPath2astModule
4
+ from astToolkit.transformationTools import pythonCode2ast_expr
5
+ from hunterMakesPy import autoDecodingRLE
6
+ # TODO 'The...' identifiers are a vestigial semiotic system. Do I still need to import `asname`? If so, would different
7
+ # identifiers better integrate into the current semiotics?
5
8
  from mapFolding import (
6
9
  DatatypeElephino as TheDatatypeElephino, DatatypeFoldsTotal as TheDatatypeFoldsTotal,
7
10
  DatatypeLeavesTotal as TheDatatypeLeavesTotal, getPathFilenameFoldsTotal, getPathRootJobDEFAULT, packageSettings)
8
11
  from mapFolding.dataBaskets import MapFoldingState
9
- from mapFolding.someAssemblyRequired import identifierDataclassInstanceDEFAULT, ShatteredDataclass
12
+ from mapFolding.someAssemblyRequired import DatatypeConfiguration, default
13
+ from mapFolding.someAssemblyRequired._toolkitContainers import ShatteredDataclass
10
14
  from mapFolding.someAssemblyRequired.transformationTools import shatter_dataclassesDOTdataclass
11
15
  from pathlib import Path, PurePosixPath
16
+ from typing import cast
17
+ import ast
12
18
  import dataclasses
13
19
 
14
- @dataclasses.dataclass
20
+ @dataclasses.dataclass(slots=True)
15
21
  class RecipeJobTheorem2:
16
22
  """Configuration recipe for generating map folding computation jobs.
17
23
 
@@ -88,17 +94,17 @@ class RecipeJobTheorem2:
88
94
  shatteredDataclass: ShatteredDataclass = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
89
95
  """Deconstructed dataclass metadata for code transformation."""
90
96
 
91
- # Source -----------------------------------------
92
- source_astModule: Module = parseLogicalPath2astModule('mapFolding.syntheticModules.theorem2Numba') # noqa: RUF009
97
+ # ------- Source -----------------------------------------
98
+ source_astModule: ast.Module = parseLogicalPath2astModule(f'{packageSettings.identifierPackage}.{default['logicalPath']['synthetic']}.theorem2Numba') # noqa: RUF009
93
99
  """Parsed AST of the source module containing the generic algorithm."""
94
- sourceCountCallable: str = 'count'
100
+ identifierCallableSource: str = default['function']['counting']
95
101
  """Name of the counting function to extract."""
96
102
 
97
- sourceLogicalPathModuleDataclass: identifierDotAttribute = 'mapFolding.dataBaskets'
103
+ sourceLogicalPathModuleDataclass: identifierDotAttribute = f'{packageSettings.identifierPackage}.dataBaskets'
98
104
  """Logical path to the dataclass module."""
99
- sourceDataclassIdentifier: str = 'MapFoldingState'
105
+ sourceDataclassIdentifier: str = default['variable']['stateDataclass']
100
106
  """Name of the source dataclass."""
101
- sourceDataclassInstance: str = identifierDataclassInstanceDEFAULT
107
+ sourceDataclassInstance: str = default['variable']['stateInstance']
102
108
  """Instance identifier for the dataclass."""
103
109
 
104
110
  sourcePathPackage: PurePosixPath | None = PurePosixPath(packageSettings.pathPackage) # noqa: RUF009
@@ -106,7 +112,7 @@ class RecipeJobTheorem2:
106
112
  sourcePackageIdentifier: str | None = packageSettings.identifierPackage
107
113
  """Name of the source package."""
108
114
 
109
- # Filesystem, names of physical objects ------------------------------------------
115
+ # ------- Filesystem, names of physical objects ------------------------------------------
110
116
  pathPackage: PurePosixPath | None = None
111
117
  """Override path for the target package."""
112
118
  pathModule: PurePosixPath | None = PurePosixPath(getPathRootJobDEFAULT()) # noqa: RUF009
@@ -116,23 +122,23 @@ class RecipeJobTheorem2:
116
122
  pathFilenameFoldsTotal: PurePosixPath = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
117
123
  """Path for writing fold count results."""
118
124
 
119
- # Logical identifiers, as opposed to physical identifiers ------------------------
125
+ # ------- Logical identifiers, as opposed to physical identifiers ------------------------
120
126
  packageIdentifier: str | None = None
121
127
  """Target package identifier."""
122
128
  logicalPathRoot: identifierDotAttribute | None = None
123
129
  """Logical path root; probably corresponds to physical filesystem directory."""
124
130
  moduleIdentifier: str = dataclasses.field(default=None, init=True) # pyright: ignore[reportAssignmentType]
125
131
  """Target module identifier."""
126
- countCallable: str = sourceCountCallable
132
+ countCallable: str = identifierCallableSource
127
133
  """Name of the counting function in generated module."""
128
- dataclassIdentifier: str | None = sourceDataclassIdentifier
134
+ identifierDataclass: str | None = sourceDataclassIdentifier
129
135
  """Target dataclass identifier."""
130
- dataclassInstance: str | None = sourceDataclassInstance
136
+ identifierDataclassInstance: str | None = sourceDataclassInstance
131
137
  """Target dataclass instance identifier."""
132
138
  logicalPathModuleDataclass: identifierDotAttribute | None = sourceLogicalPathModuleDataclass
133
139
  """Logical path to target dataclass module."""
134
140
 
135
- # Datatypes ------------------------------------------
141
+ # ------- Datatypes ------------------------------------------
136
142
  type DatatypeFoldsTotal = TheDatatypeFoldsTotal
137
143
  """Type alias for datatype linked to the magnitude of `foldsTotal`."""
138
144
  type DatatypeElephino = TheDatatypeElephino
@@ -211,5 +217,59 @@ class RecipeJobTheorem2:
211
217
  if self.pathFilenameFoldsTotal is None: # pyright: ignore[reportUnnecessaryComparison]
212
218
  self.pathFilenameFoldsTotal = pathFilenameFoldsTotal
213
219
 
214
- if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.dataclassIdentifier and self.dataclassInstance: # pyright: ignore[reportUnnecessaryComparison]
215
- self.shatteredDataclass = shatter_dataclassesDOTdataclass(self.logicalPathModuleDataclass, self.dataclassIdentifier, self.dataclassInstance)
220
+ if self.shatteredDataclass is None and self.logicalPathModuleDataclass and self.identifierDataclass and self.identifierDataclassInstance: # pyright: ignore[reportUnnecessaryComparison]
221
+ self.shatteredDataclass = shatter_dataclassesDOTdataclass(self.logicalPathModuleDataclass, self.identifierDataclass, self.identifierDataclassInstance)
222
+
223
+ def moveShatteredDataclass_arg2body(identifier: str, job: RecipeJobTheorem2) -> ast.AnnAssign | ast.Assign:
224
+ """Embed a shattered dataclass field assignment into the function body.
225
+
226
+ (AI generated docstring)
227
+
228
+ This helper retrieves the pre-fabricated assignment for `identifier` from `job.shatteredDataclass`, hydrates the literal
229
+ payload from `job.state`, and returns the node ready for insertion into a generated function body. Scalar entries receive the
230
+ concrete integer value, array entries are encoded using the auto-decoding run-length encoded method from `hunterMakesPy`, and
231
+ other constructors are left untouched so downstream tooling can decide how to finalize them.
232
+
233
+ Parameters
234
+ ----------
235
+ identifier : str
236
+ Field name keyed in `job.shatteredDataclass.Z0Z_field2AnnAssign`.
237
+ job : RecipeJobTheorem2
238
+ Job descriptor that supplies the current computation state and shattered metadata.
239
+
240
+ Returns
241
+ -------
242
+ Ima___Assign : ast.AnnAssign | ast.Assign
243
+ Assignment node mutated with state-backed values for the requested field.
244
+ """
245
+ Ima___Assign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[identifier]
246
+ match elementConstructor:
247
+ case 'scalar':
248
+ cast('ast.Constant', cast('ast.Call', Ima___Assign.value).args[0]).value = int(eval(f"job.state.{identifier}")) # noqa: S307
249
+ case 'array':
250
+ dataAsStrRLE: str = autoDecodingRLE(eval(f"job.state.{identifier}"), assumeAddSpaces=True) # noqa: S307
251
+ dataAs_ast_expr: ast.expr = pythonCode2ast_expr(dataAsStrRLE)
252
+ cast('ast.Call', Ima___Assign.value).args = [dataAs_ast_expr]
253
+ case _:
254
+ pass
255
+ return Ima___Assign
256
+
257
+ # TODO Use this concept in general modules, not just custom jobs.
258
+ def customizeDatatypeViaImport(ingredientsFunction: IngredientsFunction, ingredientsModule: IngredientsModule, listDatatypeConfigurations: list[DatatypeConfiguration]) -> tuple[IngredientsFunction, IngredientsModule]:
259
+ """Customize data types in the given ingredients by adjusting imports.
260
+
261
+ In the ecosystem of "Ingredients", "Recipes", "DataBaskets," and "shattered dataclasses," a ton of code is dedicated to
262
+ preserving _abstract_ names for datatypes, such as `Array1DLeavesTotal` and `DatatypeFoldsTotal`. This function well
263
+ illustrates why I put so much effort into preserving the abstract names. (Normally, Python will _immediately_ replace an alias
264
+ name with the type for which it is a proxy.) Because transformed code, even if it has been through 10 transformations (see,
265
+ for example, `mapFolding.syntheticModules.A007822.asynchronousNumba` or its equivalent), ought to still have the abstract
266
+ names, this function gives you the power to change the datatype from numpy to numba and/or from 8-bits to 16-bits merely by
267
+ changing the import statements. You shouldn't need to change any "business" logic.
268
+
269
+ NOTE This will not remove potentially conflicting existing imports from other modules.
270
+ """
271
+ for datatypeConfig in listDatatypeConfigurations:
272
+ ingredientsFunction.imports.removeImportFrom(datatypeConfig.typeModule, None, datatypeConfig.datatypeIdentifier)
273
+ ingredientsFunction.imports.addImportFrom_asStr(datatypeConfig.typeModule, datatypeConfig.typeIdentifier, datatypeConfig.type_asname)
274
+
275
+ return ingredientsFunction, ingredientsModule
@@ -73,20 +73,15 @@ calculations through the strategic application of compiler optimization techniqu
73
73
  """
74
74
 
75
75
  from mapFolding.someAssemblyRequired.infoBooth import (
76
+ default as default,
77
+ defaultA007822 as defaultA007822,
76
78
  dictionaryEstimatesMapFolding as dictionaryEstimatesMapFolding,
77
- identifierCallableSourceDEFAULT as identifierCallableSourceDEFAULT,
78
- identifierCallableSourceDispatcherDEFAULT as identifierCallableSourceDispatcherDEFAULT,
79
- identifierCountingDEFAULT as identifierCountingDEFAULT,
80
- identifierDataclassInstanceDEFAULT as identifierDataclassInstanceDEFAULT,
81
- identifierModuleDataPackingDEFAULT as identifierModuleDataPackingDEFAULT,
82
- identifierModuleSourceAlgorithmDEFAULT as identifierModuleSourceAlgorithmDEFAULT,
83
- logicalPathInfixAlgorithmDEFAULT as logicalPathInfixAlgorithmDEFAULT,
84
- logicalPathInfixDEFAULT as logicalPathInfixDEFAULT,
85
79
  )
86
80
 
87
81
  from mapFolding.someAssemblyRequired._toolIfThis import IfThis as IfThis
88
82
 
89
83
  from mapFolding.someAssemblyRequired._toolkitContainers import (
84
+ DatatypeConfiguration as DatatypeConfiguration,
90
85
  DeReConstructField2ast as DeReConstructField2ast,
91
86
  ShatteredDataclass as ShatteredDataclass,
92
87
  )