mapFolding 0.12.3__py3-none-any.whl → 0.13.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 }
@@ -140,7 +142,7 @@ def decorateCallableWithNumba(ingredientsFunction: IngredientsFunction, paramete
140
142
  (AI generated docstring)
141
143
 
142
144
  This function applies Numba's `@jit` decorator to an existing function definition within
143
- an `IngredientsFunction` container. It handles the complete transformation pipeline
145
+ an `IngredientsFunction` container. It handles the complete transformation assembly line
144
146
  including removing any existing decorators that might conflict with Numba, constructing
145
147
  type signatures for Numba compilation when possible, applying the `@jit` decorator with
146
148
  specified or default parameters, and updating import requirements to include necessary
@@ -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:
@@ -4,7 +4,7 @@ This test suite provides comprehensive validation of map folding computations,
4
4
  file system operations, OEIS integration, task division, and foundational
5
5
  utilities. The tests are designed to support multiple audiences and use cases.
6
6
 
7
- Test Module Organization:
7
+ Test Module Organization (in mapFolding/tests/):
8
8
  - conftest.py: Testing infrastructure and shared fixtures
9
9
  - test_computations.py: Core mathematical validation and algorithm testing
10
10
  - test_filesystem.py: File operations and path management
@@ -25,4 +25,4 @@ ensure consistent error reporting across all tests.
25
25
  For AI Assistants:
26
26
  The testing framework emphasizes readable, predictable patterns that maintain
27
27
  mathematical correctness while supporting code evolution and optimization.
28
- """
28
+ """