mapFolding 0.3.8__py3-none-any.whl → 0.3.10__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.
- mapFolding/__init__.py +56 -0
- mapFolding/basecamp.py +55 -0
- mapFolding/beDRY.py +376 -0
- mapFolding/oeis.py +339 -0
- mapFolding/someAssemblyRequired/__init__.py +2 -0
- {someAssemblyRequired → mapFolding/someAssemblyRequired}/makeJob.py +4 -5
- mapFolding/someAssemblyRequired/synthesizeJobNumba.py +383 -0
- mapFolding/someAssemblyRequired/synthesizeModuleJAX.py +29 -0
- {someAssemblyRequired → mapFolding/someAssemblyRequired}/synthesizeModulesNumba.py +186 -99
- syntheticModules/numbaInitialize.py → mapFolding/syntheticModules/numba_countInitialize.py +6 -9
- syntheticModules/numbaParallel.py → mapFolding/syntheticModules/numba_countParallel.py +4 -4
- syntheticModules/numbaSequential.py → mapFolding/syntheticModules/numba_countSequential.py +5 -5
- mapFolding/syntheticModules/numba_doTheNeedful.py +30 -0
- mapFolding/theDao.py +213 -0
- mapFolding/theSSOT.py +251 -0
- mapFolding/theSSOTnumba.py +115 -0
- mapFolding-0.3.10.dist-info/LICENSE +407 -0
- {mapFolding-0.3.8.dist-info → mapFolding-0.3.10.dist-info}/METADATA +9 -11
- mapFolding-0.3.10.dist-info/RECORD +40 -0
- mapFolding-0.3.10.dist-info/top_level.txt +2 -0
- tests/__init__.py +1 -0
- tests/conftest.py +183 -0
- tests/conftest_tmpRegistry.py +62 -0
- tests/conftest_uniformTests.py +53 -0
- tests/test_oeis.py +141 -0
- tests/test_other.py +259 -0
- tests/test_tasks.py +44 -0
- tests/test_types.py +5 -0
- benchmarks/benchmarking.py +0 -67
- citations/constants.py +0 -3
- citations/updateCitation.py +0 -354
- mapFolding-0.3.8.dist-info/RECORD +0 -26
- mapFolding-0.3.8.dist-info/top_level.txt +0 -5
- someAssemblyRequired/__init__.py +0 -1
- someAssemblyRequired/synthesizeModuleJobNumba.py +0 -212
- syntheticModules/__init__.py +0 -3
- {reference → mapFolding/reference}/flattened.py +0 -0
- {reference → mapFolding/reference}/hunterNumba.py +0 -0
- {reference → mapFolding/reference}/irvineJavaPort.py +0 -0
- {reference → mapFolding/reference}/jax.py +0 -0
- {reference → mapFolding/reference}/lunnan.py +0 -0
- {reference → mapFolding/reference}/lunnanNumpy.py +0 -0
- {reference → mapFolding/reference}/lunnanWhile.py +0 -0
- {reference → mapFolding/reference}/rotatedEntryPoint.py +0 -0
- {reference → mapFolding/reference}/total_countPlus1vsPlusN.py +0 -0
- {someAssemblyRequired → mapFolding/someAssemblyRequired}/getLLVMforNoReason.py +0 -0
- {mapFolding-0.3.8.dist-info → mapFolding-0.3.10.dist-info}/WHEEL +0 -0
- {mapFolding-0.3.8.dist-info → mapFolding-0.3.10.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"""
|
|
2
|
+
It's rough, but it works. Actually, the modules it produces are lightening fast.
|
|
3
|
+
|
|
4
|
+
Specific issues:
|
|
5
|
+
- When trying to run the synthesized file, `ModuleNotFoundError: No module named '<dynamic>'` unless I first re-save the file in the IDE.
|
|
6
|
+
- ast interprets the signature as `def countSequential() -> None:` even though there is a return statement.
|
|
7
|
+
- Similarly, but possibly my fault, `decorateCallableWithNumba` doesn't add the return type to the signature.
|
|
8
|
+
|
|
9
|
+
General issues:
|
|
10
|
+
- an ironic dearth of abstract functionality in this module based on ast.
|
|
11
|
+
- I don't have much experience with ast.
|
|
12
|
+
- ast is one of the few cases that absolutely benefits from an OOP paradigm, and I am comically inept at OOP.
|
|
13
|
+
- (almost) Everything prefixed with `Z0Z_` is something I want to substantially improve.
|
|
14
|
+
- convergence with other synthesize modules and functions would be good.
|
|
15
|
+
- while management of datatypes seems to be pretty good, managing pathFilenames could be better.
|
|
16
|
+
- as of this writing, there are zero direct tests for `someAssemblyRequired`.
|
|
17
|
+
"""
|
|
18
|
+
from mapFolding import indexMy, indexTrack, ParametersNumba, parametersNumbaDEFAULT, getFilenameFoldsTotal, getPathJobRootDEFAULT, getPathFilenameFoldsTotal
|
|
19
|
+
from mapFolding import setDatatypeElephino, setDatatypeFoldsTotal, setDatatypeLeavesTotal, setDatatypeModule, hackSSOTdatatype, computationState
|
|
20
|
+
from mapFolding.someAssemblyRequired import makeStateJob, decorateCallableWithNumba, Z0Z_UnhandledDecorators
|
|
21
|
+
from typing import Optional, Callable, List, Sequence, cast, Dict, Set, Any, Union
|
|
22
|
+
from Z0Z_tools import updateExtendPolishDictionaryLists
|
|
23
|
+
import ast
|
|
24
|
+
import collections
|
|
25
|
+
import importlib
|
|
26
|
+
import importlib.util
|
|
27
|
+
import inspect
|
|
28
|
+
import more_itertools
|
|
29
|
+
import numpy
|
|
30
|
+
import os
|
|
31
|
+
import pathlib
|
|
32
|
+
import python_minifier
|
|
33
|
+
|
|
34
|
+
dictionaryImportFrom: Dict[str, List[str]] = collections.defaultdict(list)
|
|
35
|
+
datatypeModuleScalar = 'numba'
|
|
36
|
+
|
|
37
|
+
def makeStrRLEcompacted(arrayTarget: numpy.ndarray, identifierName: Optional[str]=None) -> str:
|
|
38
|
+
"""Converts a NumPy array into a compressed string representation using run-length encoding (RLE).
|
|
39
|
+
|
|
40
|
+
This function takes a NumPy array and converts it into an optimized string representation by:
|
|
41
|
+
1. Compressing consecutive sequences of numbers into range objects
|
|
42
|
+
2. Minimizing repeated zeros using array multiplication syntax
|
|
43
|
+
3. Converting the result into a valid Python array initialization statement
|
|
44
|
+
|
|
45
|
+
Parameters:
|
|
46
|
+
arrayTarget (numpy.ndarray): The input NumPy array to be converted
|
|
47
|
+
identifierName (str): The variable name to use in the output string
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
str: A string containing Python code that recreates the input array in compressed form.
|
|
51
|
+
Format: "{identifierName} = numpy.array({compressed_data}, dtype=numpy.{dtype})"
|
|
52
|
+
|
|
53
|
+
Example:
|
|
54
|
+
>>> arr = numpy.array([[0,0,0,1,2,3,4,0,0]])
|
|
55
|
+
>>> print(makeStrRLEcompacted(arr, "myArray"))
|
|
56
|
+
"myArray = numpy.array([[0]*3,*range(1,5),[0]*2], dtype=numpy.int64)"
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def compressRangesNDArrayNoFlatten(arraySlice):
|
|
60
|
+
if isinstance(arraySlice, numpy.ndarray) and arraySlice.ndim > 1:
|
|
61
|
+
return [compressRangesNDArrayNoFlatten(arraySlice[index]) for index in range(arraySlice.shape[0])]
|
|
62
|
+
elif isinstance(arraySlice, numpy.ndarray) and arraySlice.ndim == 1:
|
|
63
|
+
listWithRanges = []
|
|
64
|
+
for group in more_itertools.consecutive_groups(arraySlice.tolist()):
|
|
65
|
+
ImaSerious = list(group)
|
|
66
|
+
if len(ImaSerious) <= 4:
|
|
67
|
+
listWithRanges += ImaSerious
|
|
68
|
+
else:
|
|
69
|
+
ImaRange = [range(ImaSerious[0], ImaSerious[-1] + 1)]
|
|
70
|
+
listWithRanges += ImaRange
|
|
71
|
+
return listWithRanges
|
|
72
|
+
return arraySlice
|
|
73
|
+
|
|
74
|
+
arrayAsNestedLists = compressRangesNDArrayNoFlatten(arrayTarget)
|
|
75
|
+
|
|
76
|
+
stringMinimized = python_minifier.minify(str(arrayAsNestedLists))
|
|
77
|
+
commaZeroMaximum = arrayTarget.shape[-1] - 1
|
|
78
|
+
stringMinimized = stringMinimized.replace('[0' + ',0'*commaZeroMaximum + ']', '[0]*'+str(commaZeroMaximum+1))
|
|
79
|
+
for countZeros in range(commaZeroMaximum, 2, -1):
|
|
80
|
+
stringMinimized = stringMinimized.replace(',0'*countZeros + ']', ']+[0]*'+str(countZeros))
|
|
81
|
+
|
|
82
|
+
stringMinimized = stringMinimized.replace('range', '*range')
|
|
83
|
+
|
|
84
|
+
if identifierName:
|
|
85
|
+
return f"{identifierName} = array({stringMinimized}, dtype={arrayTarget.dtype})"
|
|
86
|
+
return stringMinimized
|
|
87
|
+
|
|
88
|
+
def makeImports() -> List[List[ast.ImportFrom]]:
|
|
89
|
+
global dictionaryImportFrom
|
|
90
|
+
dictionaryImportFrom = updateExtendPolishDictionaryLists(dictionaryImportFrom, destroyDuplicates=True)
|
|
91
|
+
|
|
92
|
+
def parseAlias(aliasString: str):
|
|
93
|
+
parts = aliasString.split(" as ")
|
|
94
|
+
if len(parts) == 2:
|
|
95
|
+
return ast.alias(name=parts[0].strip(), asname=parts[1].strip())
|
|
96
|
+
return ast.alias(name=aliasString.strip(), asname=None)
|
|
97
|
+
|
|
98
|
+
importStatements = [[
|
|
99
|
+
ast.ImportFrom(module=module, names=[ast.alias(name=identifierName, asname=None)
|
|
100
|
+
for identifierName in listIdentifiers], level=0)
|
|
101
|
+
for module, listIdentifiers in dictionaryImportFrom.items()]
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
return importStatements
|
|
105
|
+
|
|
106
|
+
def evaluateArrayIn_body(node: ast.FunctionDef, astArg: ast.arg, argData: numpy.ndarray) -> ast.FunctionDef:
|
|
107
|
+
global dictionaryImportFrom
|
|
108
|
+
arrayType = type(argData)
|
|
109
|
+
moduleConstructor = arrayType.__module__
|
|
110
|
+
constructorName = arrayType.__name__
|
|
111
|
+
# NOTE hack
|
|
112
|
+
constructorName = constructorName.replace('ndarray', 'array')
|
|
113
|
+
dictionaryImportFrom[moduleConstructor].append(constructorName)
|
|
114
|
+
|
|
115
|
+
for stmt in node.body.copy():
|
|
116
|
+
if isinstance(stmt, ast.Assign):
|
|
117
|
+
if isinstance(stmt.targets[0], ast.Name) and isinstance(stmt.value, ast.Subscript):
|
|
118
|
+
astAssignee: ast.Name = stmt.targets[0]
|
|
119
|
+
argData_dtypeName = hackSSOTdatatype(astAssignee.id)
|
|
120
|
+
dictionaryImportFrom[moduleConstructor].append(argData_dtypeName)
|
|
121
|
+
astSubscript: ast.Subscript = stmt.value
|
|
122
|
+
if isinstance(astSubscript.value, ast.Name) and astSubscript.value.id == astArg.arg and isinstance(astSubscript.slice, ast.Attribute):
|
|
123
|
+
indexAs_astAttribute: ast.Attribute = astSubscript.slice
|
|
124
|
+
indexAsStr = ast.unparse(indexAs_astAttribute)
|
|
125
|
+
argDataSlice = argData[eval(indexAsStr)]
|
|
126
|
+
|
|
127
|
+
onlyDataRLE = makeStrRLEcompacted(argDataSlice)
|
|
128
|
+
astStatement = cast(ast.Expr, ast.parse(onlyDataRLE).body[0])
|
|
129
|
+
dataAst = astStatement.value
|
|
130
|
+
|
|
131
|
+
arrayCall = ast.Call(
|
|
132
|
+
func=ast.Name(id=constructorName, ctx=ast.Load()) , args=[dataAst]
|
|
133
|
+
, keywords=[ast.keyword(arg='dtype', value=ast.Name(id=argData_dtypeName, ctx=ast.Load()) ) ] )
|
|
134
|
+
|
|
135
|
+
assignment = ast.Assign( targets=[astAssignee], value=arrayCall )
|
|
136
|
+
node.body.insert(0, assignment)
|
|
137
|
+
node.body.remove(stmt)
|
|
138
|
+
|
|
139
|
+
node.args.args.remove(astArg)
|
|
140
|
+
return node
|
|
141
|
+
|
|
142
|
+
def evaluate_argIn_body(node: ast.FunctionDef, astArg: ast.arg, argData: numpy.ndarray, Z0Z_listChaff: List[str]) -> ast.FunctionDef:
|
|
143
|
+
global dictionaryImportFrom
|
|
144
|
+
moduleConstructor = datatypeModuleScalar
|
|
145
|
+
for stmt in node.body.copy():
|
|
146
|
+
if isinstance(stmt, ast.Assign):
|
|
147
|
+
if isinstance(stmt.targets[0], ast.Name) and isinstance(stmt.value, ast.Subscript):
|
|
148
|
+
astAssignee: ast.Name = stmt.targets[0]
|
|
149
|
+
argData_dtypeName = hackSSOTdatatype(astAssignee.id)
|
|
150
|
+
dictionaryImportFrom[moduleConstructor].append(argData_dtypeName)
|
|
151
|
+
astSubscript: ast.Subscript = stmt.value
|
|
152
|
+
if isinstance(astSubscript.value, ast.Name) and astSubscript.value.id == astArg.arg and isinstance(astSubscript.slice, ast.Attribute):
|
|
153
|
+
indexAs_astAttribute: ast.Attribute = astSubscript.slice
|
|
154
|
+
indexAsStr = ast.unparse(indexAs_astAttribute)
|
|
155
|
+
argDataSlice: int = argData[eval(indexAsStr)].item()
|
|
156
|
+
astCall = ast.Call(func=ast.Name(id=argData_dtypeName, ctx=ast.Load()) , args=[ast.Constant(value=argDataSlice)], keywords=[])
|
|
157
|
+
assignment = ast.Assign(targets=[astAssignee], value=astCall)
|
|
158
|
+
if astAssignee.id not in Z0Z_listChaff:
|
|
159
|
+
node.body.insert(0, assignment)
|
|
160
|
+
node.body.remove(stmt)
|
|
161
|
+
node.args.args.remove(astArg)
|
|
162
|
+
return node
|
|
163
|
+
|
|
164
|
+
def evaluateAnnAssignIn_body(node: ast.FunctionDef) -> ast.FunctionDef:
|
|
165
|
+
global dictionaryImportFrom
|
|
166
|
+
moduleConstructor = datatypeModuleScalar
|
|
167
|
+
for stmt in node.body.copy():
|
|
168
|
+
if isinstance(stmt, ast.AnnAssign):
|
|
169
|
+
if isinstance(stmt.target, ast.Name) and isinstance(stmt.value, ast.Constant):
|
|
170
|
+
astAssignee: ast.Name = stmt.target
|
|
171
|
+
argData_dtypeName = hackSSOTdatatype(astAssignee.id)
|
|
172
|
+
dictionaryImportFrom[moduleConstructor].append(argData_dtypeName)
|
|
173
|
+
astCall = ast.Call(func=ast.Name(id=argData_dtypeName, ctx=ast.Load()) , args=[stmt.value], keywords=[])
|
|
174
|
+
assignment = ast.Assign(targets=[astAssignee], value=astCall)
|
|
175
|
+
node.body.insert(0, assignment)
|
|
176
|
+
node.body.remove(stmt)
|
|
177
|
+
return node
|
|
178
|
+
|
|
179
|
+
def move_argTo_body(node: ast.FunctionDef, astArg: ast.arg, argData: numpy.ndarray) -> ast.FunctionDef:
|
|
180
|
+
arrayType = type(argData)
|
|
181
|
+
moduleConstructor = arrayType.__module__
|
|
182
|
+
constructorName = arrayType.__name__
|
|
183
|
+
# NOTE hack
|
|
184
|
+
constructorName = constructorName.replace('ndarray', 'array')
|
|
185
|
+
argData_dtype: numpy.dtype = argData.dtype
|
|
186
|
+
argData_dtypeName = argData.dtype.name
|
|
187
|
+
|
|
188
|
+
global dictionaryImportFrom
|
|
189
|
+
dictionaryImportFrom[moduleConstructor].append(constructorName)
|
|
190
|
+
dictionaryImportFrom[moduleConstructor].append(argData_dtypeName)
|
|
191
|
+
|
|
192
|
+
onlyDataRLE = makeStrRLEcompacted(argData)
|
|
193
|
+
astStatement = cast(ast.Expr, ast.parse(onlyDataRLE).body[0])
|
|
194
|
+
dataAst = astStatement.value
|
|
195
|
+
|
|
196
|
+
arrayCall = ast.Call(
|
|
197
|
+
func=ast.Name(id=constructorName, ctx=ast.Load())
|
|
198
|
+
, args=[dataAst]
|
|
199
|
+
, keywords=[ast.keyword(arg='dtype' , value=ast.Name(id=argData_dtypeName , ctx=ast.Load()) ) ] )
|
|
200
|
+
|
|
201
|
+
assignment = ast.Assign( targets=[ast.Name(id=astArg.arg, ctx=ast.Store())], value=arrayCall )
|
|
202
|
+
node.body.insert(0, assignment)
|
|
203
|
+
node.args.args.remove(astArg)
|
|
204
|
+
|
|
205
|
+
return node
|
|
206
|
+
|
|
207
|
+
def makeDecorator(FunctionDefTarget: ast.FunctionDef, parametersNumba: Optional[ParametersNumba]=None) -> ast.FunctionDef:
|
|
208
|
+
if parametersNumba is None:
|
|
209
|
+
parametersNumbaExtracted: Dict[str, Any] = {}
|
|
210
|
+
for decoratorItem in FunctionDefTarget.decorator_list.copy():
|
|
211
|
+
if isinstance(decoratorItem, ast.Call) and isinstance(decoratorItem.func, ast.Attribute):
|
|
212
|
+
if getattr(decoratorItem.func.value, "id", None) == "numba" and decoratorItem.func.attr == "jit":
|
|
213
|
+
FunctionDefTarget.decorator_list.remove(decoratorItem)
|
|
214
|
+
for keywordItem in decoratorItem.keywords:
|
|
215
|
+
if isinstance(keywordItem.value, ast.Constant) and keywordItem.arg is not None:
|
|
216
|
+
parametersNumbaExtracted[keywordItem.arg] = keywordItem.value.value
|
|
217
|
+
if parametersNumbaExtracted:
|
|
218
|
+
parametersNumba = ParametersNumba(parametersNumbaExtracted) # type: ignore
|
|
219
|
+
else:
|
|
220
|
+
# TODO code duplication
|
|
221
|
+
for decoratorItem in FunctionDefTarget.decorator_list.copy():
|
|
222
|
+
if isinstance(decoratorItem, ast.Call) and isinstance(decoratorItem.func, ast.Attribute):
|
|
223
|
+
if getattr(decoratorItem.func.value, "id", None) == "numba" and decoratorItem.func.attr == "jit":
|
|
224
|
+
FunctionDefTarget.decorator_list.remove(decoratorItem)
|
|
225
|
+
FunctionDefTarget = Z0Z_UnhandledDecorators(FunctionDefTarget)
|
|
226
|
+
global dictionaryImportFrom
|
|
227
|
+
dictionaryImportFrom['numba'].append('jit')
|
|
228
|
+
FunctionDefTarget = decorateCallableWithNumba(FunctionDefTarget, parametersNumba)
|
|
229
|
+
# make sure the decorator is rendered as `@jit` and not `@numba.jit`
|
|
230
|
+
for decoratorItem in FunctionDefTarget.decorator_list:
|
|
231
|
+
if isinstance(decoratorItem, ast.Call) and isinstance(decoratorItem.func, ast.Attribute) and decoratorItem.func.attr == "jit":
|
|
232
|
+
decoratorItem.func = ast.Name(id="jit", ctx=ast.Load())
|
|
233
|
+
return FunctionDefTarget
|
|
234
|
+
|
|
235
|
+
def makeLauncher(identifierCallable: str) -> ast.Module:
|
|
236
|
+
linesLaunch = f"""
|
|
237
|
+
if __name__ == '__main__':
|
|
238
|
+
import time
|
|
239
|
+
timeStart = time.perf_counter()
|
|
240
|
+
{identifierCallable}()
|
|
241
|
+
print(time.perf_counter() - timeStart)
|
|
242
|
+
"""
|
|
243
|
+
astLaunch = ast.parse(linesLaunch)
|
|
244
|
+
return astLaunch
|
|
245
|
+
|
|
246
|
+
def make_writeFoldsTotal(stateJob: computationState, pathFilenameFoldsTotal: pathlib.Path) -> ast.Module:
|
|
247
|
+
global dictionaryImportFrom
|
|
248
|
+
dictionaryImportFrom['numba'].append("objmode")
|
|
249
|
+
linesWriteFoldsTotal = f"""
|
|
250
|
+
groupsOfFolds *= {str(stateJob['foldGroups'][-1])}
|
|
251
|
+
print(groupsOfFolds)
|
|
252
|
+
with objmode():
|
|
253
|
+
open('{pathFilenameFoldsTotal.as_posix()}', 'w').write(str(groupsOfFolds))
|
|
254
|
+
return groupsOfFolds
|
|
255
|
+
"""
|
|
256
|
+
return ast.parse(linesWriteFoldsTotal)
|
|
257
|
+
|
|
258
|
+
def removeIdentifierFrom_body(node: ast.FunctionDef, astArg: ast.arg) -> ast.FunctionDef:
|
|
259
|
+
for stmt in node.body.copy():
|
|
260
|
+
if isinstance(stmt, ast.Assign):
|
|
261
|
+
if isinstance(stmt.targets[0], ast.Subscript) and isinstance(stmt.targets[0].value, ast.Name):
|
|
262
|
+
if stmt.targets[0].value.id == astArg.arg:
|
|
263
|
+
node.body.remove(stmt)
|
|
264
|
+
node.args.args.remove(astArg)
|
|
265
|
+
return node
|
|
266
|
+
|
|
267
|
+
def astObjectToAstConstant(astFunction: ast.FunctionDef, object: str, value: int) -> ast.FunctionDef:
|
|
268
|
+
"""
|
|
269
|
+
Replaces nodes in astFunction matching the AST of the string `object`
|
|
270
|
+
with a constant node holding the provided value.
|
|
271
|
+
"""
|
|
272
|
+
targetExpression = ast.parse(object, mode='eval').body
|
|
273
|
+
targetDump = ast.dump(targetExpression, annotate_fields=False)
|
|
274
|
+
|
|
275
|
+
class ReplaceObjectWithConstant(ast.NodeTransformer):
|
|
276
|
+
def __init__(self, targetDump: str, constantValue: int) -> None:
|
|
277
|
+
self.targetDump = targetDump
|
|
278
|
+
self.constantValue = constantValue
|
|
279
|
+
|
|
280
|
+
def generic_visit(self, node: ast.AST) -> ast.AST:
|
|
281
|
+
currentDump = ast.dump(node, annotate_fields=False)
|
|
282
|
+
if currentDump == self.targetDump:
|
|
283
|
+
return ast.copy_location(ast.Constant(value=self.constantValue), node)
|
|
284
|
+
return super().generic_visit(node)
|
|
285
|
+
|
|
286
|
+
transformer = ReplaceObjectWithConstant(targetDump, value)
|
|
287
|
+
newFunction = transformer.visit(astFunction)
|
|
288
|
+
ast.fix_missing_locations(newFunction)
|
|
289
|
+
return newFunction
|
|
290
|
+
|
|
291
|
+
def astNameToAstConstant(astFunction: ast.FunctionDef, name: str, value: int) -> ast.FunctionDef:
|
|
292
|
+
class ReplaceNameWithConstant(ast.NodeTransformer):
|
|
293
|
+
def visit_Name(self, node: ast.Name) -> ast.AST:
|
|
294
|
+
if node.id == name:
|
|
295
|
+
return ast.copy_location(ast.Constant(value=value), node)
|
|
296
|
+
return node
|
|
297
|
+
return ReplaceNameWithConstant().visit(astFunction)
|
|
298
|
+
|
|
299
|
+
def writeJobNumba(listDimensions: Sequence[int], callableSource: Callable, parametersNumba: Optional[ParametersNumba]=None, pathFilenameWriteJob: Optional[Union[str, os.PathLike[str]]] = None) -> pathlib.Path:
|
|
300
|
+
stateJob = makeStateJob(listDimensions, writeJob=False)
|
|
301
|
+
codeSource = inspect.getsource(callableSource)
|
|
302
|
+
astSource = ast.parse(codeSource)
|
|
303
|
+
|
|
304
|
+
pathFilenameFoldsTotal = getPathFilenameFoldsTotal(stateJob['mapShape'])
|
|
305
|
+
|
|
306
|
+
FunctionDefTarget = next((node for node in astSource.body if isinstance(node, ast.FunctionDef) and node.name == callableSource.__name__), None)
|
|
307
|
+
|
|
308
|
+
if not FunctionDefTarget:
|
|
309
|
+
raise ValueError(f"Could not find function {callableSource.__name__} in source code")
|
|
310
|
+
|
|
311
|
+
Z0Z_listArgsTarget = ['connectionGraph', 'gapsWhere']
|
|
312
|
+
Z0Z_listArraysEvaluate = ['track']
|
|
313
|
+
Z0Z_listArgsEvaluate = ['my']
|
|
314
|
+
Z0Z_listChaff = ['taskIndex', 'dimensionsTotal']
|
|
315
|
+
Z0Z_listArgsRemove = ['foldGroups']
|
|
316
|
+
for astArgument in FunctionDefTarget.args.args.copy():
|
|
317
|
+
if astArgument.arg in Z0Z_listArgsTarget:
|
|
318
|
+
FunctionDefTarget = move_argTo_body(FunctionDefTarget, astArgument, stateJob[astArgument.arg])
|
|
319
|
+
elif astArgument.arg in Z0Z_listArraysEvaluate:
|
|
320
|
+
FunctionDefTarget = evaluateArrayIn_body(FunctionDefTarget, astArgument, stateJob[astArgument.arg])
|
|
321
|
+
elif astArgument.arg in Z0Z_listArgsEvaluate:
|
|
322
|
+
FunctionDefTarget = evaluate_argIn_body(FunctionDefTarget, astArgument, stateJob[astArgument.arg], Z0Z_listChaff)
|
|
323
|
+
elif astArgument.arg in Z0Z_listArgsRemove:
|
|
324
|
+
FunctionDefTarget = removeIdentifierFrom_body(FunctionDefTarget, astArgument)
|
|
325
|
+
|
|
326
|
+
FunctionDefTarget = evaluateAnnAssignIn_body(FunctionDefTarget)
|
|
327
|
+
FunctionDefTarget = astNameToAstConstant(FunctionDefTarget, 'dimensionsTotal', int(stateJob['my'][indexMy.dimensionsTotal]))
|
|
328
|
+
FunctionDefTarget = astObjectToAstConstant(FunctionDefTarget, 'foldGroups[-1]', int(stateJob['foldGroups'][-1]))
|
|
329
|
+
|
|
330
|
+
global identifierCallableLaunch
|
|
331
|
+
identifierCallableLaunch = FunctionDefTarget.name
|
|
332
|
+
|
|
333
|
+
FunctionDefTarget = makeDecorator(FunctionDefTarget, parametersNumba)
|
|
334
|
+
|
|
335
|
+
astWriteFoldsTotal = make_writeFoldsTotal(stateJob, pathFilenameFoldsTotal)
|
|
336
|
+
FunctionDefTarget.body += astWriteFoldsTotal.body
|
|
337
|
+
|
|
338
|
+
astLauncher = makeLauncher(FunctionDefTarget.name)
|
|
339
|
+
|
|
340
|
+
astImports = makeImports()
|
|
341
|
+
|
|
342
|
+
astModule = ast.Module(
|
|
343
|
+
body=cast(List[ast.stmt]
|
|
344
|
+
, astImports
|
|
345
|
+
+ [FunctionDefTarget]
|
|
346
|
+
+ [astLauncher])
|
|
347
|
+
, type_ignores=[]
|
|
348
|
+
)
|
|
349
|
+
ast.fix_missing_locations(astModule)
|
|
350
|
+
|
|
351
|
+
codeSource = ast.unparse(astModule)
|
|
352
|
+
|
|
353
|
+
if pathFilenameWriteJob is None:
|
|
354
|
+
filename = getFilenameFoldsTotal(stateJob['mapShape'])
|
|
355
|
+
pathRoot = getPathJobRootDEFAULT()
|
|
356
|
+
pathFilenameWriteJob = pathlib.Path(pathRoot, pathlib.Path(filename).stem, pathlib.Path(filename).with_suffix('.py'))
|
|
357
|
+
else:
|
|
358
|
+
pathFilenameWriteJob = pathlib.Path(pathFilenameWriteJob)
|
|
359
|
+
pathFilenameWriteJob.parent.mkdir(parents=True, exist_ok=True)
|
|
360
|
+
|
|
361
|
+
pathFilenameWriteJob.write_text(codeSource)
|
|
362
|
+
return pathFilenameWriteJob
|
|
363
|
+
|
|
364
|
+
if __name__ == '__main__':
|
|
365
|
+
listDimensions = [2,15]
|
|
366
|
+
setDatatypeFoldsTotal('int64', sourGrapes=True)
|
|
367
|
+
setDatatypeElephino('uint8', sourGrapes=True)
|
|
368
|
+
setDatatypeLeavesTotal('uint8', sourGrapes=True)
|
|
369
|
+
from mapFolding.syntheticModules.numba_countSequential import countSequential
|
|
370
|
+
callableSource = countSequential
|
|
371
|
+
pathFilenameModule = writeJobNumba(listDimensions, callableSource, parametersNumbaDEFAULT)
|
|
372
|
+
|
|
373
|
+
# Induce numba.jit compilation
|
|
374
|
+
# TODO Inducing compilation might be causing the `ModuleNotFoundError: No module named '<dynamic>'` error
|
|
375
|
+
|
|
376
|
+
# moduleSpec = importlib.util.spec_from_file_location(pathFilenameModule.stem, pathFilenameModule)
|
|
377
|
+
# if moduleSpec is None: raise ImportError(f"Could not load module specification from {pathFilenameModule}")
|
|
378
|
+
# module = importlib.util.module_from_spec(moduleSpec)
|
|
379
|
+
# if moduleSpec.loader is None: raise ImportError(f"Could not load module from {moduleSpec}")
|
|
380
|
+
# moduleSpec.loader.exec_module(module)
|
|
381
|
+
|
|
382
|
+
# from mapFolding.someAssemblyRequired.getLLVMforNoReason import writeModuleLLVM
|
|
383
|
+
# pathFilenameLLVM = writeModuleLLVM(pathFilenameModule, identifierCallableLaunch)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from mapFolding import getAlgorithmSource, getPathSyntheticModules
|
|
2
|
+
from mapFolding import setDatatypeModule, setDatatypeFoldsTotal, setDatatypeElephino, setDatatypeLeavesTotal
|
|
3
|
+
from typing import Optional
|
|
4
|
+
import ast
|
|
5
|
+
import inspect
|
|
6
|
+
import pathlib
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
def transformPythonToJAX(codePython: str):
|
|
10
|
+
astPython = ast.parse(codePython)
|
|
11
|
+
|
|
12
|
+
def writeJax(*, codeSource: Optional[str] = None, pathFilenameAlgorithm: Optional[pathlib.Path] = None, pathFilenameDestination: Optional[pathlib.Path] = None) -> None:
|
|
13
|
+
if codeSource is None and pathFilenameAlgorithm is None:
|
|
14
|
+
algorithmSource = getAlgorithmSource()
|
|
15
|
+
codeSource = inspect.getsource(algorithmSource)
|
|
16
|
+
transformedText = transformPythonToJAX(codeSource)
|
|
17
|
+
pathFilenameAlgorithm = pathlib.Path(inspect.getfile(algorithmSource))
|
|
18
|
+
else:
|
|
19
|
+
raise NotImplementedError("You haven't written this part yet.")
|
|
20
|
+
if pathFilenameDestination is None:
|
|
21
|
+
pathFilenameDestination = getPathSyntheticModules() / "countJax.py"
|
|
22
|
+
# pathFilenameDestination.write_text(transformedText)
|
|
23
|
+
|
|
24
|
+
if __name__ == '__main__':
|
|
25
|
+
setDatatypeModule('jax.numpy', sourGrapes=True)
|
|
26
|
+
setDatatypeFoldsTotal('int64', sourGrapes=True)
|
|
27
|
+
setDatatypeElephino('uint8', sourGrapes=True)
|
|
28
|
+
setDatatypeLeavesTotal('uint8', sourGrapes=True)
|
|
29
|
+
writeJax()
|