mapFolding 0.13.0__tar.gz → 0.13.1__tar.gz

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 (60) hide show
  1. {mapfolding-0.13.0 → mapfolding-0.13.1}/PKG-INFO +1 -1
  2. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/RecipeJob.py +3 -4
  3. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/_toolkitContainers.py +3 -3
  4. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/makeAllModules.py +2 -2
  5. mapfolding-0.13.1/mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +196 -0
  6. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/toolkitNumba.py +9 -7
  7. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding.egg-info/PKG-INFO +1 -1
  8. {mapfolding-0.13.0 → mapfolding-0.13.1}/pyproject.toml +1 -1
  9. mapfolding-0.13.0/mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +0 -256
  10. {mapfolding-0.13.0 → mapfolding-0.13.1}/LICENSE +0 -0
  11. {mapfolding-0.13.0 → mapfolding-0.13.1}/README.md +0 -0
  12. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/__init__.py +0 -0
  13. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/_theSSOT.py +0 -0
  14. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/_theTypes.py +0 -0
  15. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/basecamp.py +0 -0
  16. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/beDRY.py +0 -0
  17. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/daoOfMapFolding.py +0 -0
  18. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/dataBaskets.py +0 -0
  19. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/filesystemToolkit.py +0 -0
  20. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/oeis.py +0 -0
  21. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/py.typed +0 -0
  22. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/__init__.py +0 -0
  23. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/flattened.py +0 -0
  24. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/hunterNumba.py +0 -0
  25. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/irvineJavaPort.py +0 -0
  26. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/jaxCount.py +0 -0
  27. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/jobsCompleted/[2x19]/p2x19.py +0 -0
  28. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/jobsCompleted/__init__.py +0 -0
  29. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/jobsCompleted/p2x19/p2x19.py +0 -0
  30. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/lunnonNumpy.py +0 -0
  31. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/lunnonWhile.py +0 -0
  32. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/rotatedEntryPoint.py +0 -0
  33. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/reference/total_countPlus1vsPlusN.py +0 -0
  34. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/__init__.py +0 -0
  35. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/_toolIfThis.py +0 -0
  36. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/getLLVMforNoReason.py +0 -0
  37. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/infoBooth.py +0 -0
  38. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +0 -0
  39. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/someAssemblyRequired/transformationTools.py +0 -0
  40. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/syntheticModules/__init__.py +0 -0
  41. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/syntheticModules/countParallel.py +0 -0
  42. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/syntheticModules/daoOfMapFolding.py +0 -0
  43. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/syntheticModules/dataPacking.py +0 -0
  44. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/syntheticModules/initializeCount.py +0 -0
  45. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/syntheticModules/theorem2.py +0 -0
  46. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/syntheticModules/theorem2Numba.py +0 -0
  47. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/syntheticModules/theorem2Trimmed.py +0 -0
  48. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/tests/__init__.py +0 -0
  49. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/tests/conftest.py +0 -0
  50. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/tests/test_computations.py +0 -0
  51. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/tests/test_filesystem.py +0 -0
  52. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/tests/test_oeis.py +0 -0
  53. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/tests/test_other.py +0 -0
  54. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding/tests/test_tasks.py +0 -0
  55. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding.egg-info/SOURCES.txt +0 -0
  56. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding.egg-info/dependency_links.txt +0 -0
  57. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding.egg-info/entry_points.txt +0 -0
  58. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding.egg-info/requires.txt +0 -0
  59. {mapfolding-0.13.0 → mapfolding-0.13.1}/mapFolding.egg-info/top_level.txt +0 -0
  60. {mapfolding-0.13.0 → mapfolding-0.13.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapFolding
3
- Version: 0.13.0
3
+ Version: 0.13.1
4
4
  Summary: Map folding algorithm with code transformation framework for optimizing numerical computations.
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
@@ -9,7 +9,6 @@ from mapFolding import (
9
9
  from mapFolding.someAssemblyRequired import dataclassInstanceIdentifierDEFAULT, ShatteredDataclass
10
10
  from mapFolding.someAssemblyRequired.transformationTools import shatter_dataclassesDOTdataclass
11
11
  from pathlib import Path, PurePosixPath
12
- from typing import TypeAlias
13
12
  import dataclasses
14
13
 
15
14
  @dataclasses.dataclass
@@ -134,11 +133,11 @@ class RecipeJobTheorem2:
134
133
  """Logical path to target dataclass module."""
135
134
 
136
135
  # Datatypes ------------------------------------------
137
- DatatypeFoldsTotal: TypeAlias = TheDatatypeFoldsTotal
136
+ type DatatypeFoldsTotal = TheDatatypeFoldsTotal
138
137
  """Type alias for datatype linked to the magnitude of `foldsTotal`."""
139
- DatatypeElephino: TypeAlias = TheDatatypeElephino
138
+ type DatatypeElephino = TheDatatypeElephino
140
139
  """Type alias for intermediate computation datatype."""
141
- DatatypeLeavesTotal: TypeAlias = TheDatatypeLeavesTotal
140
+ type DatatypeLeavesTotal = TheDatatypeLeavesTotal
142
141
  """Type alias for datatype linked to the magnitude of `leavesTotal`."""
143
142
 
144
143
  def _makePathFilename(self, pathRoot: PurePosixPath | None = None, logicalPathINFIX: identifierDotAttribute | None = None, filenameStem: str | None = None, fileExtension: str | None = None) -> PurePosixPath:
@@ -217,10 +217,10 @@ class DeReConstructField2ast:
217
217
  self.ast_keyword_field__field = Make.keyword(self.name, self.astName)
218
218
  self.ast_nameDOTname = Make.Attribute(Make.Name(dataclassesDOTdataclassInstanceIdentifier), self.name)
219
219
 
220
- self.astAnnotation = raiseIfNone(NodeTourist[ast.AnnAssign, ast.Name | None](
220
+ self.astAnnotation = cast('ast.Name', raiseIfNone(NodeTourist(
221
221
  findThis = Be.AnnAssign.targetIs(IfThis.isNameIdentifier(self.name))
222
- , doThat = Then.extractIt(cast("Callable[[ast.AnnAssign], ast.Name | None]", DOT.annotation))
223
- ).captureLastMatch(dataclassClassDef))
222
+ , doThat = Then.extractIt(DOT.annotation)
223
+ ).captureLastMatch(dataclassClassDef)))
224
224
 
225
225
  self.ast_argAnnotated = Make.arg(self.name, self.astAnnotation)
226
226
 
@@ -299,7 +299,7 @@ def makeDaoOfMapFolding(astModule: ast.Module, moduleIdentifier: str, callableId
299
299
  ingredientsFunctionDispatcher.imports.update(shatteredDataclass.imports)
300
300
  targetCallableIdentifier = ingredientsFunction.astFunctionDef.name
301
301
  ingredientsFunctionDispatcher = unpackDataclassCallFunctionRepackDataclass(ingredientsFunctionDispatcher, targetCallableIdentifier, shatteredDataclass)
302
- astTuple: ast.Tuple = cast('ast.Tuple', raiseIfNone(NodeTourist[ast.Return, ast.expr | None](Be.Return.valueIs(Be.Tuple)
302
+ astTuple: ast.Tuple = cast('ast.Tuple', raiseIfNone(NodeTourist(Be.Return.valueIs(Be.Tuple)
303
303
  , doThat=Then.extractIt(DOT.value)).captureLastMatch(ingredientsFunction.astFunctionDef)))
304
304
  astTuple.ctx = ast.Store()
305
305
 
@@ -743,7 +743,7 @@ def makeUnRePackDataclass(astImportFrom: ast.ImportFrom) -> None:
743
743
  targetCallableIdentifier = astImportFrom.names[0].name
744
744
  ingredientsFunction = raiseIfNone(unpackDataclassCallFunctionRepackDataclass(ingredientsFunction, targetCallableIdentifier, shatteredDataclass))
745
745
  targetFunctionDef: ast.FunctionDef = raiseIfNone(extractFunctionDef(parseLogicalPath2astModule(raiseIfNone(astImportFrom.module)), targetCallableIdentifier))
746
- astTuple: ast.Tuple = cast('ast.Tuple', raiseIfNone(NodeTourist[ast.Return, ast.expr | None](Be.Return.valueIs(Be.Tuple)
746
+ astTuple: ast.Tuple = cast('ast.Tuple', raiseIfNone(NodeTourist(Be.Return.valueIs(Be.Tuple)
747
747
  , doThat=Then.extractIt(DOT.value)).captureLastMatch(targetFunctionDef)))
748
748
  astTuple.ctx = ast.Store()
749
749
 
@@ -0,0 +1,196 @@
1
+ """codon.
2
+
3
+ https://docs.exaloop.io/start/install/
4
+ """
5
+
6
+ from astToolkit import (
7
+ Be, DOT, extractFunctionDef, Grab, identifierDotAttribute, IngredientsFunction, IngredientsModule, Make, NodeChanger,
8
+ NodeTourist, Then)
9
+ from astToolkit.transformationTools import removeUnusedParameters, write_astModule
10
+ from hunterMakesPy import autoDecodingRLE, raiseIfNone
11
+ from mapFolding import getPathFilenameFoldsTotal, MapFoldingState
12
+ from mapFolding.someAssemblyRequired import IfThis
13
+ from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2
14
+ from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
15
+ from pathlib import Path, PurePosixPath
16
+ from typing import cast, NamedTuple
17
+ import ast
18
+ import subprocess
19
+ import sys
20
+
21
+ class DatatypeConfiguration(NamedTuple):
22
+ """Configuration for mapping framework datatypes to compiled datatypes.
23
+
24
+ This configuration class defines how abstract datatypes used in the map folding framework should be replaced with compiled
25
+ datatypes during code generation. Each configuration specifies the source module, target type name, and optional import
26
+ alias for the transformation.
27
+
28
+ Attributes
29
+ ----------
30
+ datatypeIdentifier : str
31
+ Framework datatype identifier to be replaced.
32
+ typeModule : identifierDotAttribute
33
+ Module containing the target datatype (e.g., 'codon', 'numpy').
34
+ typeIdentifier : str
35
+ Concrete type name in the target module.
36
+ type_asname : str | None = None
37
+ Optional import alias for the type.
38
+ """
39
+
40
+ datatypeIdentifier: str
41
+ typeModule: identifierDotAttribute
42
+ typeIdentifier: str
43
+ type_asname: str | None = None
44
+
45
+ # TODO replace with dynamic system. Probably use `Final` in the dataclass.
46
+ listIdentifiersStaticValuesHARDCODED: list[str] = ['dimensionsTotal', 'leavesTotal']
47
+
48
+ listDatatypeConfigurations: list[DatatypeConfiguration] = [
49
+ DatatypeConfiguration(datatypeIdentifier='DatatypeLeavesTotal', typeModule='numpy', typeIdentifier='uint16', type_asname='DatatypeLeavesTotal'),
50
+ DatatypeConfiguration(datatypeIdentifier='DatatypeElephino', typeModule='numpy', typeIdentifier='uint16', type_asname='DatatypeElephino'),
51
+ DatatypeConfiguration(datatypeIdentifier='DatatypeFoldsTotal', typeModule='numpy', typeIdentifier='int64', type_asname='DatatypeFoldsTotal'),
52
+ ]
53
+
54
+ listNumPy_dtype: list[DatatypeConfiguration] = [
55
+ DatatypeConfiguration(datatypeIdentifier='Array1DLeavesTotal', typeModule='numpy', typeIdentifier='uint16', type_asname='Array1DLeavesTotal'),
56
+ DatatypeConfiguration(datatypeIdentifier='Array1DElephino', typeModule='numpy', typeIdentifier='uint16', type_asname='Array1DElephino'),
57
+ DatatypeConfiguration(datatypeIdentifier='Array3D', typeModule='numpy', typeIdentifier='uint16', type_asname='Array3D'),
58
+ ]
59
+
60
+ def _addWriteFoldsTotal(ingredientsFunction: IngredientsFunction, job: RecipeJobTheorem2) -> IngredientsFunction:
61
+ NodeChanger(Be.Return, Then.removeIt).visit(ingredientsFunction.astFunctionDef)
62
+ ingredientsFunction.astFunctionDef.returns = Make.Constant(None)
63
+
64
+ writeFoldsTotal = Make.Expr(Make.Call(Make.Attribute(
65
+ Make.Call(Make.Name('open'), listParameters=[Make.Constant(str(job.pathFilenameFoldsTotal.as_posix())), Make.Constant('w')])
66
+ , 'write'), listParameters=[Make.Call(Make.Name('str'), listParameters=[
67
+ Make.Mult().join([job.shatteredDataclass.countingVariableName, Make.Constant(job.state.leavesTotal * 2)])])]))
68
+
69
+ NodeChanger(IfThis.isAllOf(Be.AugAssign.targetIs(IfThis.isNameIdentifier(job.shatteredDataclass.countingVariableName.id))
70
+ , Be.AugAssign.opIs(Be.Mult), Be.AugAssign.valueIs(Be.Constant))
71
+ , doThat=Then.replaceWith(writeFoldsTotal)
72
+ ).visit(ingredientsFunction.astFunctionDef)
73
+
74
+ return ingredientsFunction
75
+
76
+ def _datatypeDefinitions(ingredientsFunction: IngredientsFunction, ingredientsModule: IngredientsModule) -> tuple[IngredientsFunction, IngredientsModule]:
77
+ for datatypeConfig in [*listDatatypeConfigurations, *listNumPy_dtype]:
78
+ ingredientsFunction.imports.removeImportFrom(datatypeConfig.typeModule, None, datatypeConfig.datatypeIdentifier)
79
+ ingredientsFunction.imports.addImportFrom_asStr(datatypeConfig.typeModule, datatypeConfig.typeIdentifier, datatypeConfig.type_asname)
80
+
81
+ ingredientsFunction.imports.removeImportFromModule('mapFolding.dataBaskets')
82
+
83
+ return ingredientsFunction, ingredientsModule
84
+
85
+ def _pythonCode2expr(string: str) -> ast.expr:
86
+ """Convert *one* expression as a string of Python code to an `ast.expr`."""
87
+ return raiseIfNone(NodeTourist(Be.Expr, Then.extractIt(DOT.value)).captureLastMatch(ast.parse(string)))
88
+
89
+ def _variableCompatibility(ingredientsFunction: IngredientsFunction, job: RecipeJobTheorem2) -> IngredientsFunction:
90
+ # On some assignment or comparison values, add a type constructor to ensure compatibility.
91
+ # On some values-as-indexer, add a type constructor to ensure indexing-method compatibility.
92
+ for ast_arg in job.shatteredDataclass.list_argAnnotated4ArgumentsSpecification:
93
+ identifier = ast_arg.arg
94
+ annotation = raiseIfNone(ast_arg.annotation)
95
+
96
+ # `identifier` in Augmented Assignment, or in Assignments and value is Constant.
97
+ NodeChanger(findThis=IfThis.isAnyOf(
98
+ Be.AugAssign.targetIs(IfThis.isNestedNameIdentifier(identifier))
99
+ , IfThis.isAllOf(IfThis.isAssignAndTargets0Is(IfThis.isNameIdentifier(identifier))
100
+ , Be.Assign.valueIs(Be.Constant))
101
+ )
102
+ , doThat=lambda node, annotation=annotation: Grab.valueAttribute(Then.replaceWith(Make.Call(annotation, listParameters=[node.value])))(node)
103
+ ).visit(ingredientsFunction.astFunctionDef)
104
+
105
+ # `identifier` - 1.
106
+ NodeChanger(Be.BinOp.leftIs(IfThis.isNestedNameIdentifier(identifier))
107
+ , doThat=lambda node, annotation=annotation: Grab.rightAttribute(Then.replaceWith(Make.Call(annotation, listParameters=[node.right])))(node)
108
+ ).visit(ingredientsFunction.astFunctionDef)
109
+
110
+ # `identifier` in Comparison.
111
+ NodeChanger(Be.Compare.leftIs(IfThis.isNestedNameIdentifier(identifier))
112
+ , doThat=lambda node, annotation=annotation: Grab.comparatorsAttribute(lambda at, annotation=annotation: Then.replaceWith([Make.Call(annotation, listParameters=[node.comparators[0]])])(at[0]))(node)
113
+ ).visit(ingredientsFunction.astFunctionDef)
114
+
115
+ # `identifier` has exactly one index value.
116
+ NodeChanger(IfThis.isAllOf(Be.Subscript.valueIs(IfThis.isNestedNameIdentifier(identifier))
117
+ , lambda node: not Be.Subscript.sliceIs(Be.Tuple)(node))
118
+ , doThat=lambda node: Grab.sliceAttribute(Then.replaceWith(Make.Call(Make.Name('int'), listParameters=[node.slice])))(node)
119
+ ).visit(ingredientsFunction.astFunctionDef)
120
+
121
+ # `identifier` has multiple index values.
122
+ NodeChanger(IfThis.isAllOf(Be.Subscript.valueIs(IfThis.isNestedNameIdentifier(identifier))
123
+ , Be.Subscript.sliceIs(Be.Tuple))
124
+ , doThat=lambda node: Grab.sliceAttribute(Grab.eltsAttribute(
125
+ Then.replaceWith([
126
+ Make.Call(Make.Name('int'), listParameters=[cast('ast.Tuple', node.slice).elts[index]])
127
+ for index in range(len(cast('ast.Tuple', node.slice).elts))])))(node)
128
+ ).visit(ingredientsFunction.astFunctionDef)
129
+
130
+ return ingredientsFunction
131
+
132
+ def _move_arg2body(identifier: str, job: RecipeJobTheorem2) -> ast.AnnAssign | ast.Assign:
133
+ Ima___Assign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[identifier]
134
+ match elementConstructor:
135
+ case 'scalar':
136
+ cast('ast.Constant', cast('ast.Call', Ima___Assign.value).args[0]).value = int(job.state.__dict__[identifier])
137
+ case 'array':
138
+ dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[identifier], assumeAddSpaces=True)
139
+ dataAs_ast_expr: ast.expr = _pythonCode2expr(dataAsStrRLE)
140
+ cast('ast.Call', Ima___Assign.value).args = [dataAs_ast_expr]
141
+ case _:
142
+ pass
143
+ return Ima___Assign
144
+
145
+ def makeJob(job: RecipeJobTheorem2) -> None:
146
+ """Generate an optimized module for map folding calculations.
147
+
148
+ This function orchestrates the complete code transformation assembly line to convert
149
+ a generic map folding algorithm into a highly optimized, specialized computation
150
+ module.
151
+
152
+ Parameters
153
+ ----------
154
+ job : RecipeJobTheorem2
155
+ Configuration recipe containing source locations, target paths, and state.
156
+
157
+ """
158
+ ingredientsCount: IngredientsFunction = IngredientsFunction(raiseIfNone(extractFunctionDef(job.source_astModule, job.countCallable)))
159
+ ingredientsCount.astFunctionDef.decorator_list = []
160
+
161
+ # Replace identifiers-with-static-values with their values.
162
+ listIdentifiersStaticValues: list[str] = listIdentifiersStaticValuesHARDCODED
163
+ for identifier in listIdentifiersStaticValues:
164
+ NodeChanger(IfThis.isNameIdentifier(identifier)
165
+ , Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
166
+ ).visit(ingredientsCount.astFunctionDef)
167
+
168
+ ingredientsCount.imports.update(job.shatteredDataclass.imports)
169
+ ingredientsCount = removeUnusedParameters(ingredientsCount)
170
+ NodeChanger(Be.arg, lambda removeIt: ingredientsCount.astFunctionDef.body.insert(0, _move_arg2body(removeIt.arg, job))).visit(ingredientsCount.astFunctionDef)
171
+
172
+ ingredientsCount = _addWriteFoldsTotal(ingredientsCount, job)
173
+ ingredientsCount = _variableCompatibility(ingredientsCount, job)
174
+
175
+ ingredientsModule = IngredientsModule(launcher=Make.Module([
176
+ Make.If(Make.Compare(Make.Name('__name__'), [Make.Eq()], [Make.Constant('__main__')])
177
+ , body=[Make.Expr(Make.Call(Make.Name(job.countCallable)))])]))
178
+
179
+ ingredientsCount, ingredientsModule = _datatypeDefinitions(ingredientsCount, ingredientsModule)
180
+
181
+ ingredientsModule.appendIngredientsFunction(ingredientsCount)
182
+ write_astModule(ingredientsModule, pathFilename=job.pathFilenameModule, packageName=job.packageIdentifier)
183
+
184
+ if sys.platform == 'linux':
185
+ buildCommand: list[str] = ['codon', 'build', '--exe', '--release',
186
+ '--fast-math', '--enable-unsafe-fp-math', '--disable-exceptions',
187
+ str(job.pathFilenameModule)]
188
+ subprocess.run(buildCommand, check=False)
189
+ subprocess.run(['/usr/bin/strip', str(job.pathFilenameModule.with_suffix(''))], check=False)
190
+
191
+ if __name__ == '__main__':
192
+ state = initializeGroupsOfFolds(MapFoldingState((2,4)))
193
+ pathModule = PurePosixPath(Path.home(), 'mapFolding', 'jobs')
194
+ pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
195
+ aJob = RecipeJobTheorem2(state, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
196
+ makeJob(aJob)
@@ -26,7 +26,9 @@ system to produce standalone modules optimized for specific map dimensions and c
26
26
  """
27
27
 
28
28
  from astToolkit import identifierDotAttribute, IngredientsFunction, Make
29
- from typing import cast, Final, NotRequired, TYPE_CHECKING, TypedDict
29
+ from collections.abc import Callable
30
+ from numba.core.compiler import CompilerBase as numbaCompilerBase
31
+ from typing import Any, Final, NotRequired, TYPE_CHECKING, TypedDict
30
32
  import ast
31
33
  import dataclasses
32
34
  import warnings
@@ -69,7 +71,7 @@ class ParametersNumba(TypedDict):
69
71
  forceinline: NotRequired[bool]
70
72
  forceobj: NotRequired[bool]
71
73
  inline: NotRequired[str]
72
- # locals: NotRequired[dict[str, Any]]
74
+ locals: NotRequired[dict[str, Any]]
73
75
  looplift: NotRequired[bool]
74
76
  no_cfunc_wrapper: NotRequired[bool]
75
77
  no_cpython_wrapper: NotRequired[bool]
@@ -77,8 +79,8 @@ class ParametersNumba(TypedDict):
77
79
  nogil: NotRequired[bool]
78
80
  nopython: NotRequired[bool]
79
81
  parallel: NotRequired[bool]
80
- # pipeline_class: NotRequired[type[numbaCompilerBase]]
81
- # signature_or_function: NotRequired[Any | Callable[..., Any] | str | tuple[Any, ...]]
82
+ pipeline_class: NotRequired[type[numbaCompilerBase]]
83
+ signature_or_function: NotRequired[Any | Callable[..., Any] | str | tuple[Any, ...]]
82
84
  target: NotRequired[str]
83
85
 
84
86
  parametersNumbaDefault: Final[ParametersNumba] = { '_nrt': True, 'boundscheck': False, 'cache': True, 'error_model': 'numpy', 'fastmath': True, 'forceinline': True, 'inline': 'always', 'looplift': False, 'no_cfunc_wrapper': False, 'no_cpython_wrapper': False, 'nopython': True, 'parallel': False }
@@ -257,10 +259,10 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
257
259
 
258
260
  if ingredientsFunction.astFunctionDef.returns and isinstance(ingredientsFunction.astFunctionDef.returns, ast.Name):
259
261
  theReturn: ast.Name = ingredientsFunction.astFunctionDef.returns
260
- list_argsDecorator = [cast("ast.expr", Make.Call(Make.Name(theReturn.id)
261
- , list_arg4signature_or_function if list_arg4signature_or_function else [], [] ) )]
262
+ list_argsDecorator = [Make.Call(Make.Name(theReturn.id)
263
+ , list_arg4signature_or_function if list_arg4signature_or_function else [], [] )]
262
264
  elif list_arg4signature_or_function:
263
- list_argsDecorator = [cast("ast.expr", Make.Tuple(list_arg4signature_or_function))]
265
+ list_argsDecorator = [Make.Tuple(list_arg4signature_or_function)]
264
266
 
265
267
  ingredientsFunction.astFunctionDef = Z0Z_UnhandledDecorators(ingredientsFunction.astFunctionDef)
266
268
  if parametersNumba is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapFolding
3
- Version: 0.13.0
3
+ Version: 0.13.1
4
4
  Summary: Map folding algorithm with code transformation framework for optimizing numerical computations.
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mapFolding"
3
- version = "0.13.0"
3
+ version = "0.13.1"
4
4
  description = "Map folding algorithm with code transformation framework for optimizing numerical computations."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -1,256 +0,0 @@
1
- """codon.
2
-
3
- https://docs.exaloop.io/start/install/"""
4
-
5
- from astToolkit import (
6
- Be, DOT, extractFunctionDef, Grab, hasDOTvalue, identifierDotAttribute, IngredientsFunction, IngredientsModule, Make,
7
- NodeChanger, NodeTourist, Then)
8
- from astToolkit.transformationTools import write_astModule
9
- from hunterMakesPy import autoDecodingRLE, raiseIfNone
10
- from mapFolding import getPathFilenameFoldsTotal, MapFoldingState, packageSettings
11
- from mapFolding.someAssemblyRequired import IfThis
12
- from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2
13
- from mapFolding.syntheticModules.initializeCount import initializeGroupsOfFolds
14
- from pathlib import Path, PurePosixPath
15
- from typing import cast, NamedTuple
16
- import ast
17
- import subprocess
18
- import sys
19
-
20
- class DatatypeConfiguration(NamedTuple):
21
- """Configuration for mapping framework datatypes to compiled datatypes.
22
-
23
- This configuration class defines how abstract datatypes used in the map folding framework should be replaced with compiled
24
- datatypes during code generation. Each configuration specifies the source module, target type name, and optional import
25
- alias for the transformation.
26
-
27
- Attributes
28
- ----------
29
- datatypeIdentifier : str
30
- Framework datatype identifier to be replaced.
31
- typeModule : identifierDotAttribute
32
- Module containing the target datatype (e.g., 'codon', 'numpy').
33
- typeIdentifier : str
34
- Concrete type name in the target module.
35
- type_asname : str | None = None
36
- Optional import alias for the type.
37
- """
38
-
39
- datatypeIdentifier: str
40
- typeModule: identifierDotAttribute
41
- typeIdentifier: str
42
- type_asname: str | None = None
43
-
44
- # TODO replace with dynamic system. Probably use `Final` in the dataclass.
45
- listIdentifiersStaticValuesHARDCODED: list[str] = ['dimensionsTotal', 'leavesTotal']
46
-
47
- listDatatypeConfigs: list[DatatypeConfiguration] = [
48
- DatatypeConfiguration(datatypeIdentifier='DatatypeLeavesTotal', typeModule='numpy', typeIdentifier='uint16', type_asname='DatatypeLeavesTotal'),
49
- DatatypeConfiguration(datatypeIdentifier='DatatypeElephino', typeModule='numpy', typeIdentifier='uint16', type_asname='DatatypeElephino'),
50
- DatatypeConfiguration(datatypeIdentifier='DatatypeFoldsTotal', typeModule='numpy', typeIdentifier='int64', type_asname='DatatypeFoldsTotal'),
51
- ]
52
-
53
- listNumPyTypeConfigs: list[DatatypeConfiguration] = [
54
- DatatypeConfiguration(datatypeIdentifier='Array1DLeavesTotal', typeModule='numpy', typeIdentifier='uint16', type_asname='Array1DLeavesTotal'),
55
- DatatypeConfiguration(datatypeIdentifier='Array1DElephino', typeModule='numpy', typeIdentifier='uint16', type_asname='Array1DElephino'),
56
- DatatypeConfiguration(datatypeIdentifier='Array3D', typeModule='numpy', typeIdentifier='uint16', type_asname='Array3D'),
57
- ]
58
-
59
- def _datatypeDefinitions(ingredientsFunction: IngredientsFunction, ingredientsModule: IngredientsModule) -> tuple[IngredientsFunction, IngredientsModule]:
60
- for datatypeConfig in listDatatypeConfigs:
61
- ingredientsFunction.imports.removeImportFrom(datatypeConfig.typeModule, None, datatypeConfig.datatypeIdentifier)
62
- ingredientsFunction.imports.addImportFrom_asStr(datatypeConfig.typeModule, datatypeConfig.typeIdentifier, datatypeConfig.type_asname)
63
- continue
64
- ingredientsModule.appendPrologue(statement=Make.Assign([Make.Name(datatypeConfig.datatypeIdentifier, ast.Store())]
65
- , value=Make.Name(datatypeConfig.typeIdentifier)
66
- ))
67
-
68
- for datatypeConfig in listNumPyTypeConfigs:
69
- ingredientsFunction.imports.removeImportFrom(datatypeConfig.typeModule, None, datatypeConfig.datatypeIdentifier)
70
- ingredientsFunction.imports.addImportFrom_asStr(datatypeConfig.typeModule, datatypeConfig.typeIdentifier, datatypeConfig.type_asname)
71
- continue
72
- ingredientsModule.appendPrologue(statement=Make.Assign([Make.Name(datatypeConfig.datatypeIdentifier, ast.Store())]
73
- , value=Make.Name(datatypeConfig.typeIdentifier)
74
- ))
75
-
76
- ingredientsFunction.imports.removeImportFromModule('mapFolding.dataBaskets')
77
-
78
- return ingredientsFunction, ingredientsModule
79
-
80
- def _pythonCode2expr(string: str) -> ast.expr:
81
- """Convert *one* expression as a string of Python code to an `ast.expr`."""
82
- return raiseIfNone(NodeTourist(Be.Expr, Then.extractIt(DOT.value)).captureLastMatch(ast.parse(string)))
83
-
84
- def _variableCompatibility(ingredientsFunction: IngredientsFunction, job: RecipeJobTheorem2) -> IngredientsFunction:
85
- for ast_arg in job.shatteredDataclass.list_argAnnotated4ArgumentsSpecification:
86
- identifier = ast_arg.arg
87
- annotation = raiseIfNone(ast_arg.annotation)
88
-
89
- # `identifier` in Augmented Assignment.
90
- NodeChanger(Be.AugAssign.targetIs(IfThis.isNestedNameIdentifier(identifier))
91
- , doThat=lambda node: Grab.valueAttribute(Then.replaceWith(Make.Call(annotation, listParameters=[node.value])))(node)
92
- ).visit(ingredientsFunction.astFunctionDef)
93
-
94
- # `identifier` in Assignments; exclude `numpy.array`.
95
- NodeChanger(findThis=lambda node: IfThis.isAssignAndTargets0Is(IfThis.isNameIdentifier(identifier))(node)
96
- and Be.Assign.valueIs(Be.Constant)(node)
97
- , doThat=lambda node: Grab.valueAttribute(Then.replaceWith(Make.Call(annotation, listParameters=[node.value])))(node)
98
- ).visit(ingredientsFunction.astFunctionDef)
99
-
100
- # `identifier` - 1.
101
- NodeChanger(Be.BinOp.leftIs(IfThis.isNestedNameIdentifier(identifier))
102
- , doThat=lambda node: Grab.rightAttribute(Then.replaceWith(Make.Call(annotation, listParameters=[node.right])))(node)
103
- ).visit(ingredientsFunction.astFunctionDef)
104
-
105
- # `identifier` in Comparison.
106
- NodeChanger(Be.Compare.leftIs(IfThis.isNestedNameIdentifier(identifier))
107
- , doThat=lambda node: Grab.comparatorsAttribute(lambda at: Then.replaceWith([Make.Call(annotation, listParameters=[node.comparators[0]])])(at[0]))(node)
108
- ).visit(ingredientsFunction.astFunctionDef)
109
-
110
- # `identifier` has exactly one index value.
111
- NodeChanger(
112
- findThis=lambda node: Be.Subscript.valueIs(IfThis.isNestedNameIdentifier(identifier))(node)
113
- and not Be.Subscript.sliceIs(Be.Tuple)(node)
114
- , doThat=lambda node: Grab.sliceAttribute(Then.replaceWith(Make.Call(Make.Name('int'), listParameters=[node.slice])))(node)
115
- ).visit(ingredientsFunction.astFunctionDef)
116
-
117
- # `identifier` has multiple index values.
118
- NodeChanger(
119
- findThis=lambda node: Be.Subscript.valueIs(IfThis.isNestedNameIdentifier(identifier))(node)
120
- and Be.Subscript.sliceIs(Be.Tuple)(node)
121
- , doThat=lambda node: Grab.sliceAttribute(Grab.eltsAttribute(
122
- Then.replaceWith([
123
- Make.Call(Make.Name('int'), listParameters=[cast(ast.Tuple, node.slice).elts[index]])
124
- for index in range(len(cast(ast.Tuple, node.slice).elts))
125
- ])
126
- ))(node)
127
- ).visit(ingredientsFunction.astFunctionDef)
128
-
129
- return ingredientsFunction
130
-
131
- def move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsFunction: IngredientsFunction, job: RecipeJobTheorem2) -> IngredientsFunction:
132
- """Convert function parameters into initialized variables with concrete values.
133
-
134
- This function converts function arguments into statically initialized variables in the function body.
135
-
136
- The function handles different data types (scalars, arrays, custom types) appropriately, replacing abstract parameter
137
- references with concrete values from the computation state. It also removes unused parameters and variables.
138
-
139
- Parameters
140
- ----------
141
- ingredientsFunction : IngredientsFunction
142
- The function to transform.
143
- job : RecipeJobTheorem2
144
- Recipe containing concrete values for parameters and field metadata.
145
-
146
- Returns
147
- -------
148
- modifiedFunction : IngredientsFunction
149
- The modified function with parameters converted to initialized variables.
150
-
151
- """
152
- ingredientsFunction.imports.update(job.shatteredDataclass.imports)
153
-
154
- list_argCuzMyBrainRefusesToThink: list[ast.arg] = ingredientsFunction.astFunctionDef.args.args + ingredientsFunction.astFunctionDef.args.posonlyargs + ingredientsFunction.astFunctionDef.args.kwonlyargs
155
- list_arg_arg: list[str] = [ast_arg.arg for ast_arg in list_argCuzMyBrainRefusesToThink]
156
- listName: list[ast.Name] = []
157
- NodeTourist(Be.Name, Then.appendTo(listName)).visit(ingredientsFunction.astFunctionDef)
158
- listIdentifiers: list[str] = [astName.id for astName in listName]
159
- listIdentifiersNotUsed: list[str] = list(set(list_arg_arg) - set(listIdentifiers))
160
-
161
- for ast_arg in list_argCuzMyBrainRefusesToThink:
162
- if ast_arg.arg in job.shatteredDataclass.field2AnnAssign:
163
- if ast_arg.arg in listIdentifiersNotUsed:
164
- pass
165
- else:
166
- Ima___Assign, elementConstructor = job.shatteredDataclass.Z0Z_field2AnnAssign[ast_arg.arg]
167
- match elementConstructor:
168
- case 'scalar':
169
- cast('ast.Constant', cast('ast.Call', Ima___Assign.value).args[0]).value = int(job.state.__dict__[ast_arg.arg])
170
- case 'array':
171
- dataAsStrRLE: str = autoDecodingRLE(job.state.__dict__[ast_arg.arg], assumeAddSpaces=True)
172
- dataAs_ast_expr: ast.expr = _pythonCode2expr(dataAsStrRLE)
173
- cast('ast.Call', Ima___Assign.value).args = [dataAs_ast_expr]
174
- case _:
175
- pass
176
-
177
- ingredientsFunction.astFunctionDef.body.insert(0, Ima___Assign)
178
-
179
- NodeChanger(IfThis.is_argIdentifier(ast_arg.arg), Then.removeIt).visit(ingredientsFunction.astFunctionDef)
180
-
181
- ast.fix_missing_locations(ingredientsFunction.astFunctionDef)
182
- return ingredientsFunction
183
-
184
- def makeJob(job: RecipeJobTheorem2) -> None:
185
- """Generate an optimized module for map folding calculations.
186
-
187
- This function orchestrates the complete code transformation assembly line to convert
188
- a generic map folding algorithm into a highly optimized, specialized computation
189
- module.
190
-
191
- Parameters
192
- ----------
193
- job : RecipeJobTheorem2
194
- Configuration recipe containing source locations, target paths, and state.
195
-
196
- """
197
- ingredientsCount: IngredientsFunction = IngredientsFunction(raiseIfNone(extractFunctionDef(job.source_astModule, job.countCallable)))
198
- ingredientsCount.astFunctionDef.decorator_list = []
199
-
200
- # Replace identifiers-with-static-values with their values.
201
- listIdentifiersStaticValues: list[str] = listIdentifiersStaticValuesHARDCODED
202
- for identifier in listIdentifiersStaticValues:
203
- NodeChanger(IfThis.isNameIdentifier(identifier)
204
- , Then.replaceWith(Make.Constant(int(job.state.__dict__[identifier])))
205
- ).visit(ingredientsCount.astFunctionDef)
206
-
207
- linesLaunch: str = f"""
208
- if __name__ == '__main__':
209
- foldsTotal = {job.countCallable}()
210
- print('\\nmap {job.state.mapShape} =', foldsTotal)
211
- writeStream = open('{job.pathFilenameFoldsTotal.as_posix()}', 'w')
212
- writeStream.write(str(foldsTotal))
213
- writeStream.close()
214
- """
215
- ingredientsModule = IngredientsModule(launcher=ast.parse(linesLaunch))
216
-
217
- # TODO think about `groupsOfFolds *= DatatypeFoldsTotal({2 * job.state.leavesTotal}); return groupsOfFolds`
218
- NodeChanger(Be.Return
219
- , Then.replaceWith(Make.Return(job.shatteredDataclass.countingVariableName))).visit(ingredientsCount.astFunctionDef)
220
- groupsOfFolds2foldsTotal = NodeChanger[ast.AugAssign, hasDOTvalue](
221
- findThis=(lambda node: Be.AugAssign.targetIs(IfThis.isNameIdentifier(job.shatteredDataclass.countingVariableName.id))(node)
222
- and Be.AugAssign.opIs(Be.Mult)(node)
223
- and Be.AugAssign.valueIs(Be.Constant)(node)
224
- )
225
- , doThat=lambda node: Grab.valueAttribute(Then.replaceWith(Make.Constant(job.state.leavesTotal * ast.literal_eval(node.value))))(node)
226
- )
227
- groupsOfFolds2foldsTotal.visit(ingredientsCount.astFunctionDef)
228
-
229
- # TODO think about assigning `returns` here, then removing `returns` a few lines from now.
230
- ingredientsCount.astFunctionDef.returns = job.shatteredDataclass.countingVariableAnnotation
231
-
232
- ingredientsCount = move_arg2FunctionDefDOTbodyAndAssignInitialValues(ingredientsCount, job)
233
-
234
- ingredientsCount, ingredientsModule = _datatypeDefinitions(ingredientsCount, ingredientsModule)
235
- # NOTE Reminder, `returns = None` means "type information is null"; the identifier for the return was removed by `_datatypeDefinitions`.
236
- ingredientsCount.astFunctionDef.returns = None
237
-
238
- ingredientsCount = _variableCompatibility(ingredientsCount, job)
239
-
240
- ingredientsModule.appendIngredientsFunction(ingredientsCount)
241
- write_astModule(ingredientsModule, pathFilename=job.pathFilenameModule, packageName=job.packageIdentifier)
242
-
243
- if sys.platform == 'linux':
244
- pathFilenameBuild = Path.home() / 'mapFolding' / 'jobs' / job.pathFilenameModule.stem
245
- pathFilenameBuild.parent.mkdir(parents=True, exist_ok=True)
246
-
247
- buildCommand = ['codon', 'build', '-release', '-disable-exceptions', '-o', str(pathFilenameBuild), str(job.pathFilenameModule)]
248
- subprocess.run(buildCommand)
249
-
250
- if __name__ == '__main__':
251
- state = initializeGroupsOfFolds(MapFoldingState((2,4)))
252
- pathModule = PurePosixPath(packageSettings.pathPackage, 'jobs')
253
- # TODO put `pathFilenameFoldsTotal` in wsl.
254
- pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
255
- aJob = RecipeJobTheorem2(state, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
256
- makeJob(aJob)
File without changes
File without changes
File without changes