mapFolding 0.16.1__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 (78) hide show
  1. easyRun/A000682.py +1 -1
  2. easyRun/A005316.py +2 -3
  3. easyRun/NOTcountingFolds.py +6 -5
  4. easyRun/countFolds.py +1 -1
  5. easyRun/generateAllModules.py +14 -0
  6. easyRun/meanders.py +16 -18
  7. mapFolding/__init__.py +1 -0
  8. mapFolding/_theSSOT.py +3 -2
  9. mapFolding/_theTypes.py +3 -0
  10. mapFolding/algorithms/A086345.py +75 -0
  11. mapFolding/algorithms/matrixMeanders.py +15 -28
  12. mapFolding/algorithms/matrixMeandersBeDry.py +34 -116
  13. mapFolding/algorithms/matrixMeandersNumPy.py +117 -70
  14. mapFolding/algorithms/matrixMeandersPandas.py +113 -130
  15. mapFolding/algorithms/oeisIDbyFormula.py +25 -14
  16. mapFolding/algorithms/symmetricFolds.py +36 -0
  17. mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +26 -12
  18. mapFolding/basecamp.py +152 -323
  19. mapFolding/dataBaskets.py +136 -34
  20. mapFolding/filesystemToolkit.py +4 -32
  21. mapFolding/oeis.py +5 -12
  22. mapFolding/reference/A000682facts.py +785 -1264
  23. mapFolding/reference/A005316facts.py +958 -923
  24. mapFolding/reference/A086345Wu.py +25 -0
  25. mapFolding/reference/matrixMeandersAnalysis/signatures.py +2033 -0
  26. mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +9 -44
  27. mapFolding/someAssemblyRequired/A007822/_asynchronousAnnex.py +51 -0
  28. mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +39 -136
  29. mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +44 -45
  30. mapFolding/someAssemblyRequired/RecipeJob.py +78 -18
  31. mapFolding/someAssemblyRequired/__init__.py +3 -8
  32. mapFolding/someAssemblyRequired/_toolkitContainers.py +32 -3
  33. mapFolding/someAssemblyRequired/infoBooth.py +40 -23
  34. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +75 -154
  35. mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +56 -88
  36. mapFolding/someAssemblyRequired/makingModules_count.py +91 -85
  37. mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +7 -65
  38. mapFolding/someAssemblyRequired/{mapFolding → mapFoldingModules}/makeMapFoldingModules.py +25 -31
  39. mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +14 -13
  40. mapFolding/someAssemblyRequired/toolkitMakeModules.py +10 -10
  41. mapFolding/someAssemblyRequired/toolkitNumba.py +1 -1
  42. mapFolding/someAssemblyRequired/transformationTools.py +17 -19
  43. mapFolding/syntheticModules/A007822/algorithm.py +46 -50
  44. mapFolding/syntheticModules/A007822/asynchronous.py +93 -34
  45. mapFolding/syntheticModules/A007822/initializeState.py +15 -21
  46. mapFolding/syntheticModules/A007822/theorem2.py +21 -21
  47. mapFolding/syntheticModules/A007822/theorem2Numba.py +42 -23
  48. mapFolding/syntheticModules/A007822/theorem2Trimmed.py +21 -21
  49. mapFolding/syntheticModules/countParallelNumba.py +3 -7
  50. mapFolding/syntheticModules/daoOfMapFoldingNumba.py +3 -6
  51. mapFolding/syntheticModules/meanders/bigInt.py +15 -25
  52. mapFolding/syntheticModules/theorem2.py +6 -0
  53. mapFolding/syntheticModules/theorem2Numba.py +26 -2
  54. mapFolding/syntheticModules/theorem2Trimmed.py +6 -0
  55. mapFolding/tests/test_computations.py +1 -1
  56. mapFolding/zCuzDocStoopid/makeDocstrings.py +2 -0
  57. {mapfolding-0.16.1.dist-info → mapfolding-0.16.4.dist-info}/METADATA +4 -1
  58. mapfolding-0.16.4.dist-info/RECORD +106 -0
  59. mapFolding/_dataPacking.py +0 -68
  60. mapFolding/reference/meandersDumpingGround/A005316intOptimized.py +0 -122
  61. mapFolding/reference/meandersDumpingGround/A005316optimized128bit.py +0 -79
  62. mapFolding/reference/meandersDumpingGround/matrixMeandersBaseline.py +0 -65
  63. mapFolding/reference/meandersDumpingGround/matrixMeandersBaselineAnnex.py +0 -84
  64. mapFolding/reference/meandersDumpingGround/matrixMeandersSimpleQueue.py +0 -90
  65. mapFolding/syntheticModules/A007822/algorithmNumba.py +0 -94
  66. mapFolding/syntheticModules/A007822/asynchronousAnnex.py +0 -66
  67. mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +0 -85
  68. mapFolding/syntheticModules/A007822/asynchronousNumba.py +0 -52
  69. mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +0 -53
  70. mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +0 -47
  71. mapFolding/syntheticModules/dataPacking.py +0 -28
  72. mapFolding/syntheticModules/dataPackingA007822.py +0 -92
  73. mapfolding-0.16.1.dist-info/RECORD +0 -114
  74. /mapFolding/someAssemblyRequired/{mapFolding → mapFoldingModules}/__init__.py +0 -0
  75. {mapfolding-0.16.1.dist-info → mapfolding-0.16.4.dist-info}/WHEEL +0 -0
  76. {mapfolding-0.16.1.dist-info → mapfolding-0.16.4.dist-info}/entry_points.txt +0 -0
  77. {mapfolding-0.16.1.dist-info → mapfolding-0.16.4.dist-info}/licenses/LICENSE +0 -0
  78. {mapfolding-0.16.1.dist-info → mapfolding-0.16.4.dist-info}/top_level.txt +0 -0
@@ -1,54 +1,19 @@
1
1
  from astToolkit import extractFunctionDef, Make # noqa: D100
2
2
  from hunterMakesPy import raiseIfNone
3
- from mapFolding.someAssemblyRequired import (
4
- identifierCallableSourceDEFAULT, identifierCallableSourceDispatcherDEFAULT, identifierCountingDEFAULT,
5
- identifierDataclassInstanceDEFAULT, logicalPathInfixDEFAULT)
3
+ from mapFolding.someAssemblyRequired import defaultA007822
4
+ from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule
6
5
  import ast
7
6
 
8
- identifierDataclass: str = identifierDataclassInstanceDEFAULT
9
- identifierCounting: str = identifierCountingDEFAULT
10
- logicalPathInfixA007822: str = logicalPathInfixDEFAULT + '.A007822'
11
- sourceCallableDispatcherA007822: str = identifierCallableSourceDispatcherDEFAULT
12
- sourceCallableIdentifierA007822: str = identifierCallableSourceDEFAULT
7
+ FunctionDef_filterAsymmetricFolds: ast.FunctionDef = raiseIfNone(extractFunctionDef(getModule(logicalPathInfix='algorithms', identifierModule='symmetricFolds'), defaultA007822['function']['filterAsymmetricFolds']))
13
8
 
14
- identifier_filterAsymmetricFolds = 'filterAsymmetricFolds'
15
-
16
- ImaString = f"""
17
- def {identifier_filterAsymmetricFolds}({identifierDataclass}: MapFoldingState) -> MapFoldingState:
18
- {identifierDataclass}.indexLeaf = 0
19
- leafConnectee = 0
20
- while leafConnectee < {identifierDataclass}.leavesTotal + 1:
21
- leafNumber = int({identifierDataclass}.leafBelow[{identifierDataclass}.indexLeaf])
22
- {identifierDataclass}.leafComparison[leafConnectee] = (leafNumber - {identifierDataclass}.indexLeaf + {identifierDataclass}.leavesTotal) % {identifierDataclass}.leavesTotal
23
- {identifierDataclass}.indexLeaf = leafNumber
24
- leafConnectee += 1
25
-
26
- indexInMiddle = {identifierDataclass}.leavesTotal // 2
27
- {identifierDataclass}.indexMiniGap = 0
28
- while {identifierDataclass}.indexMiniGap < {identifierDataclass}.leavesTotal + 1:
29
- ImaSymmetricFold = True
30
- leafConnectee = 0
31
- while leafConnectee < indexInMiddle:
32
- if {identifierDataclass}.leafComparison[({identifierDataclass}.indexMiniGap + leafConnectee) % ({identifierDataclass}.leavesTotal + 1)] != {identifierDataclass}.leafComparison[({identifierDataclass}.indexMiniGap + {identifierDataclass}.leavesTotal - 1 - leafConnectee) % ({identifierDataclass}.leavesTotal + 1)]:
33
- ImaSymmetricFold = False
34
- break
35
- leafConnectee += 1
36
- {identifierDataclass}.{identifierCounting} += ImaSymmetricFold
37
- {identifierDataclass}.indexMiniGap += 1
38
-
39
- return {identifierDataclass}
40
- """ # noqa: E501
41
-
42
- FunctionDef_filterAsymmetricFolds: ast.FunctionDef = raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_filterAsymmetricFolds))
43
- del ImaString
44
-
45
- ImaString = f"{identifierDataclass} = {identifier_filterAsymmetricFolds}({identifierDataclass})"
9
+ ImaString: str = f"{defaultA007822['variable']['stateInstance']} = {defaultA007822['function']['filterAsymmetricFolds']}({defaultA007822['variable']['stateInstance']})"
46
10
  A007822incrementCount = ast.parse(ImaString).body[0]
47
11
  del ImaString
48
12
 
49
- ImaString = f'{identifierDataclass}.{identifierCounting} = ({identifierDataclass}.{identifierCounting} + 1) // 2'
50
- A007822adjustFoldsTotal = ast.parse(ImaString).body[0]
13
+ ImaString = f'{defaultA007822['variable']['stateInstance']}.{defaultA007822['variable']['counting']} = ({defaultA007822['variable']['stateInstance']}.{defaultA007822['variable']['counting']} + 1) // 2'
14
+ A007822adjustFoldsTotal: ast.stmt = ast.parse(ImaString).body[0]
51
15
  del ImaString
52
16
 
53
- astExprCall_filterAsymmetricFoldsDataclass: ast.Expr = Make.Expr(Make.Call(Make.Name(identifier_filterAsymmetricFolds), listParameters=[Make.Attribute(Make.Name(identifierDataclass), 'leafBelow')]))
54
- astExprCall_filterAsymmetricFoldsLeafBelow: ast.Expr = Make.Expr(Make.Call(Make.Name(identifier_filterAsymmetricFolds), listParameters=[Make.Name('leafBelow')]))
17
+ ExprCallFilterAsymmetricFolds_leafBelow: ast.Expr = Make.Expr(Make.Call(Make.Name(defaultA007822['function']['filterAsymmetricFolds']), listParameters=[Make.Name('leafBelow')]))
18
+ ExprCallFilterAsymmetricFoldsState: ast.Expr = Make.Expr(Make.Call(Make.Name(defaultA007822['function']['filterAsymmetricFolds']), listParameters=[Make.Name(defaultA007822['variable']['stateInstance'])]))
19
+ ExprCallFilterAsymmetricFoldsStateDot_leafBelow: ast.Expr = Make.Expr(Make.Call(Make.Name(defaultA007822['function']['filterAsymmetricFolds']), listParameters=[Make.Attribute(Make.Name(defaultA007822['variable']['stateInstance']), 'leafBelow')]))
@@ -0,0 +1,51 @@
1
+ # NOTE The real module is generated from this incomplete module. Comments are not preserved.
2
+ # ruff: noqa: PLW0603
3
+ from copy import deepcopy
4
+ from mapFolding import DatatypeFoldsTotal
5
+ from mapFolding.dataBaskets import SymmetricFoldsState
6
+ from queue import Queue
7
+ from threading import Lock, Thread
8
+
9
+ listThreads: list[Thread] = []
10
+ queueFutures: Queue[SymmetricFoldsState] = Queue()
11
+ symmetricFoldsTotal: int = 0
12
+ LOCKsymmetricFoldsTotal = Lock()
13
+ # TODO There isn't a better way to do this?
14
+ STOPsignal = object()
15
+
16
+ def initializeConcurrencyManager(maxWorkers: int, symmetricFolds: int=0) -> None:
17
+ global listThreads, symmetricFoldsTotal, queueFutures
18
+ listThreads = []
19
+ queueFutures = Queue()
20
+ symmetricFoldsTotal = symmetricFolds
21
+
22
+ indexThread = 0
23
+ while indexThread < maxWorkers:
24
+ thread = Thread(target=_threadDoesSomething, name=f"thread{indexThread}", daemon=True)
25
+ thread.start()
26
+ listThreads.append(thread)
27
+ indexThread += 1
28
+
29
+ def _threadDoesSomething() -> None:
30
+ global symmetricFoldsTotal
31
+ while True:
32
+ state = queueFutures.get()
33
+ if state is STOPsignal:
34
+ break
35
+ state = _filterAsymmetricFolds(state)
36
+ with LOCKsymmetricFoldsTotal:
37
+ symmetricFoldsTotal += state.groupsOfFolds
38
+
39
+ def _filterAsymmetricFolds(state: SymmetricFoldsState) -> SymmetricFoldsState:
40
+ """Add real function during generation; the signature is here to preview its interactions with the module."""
41
+ return state
42
+
43
+ def filterAsymmetricFolds(state: SymmetricFoldsState) -> None:
44
+ queueFutures.put_nowait(deepcopy(state))
45
+
46
+ def getSymmetricFoldsTotal() -> DatatypeFoldsTotal:
47
+ for _thread in listThreads:
48
+ queueFutures.put(STOPsignal) # pyright: ignore[reportArgumentType]
49
+ for thread in listThreads:
50
+ thread.join()
51
+ return symmetricFoldsTotal
@@ -1,30 +1,23 @@
1
1
  """addSymmetryCheckAsynchronous."""
2
- from astToolkit import Be, extractFunctionDef, Grab, Make, NodeChanger, NodeTourist, parsePathFilename2astModule, Then
2
+ from astToolkit import Be, Grab, identifierDotAttribute, LedgerOfImports, Make, NodeChanger, NodeTourist, Then
3
3
  from hunterMakesPy import raiseIfNone
4
4
  from mapFolding import packageSettings
5
- from mapFolding.someAssemblyRequired import IfThis, logicalPathInfixAlgorithmDEFAULT
6
- from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import (
7
- A007822adjustFoldsTotal, astExprCall_filterAsymmetricFoldsDataclass, identifier_filterAsymmetricFolds,
8
- identifierCounting, identifierDataclass, logicalPathInfixA007822, sourceCallableDispatcherA007822,
9
- sourceCallableIdentifierA007822)
10
- from mapFolding.someAssemblyRequired.makingModules_count import makeTheorem2, numbaOnTheorem2, trimTheorem2
5
+ from mapFolding.someAssemblyRequired import defaultA007822, IfThis
6
+ from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import ExprCallFilterAsymmetricFoldsState
11
7
  from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename, write_astModule
12
- from os import PathLike
13
8
  from pathlib import PurePath
14
9
  import ast
15
10
 
16
- identifier_getAsymmetricFoldsTotal = 'getAsymmetricFoldsTotal'
17
- identifier_initializeConcurrencyManager = 'initializeConcurrencyManager'
18
- identifier_processCompletedFutures = '_processCompletedFutures'
11
+ # TODO figure out asynchronous + numba.
19
12
 
20
- astExprCall_initializeConcurrencyManager: ast.Expr = Make.Expr(Make.Call(Make.Name(identifier_initializeConcurrencyManager)))
13
+ astExprCall_initializeConcurrencyManager: ast.Expr = Make.Expr(Make.Call(Make.Name(defaultA007822['function']['initializeConcurrencyManager']), listParameters=[Make.Name('maxWorkers')]))
21
14
  AssignTotal2CountingIdentifier: ast.Assign = Make.Assign(
22
- [Make.Attribute(Make.Name(identifierDataclass), identifierCounting, context=Make.Store())]
23
- , value=Make.Call(Make.Name(identifier_getAsymmetricFoldsTotal))
15
+ [Make.Attribute(Make.Name(defaultA007822['variable']['stateInstance']), defaultA007822['variable']['counting'], context=Make.Store())]
16
+ , value=Make.Call(Make.Name(defaultA007822['function']['getSymmetricFoldsTotal']))
24
17
  )
25
18
 
26
- def addSymmetryCheckAsynchronous(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
27
- """Add symmetry check to the counting function.
19
+ def addSymmetryCheckAsynchronous(astModule: ast.Module, identifierModule: str, identifierCallable: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
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.
28
21
 
29
22
  To do asynchronous filtering, a few things must happen.
30
23
  1. When the algorithm finds a `groupOfFolds`, the call to `filterAsymmetricFolds` must be non-blocking.
@@ -39,16 +32,13 @@ def addSymmetryCheckAsynchronous(astModule: ast.Module, moduleIdentifier: str, c
39
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.
40
33
  """
41
34
  astFunctionDef_count: ast.FunctionDef = raiseIfNone(NodeTourist(
42
- findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableIdentifierA007822))
35
+ findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(defaultA007822['function']['counting']))
43
36
  , doThat = Then.extractIt
44
37
  ).captureLastMatch(astModule))
45
38
 
46
- NodeChanger(Be.Return, Then.insertThisAbove([A007822adjustFoldsTotal])).visit(astFunctionDef_count)
47
-
48
39
  NodeChanger(
49
- findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(identifierDataclass, identifierCounting))
50
- , doThat=Then.replaceWith(astExprCall_filterAsymmetricFoldsDataclass)
51
- ).visit(astFunctionDef_count)
40
+ Be.Assign.valueIs(IfThis.isCallIdentifier(defaultA007822['function']['filterAsymmetricFolds']))
41
+ , Then.replaceWith(ExprCallFilterAsymmetricFoldsState)).visit(astFunctionDef_count)
52
42
 
53
43
  NodeChanger(
54
44
  findThis=Be.While.testIs(IfThis.isCallIdentifier('activeLeafGreaterThan0'))
@@ -56,9 +46,10 @@ def addSymmetryCheckAsynchronous(astModule: ast.Module, moduleIdentifier: str, c
56
46
  ).visit(astFunctionDef_count)
57
47
 
58
48
  NodeChanger(
59
- findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableIdentifierA007822))
49
+ findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(defaultA007822['function']['counting']))
60
50
  , doThat=Then.replaceWith(astFunctionDef_count)
61
51
  ).visit(astModule)
52
+ del astFunctionDef_count
62
53
 
63
54
  astFunctionDef_doTheNeedful: ast.FunctionDef = raiseIfNone(NodeTourist(
64
55
  findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableDispatcher))
@@ -66,132 +57,44 @@ def addSymmetryCheckAsynchronous(astModule: ast.Module, moduleIdentifier: str, c
66
57
  ).captureLastMatch(astModule))
67
58
 
68
59
  astFunctionDef_doTheNeedful.body.insert(0, astExprCall_initializeConcurrencyManager)
60
+ astFunctionDef_doTheNeedful.args.args.append(Make.arg('maxWorkers', Make.Name('int')))
69
61
 
70
62
  NodeChanger(
71
63
  findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableDispatcher))
72
64
  , doThat=Then.replaceWith(astFunctionDef_doTheNeedful)
73
65
  ).visit(astModule)
66
+ del astFunctionDef_doTheNeedful
74
67
 
75
- astImportFrom = ast.ImportFrom(f'{packageSettings.identifierPackage}.{logicalPathInfix}.{moduleIdentifier}Annex'
76
- , [Make.alias(identifier_filterAsymmetricFolds), Make.alias(identifier_getAsymmetricFoldsTotal), Make.alias(identifier_initializeConcurrencyManager)], 0)
77
-
78
- astModule.body.insert(0, astImportFrom)
79
-
80
- pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
81
- pathFilenameAnnex: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier + 'Annex')
68
+ imports = LedgerOfImports(astModule)
69
+ removeImports = NodeChanger(IfThis.isAnyOf(Be.ImportFrom, Be.Import), Then.removeIt)
70
+ removeImports.visit(astModule)
82
71
 
83
- write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
84
- del astModule
85
- # ----------------- Ingredients Module Annex ------------------------------------------------------------------------------
86
- ImaString = """from concurrent.futures import Future as ConcurrentFuture, ThreadPoolExecutor
87
- from hunterMakesPy import raiseIfNone
88
- from mapFolding import Array1DLeavesTotal
89
- from queue import Empty, Queue
90
- from threading import Thread
91
- import numpy"""
92
-
93
- astModule = ast.parse(ImaString)
94
- del ImaString
95
-
96
- ImaString = f"""concurrencyManager = None
97
- {identifierCounting}Total: int = 0
98
- processingThread = None
99
- queueFutures: Queue[ConcurrentFuture[int]] = Queue()
100
- """
101
- astModule.body.extend(ast.parse(ImaString).body)
102
- del ImaString
103
-
104
- ImaString = f"""def {identifier_initializeConcurrencyManager}(maxWorkers: int | None = None, {identifierCounting}: int = 0) -> None:
105
- global concurrencyManager, queueFutures, {identifierCounting}Total, processingThread
106
- concurrencyManager = ThreadPoolExecutor(max_workers=maxWorkers)
107
- queueFutures = Queue()
108
- {identifierCounting}Total = {identifierCounting}
109
- processingThread = Thread(target={identifier_processCompletedFutures})
110
- processingThread.start()
111
- """
112
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_initializeConcurrencyManager)))
113
- del ImaString
114
-
115
- ImaString = f"""def {identifier_processCompletedFutures}() -> None:
116
- global queueFutures, {identifierCounting}Total
117
- while True:
118
- try:
119
- claimTicket: ConcurrentFuture[int] = queueFutures.get(timeout=1)
120
- if claimTicket is None:
121
- break
122
- {identifierCounting}Total += claimTicket.result()
123
- except Empty:
124
- continue
125
- """
126
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_processCompletedFutures)))
127
- del ImaString
128
-
129
- ImaString = f"""def _{identifier_filterAsymmetricFolds}(leafBelow: Array1DLeavesTotal) -> int:
130
- {identifierCounting} = 0
131
- leafComparison: Array1DLeavesTotal = numpy.zeros_like(leafBelow)
132
- leavesTotal = leafBelow.size - 1
133
-
134
- indexLeaf = 0
135
- leafConnectee = 0
136
- while leafConnectee < leavesTotal + 1:
137
- leafNumber = int(leafBelow[indexLeaf])
138
- leafComparison[leafConnectee] = (leafNumber - indexLeaf + leavesTotal) % leavesTotal
139
- indexLeaf = leafNumber
140
- leafConnectee += 1
141
-
142
- indexInMiddle = leavesTotal // 2
143
- indexDistance = 0
144
- while indexDistance < leavesTotal + 1:
145
- ImaSymmetricFold = True
146
- leafConnectee = 0
147
- while leafConnectee < indexInMiddle:
148
- if leafComparison[(indexDistance + leafConnectee) % (leavesTotal + 1)] != leafComparison[(indexDistance + leavesTotal - 1 - leafConnectee) % (leavesTotal + 1)]:
149
- ImaSymmetricFold = False
150
- break
151
- leafConnectee += 1
152
- {identifierCounting} += ImaSymmetricFold
153
- indexDistance += 1
154
- return {identifierCounting}
155
- """
156
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), f'_{identifier_filterAsymmetricFolds}')))
157
- del ImaString
72
+ astModuleAsynchronousAnnex: ast.Module = getModule(logicalPathInfix=defaultA007822['logicalPath']['assembly'], identifierModule='_asynchronousAnnex')
73
+ imports.walkThis(astModuleAsynchronousAnnex)
74
+ removeImports.visit(astModuleAsynchronousAnnex)
158
75
 
159
- ImaString = f"""
160
- def {identifier_filterAsymmetricFolds}(leafBelow: Array1DLeavesTotal) -> None:
161
- global concurrencyManager, queueFutures
162
- queueFutures.put_nowait(raiseIfNone(concurrencyManager).submit(_{identifier_filterAsymmetricFolds}, leafBelow.copy()))
163
- """
164
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_filterAsymmetricFolds)))
165
- del ImaString
166
-
167
- ImaString = f"""
168
- def {identifier_getAsymmetricFoldsTotal}() -> int:
169
- global concurrencyManager, queueFutures, processingThread
170
- raiseIfNone(concurrencyManager).shutdown(wait=True)
171
- queueFutures.put(None)
172
- raiseIfNone(processingThread).join()
173
- return {identifierCounting}Total
174
- """
175
- astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_getAsymmetricFoldsTotal)))
176
- del ImaString
177
-
178
- write_astModule(astModule, pathFilenameAnnex, packageSettings.identifierPackage)
76
+ NodeChanger(Be.FunctionDef.nameIs(IfThis.isIdentifier(defaultA007822['function']['filterAsymmetricFolds']))
77
+ , Grab.nameAttribute(Then.replaceWith(f"_{defaultA007822['function']['filterAsymmetricFolds']}"))
78
+ ).visit(astModule)
179
79
 
180
- return pathFilename
80
+ NodeChanger(Be.FunctionDef.nameIs(IfThis.isIdentifier(f"_{defaultA007822['function']['filterAsymmetricFolds']}"))
81
+ , Then.removeIt
82
+ ).visit(astModuleAsynchronousAnnex)
181
83
 
182
- def _makeA007822AsynchronousModules() -> None:
84
+ astModule.body = [*imports.makeList_ast(), *astModuleAsynchronousAnnex.body, *astModule.body]
183
85
 
184
- astModule = getModule(logicalPathInfix=logicalPathInfixAlgorithmDEFAULT)
185
- pathFilename = addSymmetryCheckAsynchronous(astModule, 'asynchronous', None, logicalPathInfixA007822, sourceCallableDispatcherA007822)
86
+ pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule)
186
87
 
187
- astModule = getModule(logicalPathInfix=logicalPathInfixA007822, moduleIdentifier='asynchronous')
188
- pathFilename = makeTheorem2(astModule, 'asynchronousTheorem2', None, logicalPathInfixA007822, None)
88
+ write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
189
89
 
190
- astModule = parsePathFilename2astModule(pathFilename)
191
- pathFilename = trimTheorem2(astModule, 'asynchronousTrimmed', None, logicalPathInfixA007822, None)
90
+ return pathFilename
192
91
 
193
- astModule = parsePathFilename2astModule(pathFilename)
194
- pathFilename = numbaOnTheorem2(astModule, 'asynchronousNumba', None, logicalPathInfixA007822, None)
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'])
195
97
 
196
98
  if __name__ == '__main__':
197
- _makeA007822AsynchronousModules()
99
+ makeA007822AsynchronousModules()
100
+
@@ -1,74 +1,73 @@
1
1
  """addSymmetryCheck."""
2
- from astToolkit import Be, 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, identifierCountingDEFAULT, identifierDataclassInstanceDEFAULT, IfThis)
6
+ from mapFolding.someAssemblyRequired import default, defaultA007822, IfThis
7
7
  from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import (
8
- A007822adjustFoldsTotal, A007822incrementCount, FunctionDef_filterAsymmetricFolds, logicalPathInfixA007822,
9
- sourceCallableDispatcherA007822, sourceCallableIdentifierA007822)
10
- from mapFolding.someAssemblyRequired.makingModules_count import (
11
- makeDaoOfMapFoldingNumba, makeTheorem2, numbaOnTheorem2, trimTheorem2)
12
- from mapFolding.someAssemblyRequired.makingModules_doTheNeedful import makeInitializeState, makeUnRePackDataclass
13
- from mapFolding.someAssemblyRequired.toolkitMakeModules import (
14
- getLogicalPath, getModule, getPathFilename, write_astModule)
15
- 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
16
12
  from pathlib import PurePath
17
13
  import ast
18
14
 
19
- def addSymmetryCheck(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
20
- """Add logic to check for symmetric folds."""
21
- # NOTE HEY HEY! Are you trying to figure out why there is more than one copy of `filterAsymmetricFolds`? See the TODO NOTE, below.
15
+ def addSymmetryCheck(astModule: ast.Module, identifierModule: str, identifierCallable: str | None = None, logicalPathInfix: identifierDotAttribute | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
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)
22
20
 
23
- astFunctionDef_count: ast.FunctionDef = raiseIfNone(NodeTourist(
24
- 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']))
25
27
  , doThat = Then.extractIt
26
28
  ).captureLastMatch(astModule))
27
- astFunctionDef_count.name = sourceCallableIdentifierA007822
29
+ FunctionDef_count.name = identifierCallable or defaultA007822['function']['counting']
28
30
 
29
- NodeChanger(Be.Return, Then.insertThisAbove([A007822adjustFoldsTotal])).visit(astFunctionDef_count)
31
+ NodeChanger(Be.Return, Then.insertThisAbove([A007822adjustFoldsTotal])).visit(FunctionDef_count)
30
32
 
31
33
  NodeChanger(
32
- findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(identifierDataclassInstanceDEFAULT, identifierCountingDEFAULT))
34
+ findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(default['variable']['stateInstance'], default['variable']['counting']))
33
35
  , doThat=Then.replaceWith(A007822incrementCount)
34
- ).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')
35
41
 
36
- # TODO NOTE This will insert a copy of `filterAsymmetricFolds` for each `ast.ImportFrom` in the source module. Find or make a
37
- # system to replace the `Ingredients` paradigm.
38
- NodeChanger(Be.ImportFrom, Then.insertThisBelow([FunctionDef_filterAsymmetricFolds])).visit(astModule)
42
+ astModule.body = [*imports.makeList_ast(), FunctionDef_filterAsymmetricFolds, *astModule.body]
39
43
 
40
- pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
44
+ pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, identifierModule)
41
45
 
42
46
  write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
43
47
 
44
48
  return pathFilename
45
49
 
46
- def _makeA007822Modules() -> None:
47
- astModule = getModule(logicalPathInfix='algorithms')
48
- pathFilename = addSymmetryCheck(astModule, 'algorithm', None, logicalPathInfixA007822, None)
49
-
50
- astModule = getModule(logicalPathInfix=logicalPathInfixA007822, moduleIdentifier='algorithm')
51
- pathFilename: PurePath = makeDaoOfMapFoldingNumba(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)
52
55
 
53
- # 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)
54
59
 
55
- astModule = getModule(logicalPathInfix=logicalPathInfixA007822, moduleIdentifier='algorithm')
56
- makeInitializeState(astModule, 'initializeState', 'transitionOnGroupsOfFolds', logicalPathInfixA007822)
57
-
58
- astModule = getModule(logicalPathInfix=logicalPathInfixA007822, moduleIdentifier='algorithm')
59
- pathFilename = makeTheorem2(astModule, 'theorem2', None, logicalPathInfixA007822, None)
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'])
60
63
 
61
64
  astModule = parsePathFilename2astModule(pathFilename)
62
- pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', None, logicalPathInfixA007822, None)
65
+ pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', defaultA007822['function']['counting']
66
+ , defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
63
67
 
64
68
  astModule = parsePathFilename2astModule(pathFilename)
65
- pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', None, logicalPathInfixA007822, None)
66
- # TODO from mapFolding.syntheticModules.dataPackingA007822 import unRePackDataclass
67
- # @unRePackDataclass
68
-
69
- # TODO Make this decorator.
70
- # astImportFrom: ast.ImportFrom = Make.ImportFrom(getLogicalPath(packageSettings.identifierPackage, logicalPathInfixA007822, 'theorem2Numba'), list_alias=[Make.alias(sourceCallableIdentifierA007822)])
71
- # makeUnRePackDataclass(astImportFrom, 'dataPackingA007822')
69
+ pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', defaultA007822['function']['counting']
70
+ , defaultA007822['logicalPath']['synthetic'], defaultA007822['function']['dispatcher'])
72
71
 
73
72
  if __name__ == '__main__':
74
- _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