mapFolding 0.3.9__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 +27 -9
- mapFolding/basecamp.py +1 -1
- mapFolding/beDRY.py +25 -13
- mapFolding/oeis.py +81 -71
- mapFolding/someAssemblyRequired/__init__.py +1 -0
- mapFolding/someAssemblyRequired/makeJob.py +1 -2
- mapFolding/someAssemblyRequired/synthesizeJobNumba.py +383 -0
- mapFolding/someAssemblyRequired/synthesizeModuleJAX.py +2 -2
- mapFolding/someAssemblyRequired/synthesizeModulesNumba.py +71 -44
- mapFolding/syntheticModules/numba_countInitialize.py +4 -5
- mapFolding/syntheticModules/numba_countParallel.py +5 -6
- mapFolding/syntheticModules/numba_countSequential.py +3 -4
- mapFolding/syntheticModules/numba_doTheNeedful.py +16 -19
- mapFolding/theDao.py +43 -44
- mapFolding/theSSOT.py +13 -31
- mapFolding/theSSOTnumba.py +115 -0
- {mapFolding-0.3.9.dist-info → mapFolding-0.3.10.dist-info}/METADATA +1 -7
- mapFolding-0.3.10.dist-info/RECORD +40 -0
- tests/conftest.py +2 -43
- tests/test_oeis.py +7 -66
- tests/test_other.py +30 -29
- mapFolding/someAssemblyRequired/synthesizeModuleJobNumba.py +0 -212
- mapFolding/syntheticModules/__init__.py +0 -3
- mapFolding-0.3.9.dist-info/RECORD +0 -40
- {mapFolding-0.3.9.dist-info → mapFolding-0.3.10.dist-info}/LICENSE +0 -0
- {mapFolding-0.3.9.dist-info → mapFolding-0.3.10.dist-info}/WHEEL +0 -0
- {mapFolding-0.3.9.dist-info → mapFolding-0.3.10.dist-info}/entry_points.txt +0 -0
- {mapFolding-0.3.9.dist-info → mapFolding-0.3.10.dist-info}/top_level.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)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from mapFolding import getAlgorithmSource,
|
|
1
|
+
from mapFolding import getAlgorithmSource, getPathSyntheticModules
|
|
2
2
|
from mapFolding import setDatatypeModule, setDatatypeFoldsTotal, setDatatypeElephino, setDatatypeLeavesTotal
|
|
3
3
|
from typing import Optional
|
|
4
4
|
import ast
|
|
@@ -18,7 +18,7 @@ def writeJax(*, codeSource: Optional[str] = None, pathFilenameAlgorithm: Optiona
|
|
|
18
18
|
else:
|
|
19
19
|
raise NotImplementedError("You haven't written this part yet.")
|
|
20
20
|
if pathFilenameDestination is None:
|
|
21
|
-
pathFilenameDestination =
|
|
21
|
+
pathFilenameDestination = getPathSyntheticModules() / "countJax.py"
|
|
22
22
|
# pathFilenameDestination.write_text(transformedText)
|
|
23
23
|
|
|
24
24
|
if __name__ == '__main__':
|
|
@@ -10,6 +10,9 @@ from mapFolding import (
|
|
|
10
10
|
moduleOfSyntheticModules,
|
|
11
11
|
myPackageNameIs,
|
|
12
12
|
ParametersNumba,
|
|
13
|
+
parametersNumbaSuperJit,
|
|
14
|
+
parametersNumbaFailEarly,
|
|
15
|
+
parametersNumbaSuperJitParallel,
|
|
13
16
|
parametersNumbaDEFAULT,
|
|
14
17
|
setDatatypeElephino,
|
|
15
18
|
setDatatypeFoldsTotal,
|
|
@@ -32,6 +35,14 @@ Convert types
|
|
|
32
35
|
e.g. `groupsOfFolds: int = 0` to `groupsOfFolds = numba.types.{datatypeLarge}(0)`
|
|
33
36
|
This isn't necessary for Numba, but I may the infrastructure for other compilers or paradigms."""
|
|
34
37
|
|
|
38
|
+
def Z0Z_UnhandledDecorators(astCallable: ast.FunctionDef) -> ast.FunctionDef:
|
|
39
|
+
# TODO: more explicit handling of decorators. I'm able to ignore this because I know `algorithmSource` doesn't have any decorators.
|
|
40
|
+
for decoratorItem in astCallable.decorator_list.copy():
|
|
41
|
+
import warnings
|
|
42
|
+
astCallable.decorator_list.remove(decoratorItem)
|
|
43
|
+
warnings.warn(f"Removed decorator {ast.unparse(decoratorItem)} from {astCallable.name}")
|
|
44
|
+
return astCallable
|
|
45
|
+
|
|
35
46
|
class RecursiveInliner(ast.NodeTransformer):
|
|
36
47
|
"""
|
|
37
48
|
Class RecursiveInliner:
|
|
@@ -93,7 +104,7 @@ class RecursiveInliner(ast.NodeTransformer):
|
|
|
93
104
|
return [self.visit(stmt) for stmt in inlineDefinition.body]
|
|
94
105
|
return self.generic_visit(node)
|
|
95
106
|
|
|
96
|
-
def decorateCallableWithNumba(astCallable: ast.FunctionDef,
|
|
107
|
+
def decorateCallableWithNumba(astCallable: ast.FunctionDef, parametersNumba: Optional[ParametersNumba]=None) -> ast.FunctionDef:
|
|
97
108
|
"""
|
|
98
109
|
Decorates an AST function definition with Numba JIT compilation parameters.
|
|
99
110
|
|
|
@@ -181,8 +192,7 @@ def decorateCallableWithNumba(astCallable: ast.FunctionDef, parallel: bool=False
|
|
|
181
192
|
|
|
182
193
|
return ast.Subscript(value=datatypeNumba, slice=shapeAST, ctx=ast.Load())
|
|
183
194
|
|
|
184
|
-
|
|
185
|
-
# callableSourceDecorators = [decorator for decorator in callableInlined.decorator_list]
|
|
195
|
+
astCallable = Z0Z_UnhandledDecorators(astCallable)
|
|
186
196
|
|
|
187
197
|
listNumbaParameterSignature: Sequence[ast.expr] = []
|
|
188
198
|
for parameter in astCallable.args.args:
|
|
@@ -190,15 +200,31 @@ def decorateCallableWithNumba(astCallable: ast.FunctionDef, parallel: bool=False
|
|
|
190
200
|
if (signatureElement):
|
|
191
201
|
listNumbaParameterSignature.append(signatureElement)
|
|
192
202
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if astCallable
|
|
196
|
-
|
|
203
|
+
astTupleSignatureParameters = ast.Tuple(elts=listNumbaParameterSignature, ctx=ast.Load())
|
|
204
|
+
|
|
205
|
+
# TODO if `astCallable` has a return, the return needs to be added to `astArgsNumbaSignature` in the appropriate place
|
|
206
|
+
# The return, when placed in the args, is treated as a `Call`. This is logical because numba is converting to machine code.
|
|
207
|
+
# , args=[Call(func=Name(id='int64', ctx=Load()))]
|
|
208
|
+
ast_argsSignature = astTupleSignatureParameters
|
|
209
|
+
|
|
210
|
+
ImaReturn = next((node for node in astCallable.body if isinstance(node, ast.Return)), None)
|
|
211
|
+
# Return(value=Name(id='groupsOfFolds', ctx=Load()))]
|
|
212
|
+
if ImaReturn is not None and isinstance(ImaReturn.value, ast.Name):
|
|
213
|
+
my_idIf_I_wereA_astCall_func_astName_idParameter = ImaReturn.value.id
|
|
214
|
+
ast_argsSignature = ast.Call(
|
|
215
|
+
func=ast.Name(id=my_idIf_I_wereA_astCall_func_astName_idParameter, ctx=ast.Load()),
|
|
216
|
+
args=[astTupleSignatureParameters],
|
|
217
|
+
keywords=[]
|
|
218
|
+
)
|
|
197
219
|
else:
|
|
198
|
-
|
|
220
|
+
ast_argsSignature = astTupleSignatureParameters
|
|
221
|
+
|
|
222
|
+
if parametersNumba is None:
|
|
223
|
+
parametersNumba = parametersNumbaDEFAULT
|
|
224
|
+
|
|
199
225
|
listKeywordsNumbaSignature = [ast.keyword(arg=parameterName, value=ast.Constant(value=parameterValue)) for parameterName, parameterValue in parametersNumba.items()]
|
|
200
226
|
|
|
201
|
-
astDecoratorNumba = ast.Call(func=ast.Attribute(value=ast.Name(id='numba', ctx=ast.Load()), attr='jit', ctx=ast.Load()), args=[
|
|
227
|
+
astDecoratorNumba = ast.Call(func=ast.Attribute(value=ast.Name(id='numba', ctx=ast.Load()), attr='jit', ctx=ast.Load()), args=[ast_argsSignature], keywords=listKeywordsNumbaSignature)
|
|
202
228
|
|
|
203
229
|
astCallable.decorator_list = [astDecoratorNumba]
|
|
204
230
|
return astCallable
|
|
@@ -311,6 +337,7 @@ class UnpackArrayAccesses(ast.NodeTransformer):
|
|
|
311
337
|
return node
|
|
312
338
|
|
|
313
339
|
def inlineOneCallable(codeSource: str, callableTarget: str):
|
|
340
|
+
|
|
314
341
|
"""
|
|
315
342
|
Inlines a target callable function and its dependencies within the provided code source.
|
|
316
343
|
|
|
@@ -347,8 +374,17 @@ def inlineOneCallable(codeSource: str, callableTarget: str):
|
|
|
347
374
|
|
|
348
375
|
if callableInlined:
|
|
349
376
|
ast.fix_missing_locations(callableInlined)
|
|
350
|
-
|
|
351
|
-
|
|
377
|
+
parametersNumba = None
|
|
378
|
+
|
|
379
|
+
match callableTarget:
|
|
380
|
+
case 'countParallel':
|
|
381
|
+
parametersNumba = parametersNumbaSuperJitParallel
|
|
382
|
+
case 'countSequential':
|
|
383
|
+
parametersNumba = parametersNumbaSuperJit
|
|
384
|
+
case 'countInitialize':
|
|
385
|
+
parametersNumba = parametersNumbaDEFAULT
|
|
386
|
+
|
|
387
|
+
callableDecorated = decorateCallableWithNumba(callableInlined, parametersNumba)
|
|
352
388
|
|
|
353
389
|
if callableTarget == 'countSequential':
|
|
354
390
|
unpackerMy = UnpackArrayAccesses(indexMy, 'my')
|
|
@@ -365,59 +401,50 @@ def inlineOneCallable(codeSource: str, callableTarget: str):
|
|
|
365
401
|
return moduleSource
|
|
366
402
|
|
|
367
403
|
def makeDispatcherNumba(codeSource: str, callableTarget: str, listStuffYouOughtaKnow: List[youOughtaKnow]) -> str:
|
|
368
|
-
"""Creates AST for the dispatcher module that coordinates the optimized functions."""
|
|
369
|
-
docstringDispatcherNumba = """
|
|
370
|
-
What in tarnation is this stupid module and function?
|
|
371
|
-
|
|
372
|
-
- This function is not in the same module as `countFolds` so that we can delay Numba just-in-time (jit) compilation of this function and the finalization of its settings until we are ready.
|
|
373
|
-
- This function is not in the same module as the next function, which does the hard work, so that we can delay `numba.jit` compilation of the next function.
|
|
374
|
-
- This function is "jitted" but the next function is super jitted, which makes it too arrogant to talk to plebian Python functions. It will, however, reluctantly talk to basic jitted functions.
|
|
375
|
-
- So this module can talk to the next function, and because this module isn't as arrogant, it will talk to the low-class `countFolds` that called this function. Well, with a few restrictions, of course:
|
|
376
|
-
- No `TypedDict`
|
|
377
|
-
- The plebs must clean up their own memory problems
|
|
378
|
-
- No oversized integers
|
|
379
|
-
- No global variables, only global constants
|
|
380
|
-
- It won't accept pleb nonlocal variables either
|
|
381
|
-
- Python "class": they are all inferior to the jit class
|
|
382
|
-
- No `**kwargs`
|
|
383
|
-
- and just a few dozen-jillion other things.
|
|
384
|
-
"""
|
|
385
404
|
|
|
386
|
-
|
|
387
|
-
|
|
405
|
+
docstringDispatcherNumba = """What in tarnation is this stupid module and function?
|
|
406
|
+
|
|
407
|
+
- This function is not in the same module as `countFolds` so that we can delay Numba just-in-time (jit) compilation of this function and the finalization of its settings until we are ready.
|
|
408
|
+
- This function is not in the same module as the next function, which does the hard work, so that we can delay `numba.jit` compilation of the next function.
|
|
409
|
+
- This function is "jitted" but the next function is super jitted, which makes it too arrogant to talk to plebian Python functions. It will, however, reluctantly talk to basic jitted functions.
|
|
410
|
+
- So this module can talk to the next function, and because this module isn't as arrogant, it will talk to the low-class `countFolds` that called this function. Well, with a few restrictions, of course:
|
|
411
|
+
- No `TypedDict`
|
|
412
|
+
- The plebs must clean up their own memory problems
|
|
413
|
+
- No oversized integers
|
|
414
|
+
- No global variables, only global constants
|
|
415
|
+
- It won't accept pleb nonlocal variables either
|
|
416
|
+
- Python "class": they are all inferior to the jit class
|
|
417
|
+
- No `**kwargs`
|
|
418
|
+
- and just a few dozen-jillion other things."""
|
|
388
419
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
420
|
+
astSource = ast.parse(codeSource)
|
|
421
|
+
|
|
422
|
+
astImports = [node for node in astSource.body if isinstance(node, (ast.Import, ast.ImportFrom))]
|
|
423
|
+
FunctionDefTarget = next((node for node in astSource.body if isinstance(node, ast.FunctionDef) and node.name == callableTarget), None)
|
|
392
424
|
|
|
393
425
|
if not FunctionDefTarget:
|
|
394
426
|
raise ValueError(f"Could not find function {callableTarget} in source code")
|
|
395
427
|
|
|
396
428
|
# Zero-out the decorator list
|
|
397
|
-
FunctionDefTarget
|
|
398
|
-
# TODO: more explicit handling of decorators. I'm able to ignore this because I know `algorithmSource` doesn't have any decorators.
|
|
399
|
-
# FunctionDefTargetDecorators = [decorator for decorator in FunctionDefTarget.decorator_list]
|
|
429
|
+
FunctionDefTarget = Z0Z_UnhandledDecorators(FunctionDefTarget)
|
|
400
430
|
|
|
401
431
|
# Add Numba decorator
|
|
402
|
-
FunctionDefTarget = decorateCallableWithNumba(FunctionDefTarget,
|
|
432
|
+
FunctionDefTarget = decorateCallableWithNumba(FunctionDefTarget, parametersNumbaFailEarly)
|
|
403
433
|
FunctionDefTarget.body.insert(0, ast.Expr(value=ast.Constant(value=docstringDispatcherNumba)))
|
|
404
434
|
|
|
405
|
-
|
|
406
|
-
moduleAST = ast.Module(
|
|
435
|
+
astModule = ast.Module(
|
|
407
436
|
body=cast(List[ast.stmt]
|
|
408
|
-
,
|
|
437
|
+
, astImports
|
|
409
438
|
+ [Don_Lapre_The_Road_to_Self_Improvement_For_Programmers_by_Using_Short_Identifiers.astForCompetentProgrammers
|
|
410
439
|
for Don_Lapre_The_Road_to_Self_Improvement_For_Programmers_by_Using_Short_Identifiers in listStuffYouOughtaKnow]
|
|
411
440
|
+ [FunctionDefTarget])
|
|
412
441
|
, type_ignores=[]
|
|
413
442
|
)
|
|
414
443
|
|
|
415
|
-
ast.fix_missing_locations(
|
|
416
|
-
return ast.unparse(
|
|
444
|
+
ast.fix_missing_locations(astModule)
|
|
445
|
+
return ast.unparse(astModule)
|
|
417
446
|
|
|
418
447
|
def makeNumbaOptimizedFlow(listCallablesInline: List[str], callableDispatcher: Optional[str] = None, algorithmSource: Optional[ModuleType] = None):
|
|
419
|
-
"""Synthesizes numba-optimized versions of map folding functions."""
|
|
420
|
-
|
|
421
448
|
if not algorithmSource:
|
|
422
449
|
algorithmSource = getAlgorithmSource()
|
|
423
450
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Any, Tuple
|
|
2
2
|
import numpy
|
|
3
|
-
from numpy import integer
|
|
3
|
+
from numpy import dtype, integer, ndarray
|
|
4
4
|
import numba
|
|
5
5
|
from mapFolding import indexMy, indexTrack
|
|
6
|
-
from typing import Any, Tuple
|
|
7
6
|
|
|
8
|
-
@numba.jit((numba.uint8[:, :, ::1], numba.uint8[::1], numba.uint8[::1], numba.uint8[:, ::1]))
|
|
9
|
-
def countInitialize(connectionGraph:
|
|
7
|
+
@numba.jit((numba.uint8[:, :, ::1], numba.uint8[::1], numba.uint8[::1], numba.uint8[:, ::1]), _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)
|
|
8
|
+
def countInitialize(connectionGraph: ndarray[Tuple[int, int, int], dtype[integer[Any]]], gapsWhere: ndarray[Tuple[int], dtype[integer[Any]]], my: ndarray[Tuple[int], dtype[integer[Any]]], track: ndarray[Tuple[int, int], dtype[integer[Any]]]) -> None:
|
|
10
9
|
while my[indexMy.leaf1ndex.value]:
|
|
11
10
|
if my[indexMy.leaf1ndex.value] <= 1 or track[indexTrack.leafBelow.value, 0] == 1:
|
|
12
11
|
my[indexMy.dimensionsUnconstrained.value] = my[indexMy.dimensionsTotal.value]
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
from numpy.typing import NDArray
|
|
2
|
-
import numpy
|
|
3
|
-
from numpy import integer
|
|
4
|
-
import numba
|
|
5
1
|
from mapFolding import indexMy, indexTrack
|
|
6
2
|
from typing import Any, Tuple
|
|
3
|
+
import numpy
|
|
4
|
+
from numpy import dtype, integer, ndarray
|
|
5
|
+
import numba
|
|
7
6
|
|
|
8
|
-
@numba.jit((numba.uint8[:, :, ::1], numba.int64[::1], numba.uint8[::1], numba.uint8[::1], numba.uint8[:, ::1]), _nrt=True, boundscheck=False, cache=True, error_model='numpy', fastmath=True, forceinline=
|
|
9
|
-
def countParallel(connectionGraph:
|
|
7
|
+
@numba.jit((numba.uint8[:, :, ::1], numba.int64[::1], numba.uint8[::1], numba.uint8[::1], numba.uint8[:, ::1]), _nrt=True, boundscheck=False, cache=True, error_model='numpy', fastmath=True, forceinline=True, inline='always', looplift=False, no_cfunc_wrapper=True, no_cpython_wrapper=True, nopython=True, parallel=True)
|
|
8
|
+
def countParallel(connectionGraph: ndarray[Tuple[int, int, int], dtype[integer[Any]]], foldGroups: ndarray[Tuple[int], dtype[integer[Any]]], gapsWhere: ndarray[Tuple[int], dtype[integer[Any]]], my: ndarray[Tuple[int], dtype[integer[Any]]], track: ndarray[Tuple[int, int], dtype[integer[Any]]]) -> None:
|
|
10
9
|
gapsWherePARALLEL = gapsWhere.copy()
|
|
11
10
|
myPARALLEL = my.copy()
|
|
12
11
|
trackPARALLEL = track.copy()
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
from numpy.typing import NDArray
|
|
2
1
|
import numpy
|
|
3
|
-
from numpy import integer
|
|
2
|
+
from numpy import dtype, integer, ndarray
|
|
4
3
|
import numba
|
|
5
4
|
from mapFolding import indexMy, indexTrack
|
|
6
5
|
from typing import Any, Tuple
|
|
7
6
|
|
|
8
|
-
@numba.jit((numba.uint8[:, :, ::1], numba.int64[::1], numba.uint8[::1], numba.uint8[::1], numba.uint8[:, ::1]), _nrt=True, boundscheck=False, cache=True, error_model='numpy', fastmath=True, forceinline=
|
|
9
|
-
def countSequential(connectionGraph:
|
|
7
|
+
@numba.jit((numba.uint8[:, :, ::1], numba.int64[::1], numba.uint8[::1], numba.uint8[::1], numba.uint8[:, ::1]), _nrt=True, boundscheck=False, cache=True, error_model='numpy', fastmath=True, forceinline=True, inline='always', looplift=False, no_cfunc_wrapper=True, no_cpython_wrapper=True, nopython=True, parallel=False)
|
|
8
|
+
def countSequential(connectionGraph: ndarray[Tuple[int, int, int], dtype[integer[Any]]], foldGroups: ndarray[Tuple[int], dtype[integer[Any]]], gapsWhere: ndarray[Tuple[int], dtype[integer[Any]]], my: ndarray[Tuple[int], dtype[integer[Any]]], track: ndarray[Tuple[int, int], dtype[integer[Any]]]) -> None:
|
|
10
9
|
leafBelow = track[indexTrack.leafBelow.value]
|
|
11
10
|
gapRangeStart = track[indexTrack.gapRangeStart.value]
|
|
12
11
|
countDimensionsGapped = track[indexTrack.countDimensionsGapped.value]
|