mapFolding 0.15.0__py3-none-any.whl → 0.15.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.
- mapFolding/__init__.py +1 -0
- mapFolding/_oeisFormulas/A001010.py +18 -0
- mapFolding/_oeisFormulas/Z0Z_oeisMeanders.py +6 -1
- mapFolding/_theTypes.py +1 -1
- mapFolding/basecamp.py +89 -9
- mapFolding/daoOfMapFolding.py +2 -1
- mapFolding/oeis.py +1 -5
- mapFolding/reference/jaxCount.py +1 -1
- mapFolding/reference/rotatedEntryPoint.py +1 -1
- mapFolding/someAssemblyRequired/A007822rawMaterials.py +46 -0
- mapFolding/someAssemblyRequired/makeAllModules.py +192 -199
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +2 -2
- mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +2 -2
- mapFolding/syntheticModules/algorithmA007822.py +166 -0
- mapFolding/syntheticModules/algorithmA007822Numba.py +95 -0
- mapFolding/syntheticModules/{countParallel.py → countParallelNumba.py} +4 -6
- mapFolding/syntheticModules/{daoOfMapFolding.py → daoOfMapFoldingNumba.py} +4 -5
- mapFolding/syntheticModules/dataPacking.py +4 -5
- mapFolding/syntheticModules/{initializeCount.py → initializeState.py} +1 -1
- mapFolding/syntheticModules/initializeStateA007822.py +69 -0
- mapFolding/syntheticModules/theorem2.py +2 -1
- mapFolding/syntheticModules/theorem2A007822.py +70 -0
- mapFolding/syntheticModules/theorem2A007822Numba.py +67 -0
- mapFolding/syntheticModules/theorem2A007822Trimmed.py +64 -0
- mapFolding/syntheticModules/theorem2Numba.py +2 -1
- mapFolding/syntheticModules/theorem2Trimmed.py +2 -1
- mapFolding/tests/test_computations.py +29 -4
- {mapfolding-0.15.0.dist-info → mapfolding-0.15.1.dist-info}/METADATA +1 -1
- {mapfolding-0.15.0.dist-info → mapfolding-0.15.1.dist-info}/RECORD +33 -26
- mapFolding/_A007822.py +0 -181
- {mapfolding-0.15.0.dist-info → mapfolding-0.15.1.dist-info}/WHEEL +0 -0
- {mapfolding-0.15.0.dist-info → mapfolding-0.15.1.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.15.0.dist-info → mapfolding-0.15.1.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.15.0.dist-info → mapfolding-0.15.1.dist-info}/top_level.txt +0 -0
|
@@ -39,7 +39,10 @@ from astToolkit.transformationTools import inlineFunctionDef, removeUnusedParame
|
|
|
39
39
|
from hunterMakesPy import importLogicalPath2Identifier, raiseIfNone
|
|
40
40
|
from mapFolding import packageSettings
|
|
41
41
|
from mapFolding.someAssemblyRequired import (
|
|
42
|
-
DeReConstructField2ast, IfThis, ShatteredDataclass,
|
|
42
|
+
dataclassInstanceIdentifierDEFAULT, DeReConstructField2ast, IfThis, ShatteredDataclass,
|
|
43
|
+
sourceCallableDispatcherDEFAULT)
|
|
44
|
+
from mapFolding.someAssemblyRequired.A007822rawMaterials import (
|
|
45
|
+
FunctionDef_filterAsymmetricFolds, Z0Z_adjustFoldsTotal, Z0Z_incrementCount)
|
|
43
46
|
from mapFolding.someAssemblyRequired.infoBooth import (
|
|
44
47
|
algorithmSourceModuleDEFAULT, dataPackingModuleIdentifierDEFAULT, logicalPathInfixDEFAULT,
|
|
45
48
|
sourceCallableIdentifierDEFAULT, theCountingIdentifierDEFAULT)
|
|
@@ -98,69 +101,18 @@ def _findDataclass(ingredientsFunction: IngredientsFunction) -> tuple[str, str,
|
|
|
98
101
|
dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
|
|
99
102
|
return raiseIfNone(dataclassLogicalPathModule), dataclassIdentifier, dataclassInstanceIdentifier
|
|
100
103
|
|
|
101
|
-
def _getLogicalPath(
|
|
102
|
-
"""Construct logical module path by joining package and module components.
|
|
103
|
-
|
|
104
|
-
(AI generated docstring)
|
|
105
|
-
|
|
106
|
-
Builds a dot-separated logical path string from optional package name, infix path
|
|
107
|
-
components, and module identifiers. This standardizes module path construction
|
|
108
|
-
across the code generation system and ensures consistent naming conventions.
|
|
109
|
-
|
|
110
|
-
Parameters
|
|
111
|
-
----------
|
|
112
|
-
packageName : str | None = None
|
|
113
|
-
Root package name for the logical path.
|
|
114
|
-
logicalPathInfix : str | None = None
|
|
115
|
-
Middle path component (typically 'syntheticModules').
|
|
116
|
-
moduleIdentifier : str | None = None
|
|
117
|
-
Primary module identifier.
|
|
118
|
-
*modules : str
|
|
119
|
-
Additional module path components to append.
|
|
120
|
-
|
|
121
|
-
Returns
|
|
122
|
-
-------
|
|
123
|
-
logicalPath : identifierDotAttribute
|
|
124
|
-
Dot-separated logical path string suitable for module import operations.
|
|
125
|
-
|
|
126
|
-
"""
|
|
104
|
+
def _getLogicalPath(identifierPackage: str | None = None, logicalPathInfix: str | None = None, *moduleIdentifier: str | None) -> identifierDotAttribute:
|
|
127
105
|
listLogicalPathParts: list[str] = []
|
|
128
|
-
if
|
|
129
|
-
listLogicalPathParts.append(
|
|
106
|
+
if identifierPackage:
|
|
107
|
+
listLogicalPathParts.append(identifierPackage)
|
|
130
108
|
if logicalPathInfix:
|
|
131
109
|
listLogicalPathParts.append(logicalPathInfix)
|
|
132
110
|
if moduleIdentifier:
|
|
133
|
-
listLogicalPathParts.
|
|
134
|
-
if modules:
|
|
135
|
-
listLogicalPathParts.extend(modules)
|
|
111
|
+
listLogicalPathParts.extend([module for module in moduleIdentifier if module is not None])
|
|
136
112
|
return '.'.join(listLogicalPathParts)
|
|
137
113
|
|
|
138
|
-
def _getModule(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
(AI generated docstring)
|
|
142
|
-
|
|
143
|
-
Retrieves the specified module and parses it into an AST representation that can
|
|
144
|
-
be manipulated by the transformation tools. This provides the foundation for all
|
|
145
|
-
code generation operations by making the source algorithms available for analysis
|
|
146
|
-
and modification.
|
|
147
|
-
|
|
148
|
-
Parameters
|
|
149
|
-
----------
|
|
150
|
-
packageName : str | None = packageSettings.identifierPackage
|
|
151
|
-
Package containing the source module.
|
|
152
|
-
logicalPathInfix : str | None = logicalPathInfixDEFAULT
|
|
153
|
-
Path component within the package structure.
|
|
154
|
-
moduleIdentifier : str | None = algorithmSourceModuleDEFAULT
|
|
155
|
-
Specific module containing the algorithms.
|
|
156
|
-
|
|
157
|
-
Returns
|
|
158
|
-
-------
|
|
159
|
-
astModule : ast.Module
|
|
160
|
-
AST module representation ready for transformation operations.
|
|
161
|
-
|
|
162
|
-
"""
|
|
163
|
-
logicalPathSourceModule: identifierDotAttribute = _getLogicalPath(packageName, logicalPathInfix, moduleIdentifier)
|
|
114
|
+
def _getModule(identifierPackage: str | None = packageSettings.identifierPackage, logicalPathInfix: str | None = logicalPathInfixDEFAULT, moduleIdentifier: str | None = algorithmSourceModuleDEFAULT) -> ast.Module:
|
|
115
|
+
logicalPathSourceModule: identifierDotAttribute = _getLogicalPath(identifierPackage, logicalPathInfix, moduleIdentifier)
|
|
164
116
|
astModule: ast.Module = parseLogicalPath2astModule(logicalPathSourceModule)
|
|
165
117
|
return astModule
|
|
166
118
|
|
|
@@ -197,55 +149,43 @@ def _getPathFilename(pathRoot: PathLike[str] | PurePath | None = packageSettings
|
|
|
197
149
|
pathFilename = PurePath(pathRoot, pathFilename)
|
|
198
150
|
return pathFilename
|
|
199
151
|
|
|
200
|
-
|
|
201
|
-
"""Generate initialization module for counting variable setup.
|
|
152
|
+
# TODO Where is the generalized form of these functions?!
|
|
202
153
|
|
|
203
|
-
|
|
154
|
+
def addSymmetryCheck(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
|
|
155
|
+
"""Add logic to check for symmetric folds."""
|
|
156
|
+
imports=LedgerOfImports(astModule)
|
|
204
157
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
158
|
+
astFunctionDef_count: ast.FunctionDef = raiseIfNone(NodeTourist(
|
|
159
|
+
findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableIdentifierDEFAULT))
|
|
160
|
+
, doThat = Then.extractIt
|
|
161
|
+
).captureLastMatch(astModule))
|
|
209
162
|
|
|
210
|
-
|
|
211
|
-
|
|
163
|
+
# NOTE 2025 August 7. I am SHOCKED to discover that `astFunctionDef_count: ast.FunctionDef` returned by `NodeTourist` (subclass of
|
|
164
|
+
# `ast.NodeVisitor`) is a so-called mutable `object`!!!!!!
|
|
165
|
+
# !!!!!! Using the mutability of `ast.AST` subclasses, makes `astToolkit` SIGNIFICANTLY more powerful and solves "obstacles" I
|
|
166
|
+
# have been trying to overcome.
|
|
167
|
+
# (Side note: fuck you, Python, for your idiotic paradigms around mutability, its documentation, its identifiers, and its types.)
|
|
212
168
|
|
|
213
|
-
|
|
214
|
-
----------
|
|
215
|
-
astModule : ast.Module
|
|
216
|
-
Source module containing the base algorithm.
|
|
217
|
-
moduleIdentifier : str
|
|
218
|
-
Name for the generated initialization module.
|
|
219
|
-
callableIdentifier : str | None = None
|
|
220
|
-
Name for the initialization function.
|
|
221
|
-
logicalPathInfix : PathLike[str] | PurePath | str | None = None
|
|
222
|
-
Directory path for organizing the generated module.
|
|
223
|
-
sourceCallableDispatcher : str | None = None
|
|
224
|
-
Optional dispatcher function identifier.
|
|
169
|
+
NodeChanger(Be.Return, Then.insertThisAbove([Z0Z_adjustFoldsTotal])).visit(astFunctionDef_count)
|
|
225
170
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
171
|
+
NodeChanger(
|
|
172
|
+
findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(dataclassInstanceIdentifierDEFAULT, theCountingIdentifierDEFAULT))
|
|
173
|
+
, doThat=Then.replaceWith(Z0Z_incrementCount)
|
|
174
|
+
).visit(astFunctionDef_count)
|
|
230
175
|
|
|
231
|
-
|
|
232
|
-
sourceCallableIdentifier: identifierDotAttribute = sourceCallableIdentifierDEFAULT
|
|
233
|
-
ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
|
|
234
|
-
ingredientsFunction.astFunctionDef.name = callableIdentifier or sourceCallableIdentifier
|
|
176
|
+
ingredientsFunction=IngredientsFunction(FunctionDef_filterAsymmetricFolds)
|
|
235
177
|
|
|
236
|
-
|
|
237
|
-
theCountingIdentifier: identifierDotAttribute = theCountingIdentifierDEFAULT
|
|
178
|
+
NodeChanger(Be.ImportFrom, Then.removeIt).visit(astModule)
|
|
238
179
|
|
|
239
|
-
|
|
240
|
-
doThat = Grab.testAttribute(Grab.andDoAllOf([Grab.opsAttribute(Then.replaceWith([ast.Eq()])), Grab.leftAttribute(Grab.attrAttribute(Then.replaceWith(theCountingIdentifier)))]))
|
|
241
|
-
NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef.body[0])
|
|
180
|
+
ingredientsModule = IngredientsModule(ingredientsFunction=ingredientsFunction, epilogue=astModule, imports=imports)
|
|
242
181
|
|
|
243
182
|
pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
|
|
244
|
-
|
|
183
|
+
|
|
184
|
+
write_astModule(ingredientsModule, pathFilename, packageSettings.identifierPackage)
|
|
245
185
|
|
|
246
186
|
return pathFilename
|
|
247
187
|
|
|
248
|
-
def
|
|
188
|
+
def makeDaoOfMapFoldingNumba(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
|
|
249
189
|
"""Generate Numba-optimized sequential implementation of map folding algorithm.
|
|
250
190
|
|
|
251
191
|
(AI generated docstring)
|
|
@@ -318,19 +258,9 @@ def makeDaoOfMapFolding(astModule: ast.Module, moduleIdentifier: str, callableId
|
|
|
318
258
|
|
|
319
259
|
return pathFilename
|
|
320
260
|
|
|
321
|
-
def
|
|
261
|
+
def makeDaoOfMapFoldingParallelNumba(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
|
|
322
262
|
"""Generate parallel implementation with concurrent execution and task division.
|
|
323
263
|
|
|
324
|
-
This version of the algorithm: Creates a parallel processing version of the map folding algorithm that distributes
|
|
325
|
-
computational work across multiple processes using `ProcessPoolExecutor`. The implementation includes dataclass decomposition
|
|
326
|
-
for both base and parallel state fields, task division logic that partitions work based on leaf indices, concurrent execution
|
|
327
|
-
management with future objects, result aggregation from multiple parallel computations, and Numba optimization for the core
|
|
328
|
-
computational kernels.
|
|
329
|
-
|
|
330
|
-
The generated module contains multiple functions including core counting function with parallel-aware task filtering,
|
|
331
|
-
dataclass unpacking/repacking function for process communication, and main dispatcher function that manages the parallel
|
|
332
|
-
execution assembly line.
|
|
333
|
-
|
|
334
264
|
Parameters
|
|
335
265
|
----------
|
|
336
266
|
astModule : ast.Module
|
|
@@ -496,22 +426,56 @@ def makeDaoOfMapFoldingParallel(astModule: ast.Module, moduleIdentifier: str, ca
|
|
|
496
426
|
|
|
497
427
|
return pathFilename
|
|
498
428
|
|
|
499
|
-
def
|
|
500
|
-
"""Generate
|
|
429
|
+
def makeInitializeState(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
|
|
430
|
+
"""Generate initialization module for counting variable setup.
|
|
501
431
|
|
|
502
432
|
(AI generated docstring)
|
|
503
433
|
|
|
504
|
-
Creates a specialized
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
434
|
+
Creates a specialized module containing initialization logic for the counting variables
|
|
435
|
+
used in map folding computations. The generated function transforms the original
|
|
436
|
+
algorithm's loop conditions to use equality comparisons instead of greater-than
|
|
437
|
+
comparisons, optimizing the initialization phase.
|
|
438
|
+
|
|
439
|
+
This transformation is particularly important for ensuring that counting variables
|
|
440
|
+
are properly initialized before the main computational loops begin executing.
|
|
441
|
+
|
|
442
|
+
Parameters
|
|
443
|
+
----------
|
|
444
|
+
astModule : ast.Module
|
|
445
|
+
Source module containing the base algorithm.
|
|
446
|
+
moduleIdentifier : str
|
|
447
|
+
Name for the generated initialization module.
|
|
448
|
+
callableIdentifier : str | None = None
|
|
449
|
+
Name for the initialization function.
|
|
450
|
+
logicalPathInfix : PathLike[str] | PurePath | str | None = None
|
|
451
|
+
Directory path for organizing the generated module.
|
|
452
|
+
sourceCallableDispatcher : str | None = None
|
|
453
|
+
Optional dispatcher function identifier.
|
|
454
|
+
|
|
455
|
+
Returns
|
|
456
|
+
-------
|
|
457
|
+
pathFilename : PurePath
|
|
458
|
+
Filesystem path where the initialization module was written.
|
|
459
|
+
|
|
460
|
+
"""
|
|
461
|
+
sourceCallableIdentifier: identifierDotAttribute = sourceCallableIdentifierDEFAULT
|
|
462
|
+
ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
|
|
463
|
+
ingredientsFunction.astFunctionDef.name = callableIdentifier or sourceCallableIdentifier
|
|
464
|
+
|
|
465
|
+
dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
|
|
466
|
+
theCountingIdentifier: identifierDotAttribute = theCountingIdentifierDEFAULT
|
|
467
|
+
|
|
468
|
+
findThis = IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
|
|
469
|
+
doThat = Grab.testAttribute(Grab.andDoAllOf([Grab.opsAttribute(Then.replaceWith([ast.Eq()])), Grab.leftAttribute(Grab.attrAttribute(Then.replaceWith(theCountingIdentifier)))]))
|
|
470
|
+
NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef.body[0])
|
|
471
|
+
|
|
472
|
+
pathFilename: PurePath = _getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
|
|
473
|
+
write_astModule(IngredientsModule(ingredientsFunction), pathFilename, packageSettings.identifierPackage)
|
|
510
474
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
475
|
+
return pathFilename
|
|
476
|
+
|
|
477
|
+
def makeTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath:
|
|
478
|
+
"""Generate module by applying optimization predicted by Theorem 2.
|
|
515
479
|
|
|
516
480
|
Parameters
|
|
517
481
|
----------
|
|
@@ -543,6 +507,14 @@ def makeTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifie
|
|
|
543
507
|
|
|
544
508
|
dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
|
|
545
509
|
|
|
510
|
+
theCountingIdentifier: identifierDotAttribute = theCountingIdentifierDEFAULT
|
|
511
|
+
doubleTheCount: ast.AugAssign = Make.AugAssign(Make.Attribute(Make.Name(dataclassInstanceIdentifier), theCountingIdentifier), Make.Mult(), Make.Constant(2))
|
|
512
|
+
|
|
513
|
+
NodeChanger(
|
|
514
|
+
findThis = IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
|
|
515
|
+
, doThat = Grab.orelseAttribute(Then.replaceWith([doubleTheCount]))
|
|
516
|
+
).visit(ingredientsFunction.astFunctionDef)
|
|
517
|
+
|
|
546
518
|
NodeChanger(
|
|
547
519
|
findThis = IfThis.isWhileAttributeNamespaceIdentifierGreaterThan0(dataclassInstanceIdentifier, 'leaf1ndex')
|
|
548
520
|
, doThat = Grab.testAttribute(Grab.comparatorsAttribute(Then.replaceWith([Make.Constant(4)])))
|
|
@@ -567,13 +539,6 @@ def makeTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifie
|
|
|
567
539
|
, doThat = Then.removeIt
|
|
568
540
|
).visit(ingredientsFunction.astFunctionDef)
|
|
569
541
|
|
|
570
|
-
theCountingIdentifier: identifierDotAttribute = theCountingIdentifierDEFAULT
|
|
571
|
-
doubleTheCount: ast.AugAssign = Make.AugAssign(Make.Attribute(ast.Name(dataclassInstanceIdentifier), theCountingIdentifier), ast.Mult(), Make.Constant(2))
|
|
572
|
-
NodeChanger(
|
|
573
|
-
findThis = Be.Return
|
|
574
|
-
, doThat = Then.insertThisAbove([doubleTheCount])
|
|
575
|
-
).visit(ingredientsFunction.astFunctionDef)
|
|
576
|
-
|
|
577
542
|
ingredientsModule = IngredientsModule(ingredientsFunction)
|
|
578
543
|
|
|
579
544
|
if sourceCallableDispatcher is not None:
|
|
@@ -586,47 +551,61 @@ def makeTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifie
|
|
|
586
551
|
|
|
587
552
|
return pathFilename
|
|
588
553
|
|
|
589
|
-
def
|
|
590
|
-
"""Generate
|
|
554
|
+
def makeUnRePackDataclass(astImportFrom: ast.ImportFrom) -> None:
|
|
555
|
+
"""Generate interface module for dataclass unpacking and repacking operations.
|
|
591
556
|
|
|
592
557
|
(AI generated docstring)
|
|
593
558
|
|
|
594
|
-
Creates a
|
|
595
|
-
|
|
596
|
-
|
|
559
|
+
Creates a specialized module that serves as an interface between dataclass-based
|
|
560
|
+
calling code and optimized implementations that operate on decomposed primitive
|
|
561
|
+
values. The generated module includes a function that unpacks dataclass instances
|
|
562
|
+
into individual primitive values, calls to the specified optimized target function
|
|
563
|
+
with decomposed parameters, repacking of results back into appropriate dataclass
|
|
564
|
+
instances, and import management for all required dependencies.
|
|
597
565
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
566
|
+
This bridge module enables seamless integration between high-level dataclass-based
|
|
567
|
+
APIs and low-level optimized implementations, maintaining type safety and usability
|
|
568
|
+
while leveraging performance optimizations that require primitive value operations.
|
|
601
569
|
|
|
602
570
|
Parameters
|
|
603
571
|
----------
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
moduleIdentifier : str
|
|
607
|
-
Name for the generated trimmed module.
|
|
608
|
-
callableIdentifier : str | None = None
|
|
609
|
-
Name for the trimmed computational function.
|
|
610
|
-
logicalPathInfix : PathLike[str] | PurePath | str | None = None
|
|
611
|
-
Directory path for organizing the generated module.
|
|
612
|
-
sourceCallableDispatcher : str | None = None
|
|
613
|
-
Optional dispatcher function identifier (unused).
|
|
572
|
+
astImportFrom : ast.ImportFrom
|
|
573
|
+
Import statement specifying the target optimized function to call.
|
|
614
574
|
|
|
615
575
|
Returns
|
|
616
576
|
-------
|
|
617
|
-
|
|
618
|
-
|
|
577
|
+
None
|
|
578
|
+
The generated module is written directly to the filesystem.
|
|
619
579
|
|
|
620
580
|
"""
|
|
621
|
-
|
|
622
|
-
ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
|
|
623
|
-
ingredientsFunction.astFunctionDef.name = callableIdentifier or sourceCallableIdentifier
|
|
581
|
+
callableIdentifierHARDCODED: str = 'sequential'
|
|
624
582
|
|
|
625
|
-
|
|
583
|
+
algorithmSourceModule: identifierDotAttribute = algorithmSourceModuleDEFAULT
|
|
584
|
+
sourceCallableIdentifier: identifierDotAttribute = sourceCallableDispatcherDEFAULT
|
|
585
|
+
logicalPathSourceModule: identifierDotAttribute = '.'.join([packageSettings.identifierPackage, algorithmSourceModule]) # noqa: FLY002
|
|
626
586
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
587
|
+
logicalPathInfix: identifierDotAttribute = logicalPathInfixDEFAULT
|
|
588
|
+
moduleIdentifier: identifierDotAttribute = dataPackingModuleIdentifierDEFAULT
|
|
589
|
+
callableIdentifier: identifierDotAttribute = callableIdentifierHARDCODED
|
|
590
|
+
|
|
591
|
+
ingredientsFunction: IngredientsFunction = astModuleToIngredientsFunction(parseLogicalPath2astModule(logicalPathSourceModule), sourceCallableIdentifier)
|
|
592
|
+
ingredientsFunction.astFunctionDef.name = callableIdentifier
|
|
593
|
+
|
|
594
|
+
shatteredDataclass: ShatteredDataclass = shatter_dataclassesDOTdataclass(*_findDataclass(ingredientsFunction))
|
|
595
|
+
|
|
596
|
+
ingredientsFunction.imports.update(shatteredDataclass.imports)
|
|
597
|
+
ingredientsFunction.imports.addAst(astImportFrom)
|
|
598
|
+
targetCallableIdentifier = astImportFrom.names[0].name
|
|
599
|
+
ingredientsFunction = raiseIfNone(unpackDataclassCallFunctionRepackDataclass(ingredientsFunction, targetCallableIdentifier, shatteredDataclass))
|
|
600
|
+
targetFunctionDef: ast.FunctionDef = raiseIfNone(extractFunctionDef(parseLogicalPath2astModule(raiseIfNone(astImportFrom.module)), targetCallableIdentifier))
|
|
601
|
+
astTuple: ast.Tuple = cast('ast.Tuple', raiseIfNone(NodeTourist(Be.Return.valueIs(Be.Tuple)
|
|
602
|
+
, doThat=Then.extractIt(DOT.value)).captureLastMatch(targetFunctionDef)))
|
|
603
|
+
astTuple.ctx = ast.Store()
|
|
604
|
+
|
|
605
|
+
changeAssignCallToTarget = NodeChanger(
|
|
606
|
+
findThis = Be.Assign.valueIs(IfThis.isCallIdentifier(targetCallableIdentifier))
|
|
607
|
+
, doThat = Then.replaceWith(Make.Assign([astTuple], value=Make.Call(Make.Name(targetCallableIdentifier), astTuple.elts))))
|
|
608
|
+
changeAssignCallToTarget.visit(ingredientsFunction.astFunctionDef)
|
|
630
609
|
|
|
631
610
|
ingredientsModule = IngredientsModule(ingredientsFunction)
|
|
632
611
|
ingredientsModule.removeImportFromModule('numpy')
|
|
@@ -635,8 +614,6 @@ def trimTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifie
|
|
|
635
614
|
|
|
636
615
|
write_astModule(ingredientsModule, pathFilename, packageSettings.identifierPackage)
|
|
637
616
|
|
|
638
|
-
return pathFilename
|
|
639
|
-
|
|
640
617
|
def numbaOnTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
|
|
641
618
|
"""Generate Numba-accelerated Theorem 2 implementation with dataclass decomposition.
|
|
642
619
|
|
|
@@ -696,61 +673,47 @@ def numbaOnTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdenti
|
|
|
696
673
|
|
|
697
674
|
return pathFilename
|
|
698
675
|
|
|
699
|
-
def
|
|
700
|
-
"""Generate
|
|
676
|
+
def trimTheorem2(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
|
|
677
|
+
"""Generate constrained Theorem 2 implementation by removing unnecessary logic.
|
|
701
678
|
|
|
702
679
|
(AI generated docstring)
|
|
703
680
|
|
|
704
|
-
Creates a
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
into individual primitive values, calls to the specified optimized target function
|
|
708
|
-
with decomposed parameters, repacking of results back into appropriate dataclass
|
|
709
|
-
instances, and import management for all required dependencies.
|
|
681
|
+
Creates a trimmed version of the Theorem 2 implementation by eliminating conditional logic that is not needed under specific
|
|
682
|
+
constraint assumptions. This transformation removes checks for unconstrained dimensions, simplifying the algorithm for cases
|
|
683
|
+
where dimensional constraints are guaranteed to be satisfied by external conditions.
|
|
710
684
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
685
|
+
The trimming operation is particularly valuable for generating lean implementations where the calling context ensures that
|
|
686
|
+
certain conditions will always be met, allowing the removal of defensive programming constructs that add computational
|
|
687
|
+
overhead without providing benefits in the constrained environment.
|
|
714
688
|
|
|
715
689
|
Parameters
|
|
716
690
|
----------
|
|
717
|
-
|
|
718
|
-
|
|
691
|
+
astModule : ast.Module
|
|
692
|
+
Source module containing the Theorem 2 implementation.
|
|
693
|
+
moduleIdentifier : str
|
|
694
|
+
Name for the generated trimmed module.
|
|
695
|
+
callableIdentifier : str | None = None
|
|
696
|
+
Name for the trimmed computational function.
|
|
697
|
+
logicalPathInfix : PathLike[str] | PurePath | str | None = None
|
|
698
|
+
Directory path for organizing the generated module.
|
|
699
|
+
sourceCallableDispatcher : str | None = None
|
|
700
|
+
Optional dispatcher function identifier (unused).
|
|
719
701
|
|
|
720
702
|
Returns
|
|
721
703
|
-------
|
|
722
|
-
|
|
723
|
-
|
|
704
|
+
pathFilename : PurePath
|
|
705
|
+
Filesystem path where the trimmed module was written.
|
|
724
706
|
|
|
725
707
|
"""
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
sourceCallableIdentifier: identifierDotAttribute = sourceCallableDispatcherDEFAULT
|
|
730
|
-
logicalPathSourceModule: identifierDotAttribute = '.'.join([packageSettings.identifierPackage, algorithmSourceModule]) # noqa: FLY002
|
|
731
|
-
|
|
732
|
-
logicalPathInfix: identifierDotAttribute = logicalPathInfixDEFAULT
|
|
733
|
-
moduleIdentifier: identifierDotAttribute = dataPackingModuleIdentifierDEFAULT
|
|
734
|
-
callableIdentifier: identifierDotAttribute = callableIdentifierHARDCODED
|
|
735
|
-
|
|
736
|
-
ingredientsFunction: IngredientsFunction = astModuleToIngredientsFunction(parseLogicalPath2astModule(logicalPathSourceModule), sourceCallableIdentifier)
|
|
737
|
-
ingredientsFunction.astFunctionDef.name = callableIdentifier
|
|
738
|
-
|
|
739
|
-
shatteredDataclass: ShatteredDataclass = shatter_dataclassesDOTdataclass(*_findDataclass(ingredientsFunction))
|
|
708
|
+
sourceCallableIdentifier = sourceCallableIdentifierDEFAULT
|
|
709
|
+
ingredientsFunction = IngredientsFunction(inlineFunctionDef(sourceCallableIdentifier, astModule), LedgerOfImports(astModule))
|
|
710
|
+
ingredientsFunction.astFunctionDef.name = callableIdentifier or sourceCallableIdentifier
|
|
740
711
|
|
|
741
|
-
|
|
742
|
-
ingredientsFunction.imports.addAst(astImportFrom)
|
|
743
|
-
targetCallableIdentifier = astImportFrom.names[0].name
|
|
744
|
-
ingredientsFunction = raiseIfNone(unpackDataclassCallFunctionRepackDataclass(ingredientsFunction, targetCallableIdentifier, shatteredDataclass))
|
|
745
|
-
targetFunctionDef: ast.FunctionDef = raiseIfNone(extractFunctionDef(parseLogicalPath2astModule(raiseIfNone(astImportFrom.module)), targetCallableIdentifier))
|
|
746
|
-
astTuple: ast.Tuple = cast('ast.Tuple', raiseIfNone(NodeTourist(Be.Return.valueIs(Be.Tuple)
|
|
747
|
-
, doThat=Then.extractIt(DOT.value)).captureLastMatch(targetFunctionDef)))
|
|
748
|
-
astTuple.ctx = ast.Store()
|
|
712
|
+
dataclassInstanceIdentifier: identifierDotAttribute = raiseIfNone(NodeTourist(Be.arg, Then.extractIt(DOT.arg)).captureLastMatch(ingredientsFunction.astFunctionDef))
|
|
749
713
|
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
changeAssignCallToTarget.visit(ingredientsFunction.astFunctionDef)
|
|
714
|
+
findThis = IfThis.isIfUnaryNotAttributeNamespaceIdentifier(dataclassInstanceIdentifier, 'dimensionsUnconstrained')
|
|
715
|
+
doThat = Then.removeIt
|
|
716
|
+
NodeChanger(findThis, doThat).visit(ingredientsFunction.astFunctionDef)
|
|
754
717
|
|
|
755
718
|
ingredientsModule = IngredientsModule(ingredientsFunction)
|
|
756
719
|
ingredientsModule.removeImportFromModule('numpy')
|
|
@@ -759,15 +722,17 @@ def makeUnRePackDataclass(astImportFrom: ast.ImportFrom) -> None:
|
|
|
759
722
|
|
|
760
723
|
write_astModule(ingredientsModule, pathFilename, packageSettings.identifierPackage)
|
|
761
724
|
|
|
762
|
-
|
|
763
|
-
astModule: ast.Module = _getModule(logicalPathInfix=None)
|
|
764
|
-
makeInitializeGroupsOfFolds(astModule, 'initializeCount', 'initializeGroupsOfFolds', logicalPathInfixDEFAULT)
|
|
725
|
+
return pathFilename
|
|
765
726
|
|
|
727
|
+
if __name__ == '__main__':
|
|
766
728
|
astModule = _getModule(logicalPathInfix=None)
|
|
767
|
-
pathFilename: PurePath =
|
|
729
|
+
pathFilename: PurePath = makeDaoOfMapFoldingNumba(astModule, 'daoOfMapFoldingNumba', None, logicalPathInfixDEFAULT, sourceCallableDispatcherDEFAULT)
|
|
768
730
|
|
|
769
731
|
astModule = _getModule(logicalPathInfix=None)
|
|
770
|
-
pathFilename =
|
|
732
|
+
pathFilename = makeDaoOfMapFoldingParallelNumba(astModule, 'countParallelNumba', None, logicalPathInfixDEFAULT, sourceCallableDispatcherDEFAULT)
|
|
733
|
+
|
|
734
|
+
astModule: ast.Module = _getModule(logicalPathInfix=None)
|
|
735
|
+
makeInitializeState(astModule, 'initializeState', 'transitionOnGroupsOfFolds', logicalPathInfixDEFAULT)
|
|
771
736
|
|
|
772
737
|
astModule = _getModule(logicalPathInfix=None)
|
|
773
738
|
pathFilename = makeTheorem2(astModule, 'theorem2', None, logicalPathInfixDEFAULT, None)
|
|
@@ -780,3 +745,31 @@ if __name__ == '__main__':
|
|
|
780
745
|
|
|
781
746
|
astImportFrom: ast.ImportFrom = Make.ImportFrom(_getLogicalPath(packageSettings.identifierPackage, logicalPathInfixDEFAULT, 'theorem2Numba'), list_alias=[Make.alias(sourceCallableIdentifierDEFAULT)])
|
|
782
747
|
makeUnRePackDataclass(astImportFrom)
|
|
748
|
+
|
|
749
|
+
# A007822 -----------------------------------------------------------
|
|
750
|
+
astModule = _getModule(logicalPathInfix=None)
|
|
751
|
+
pathFilename = addSymmetryCheck(astModule, 'algorithmA007822', None, logicalPathInfixDEFAULT, None)
|
|
752
|
+
|
|
753
|
+
astModule = _getModule(moduleIdentifier='algorithmA007822')
|
|
754
|
+
pathFilename: PurePath = makeDaoOfMapFoldingNumba(astModule, 'algorithmA007822Numba', None, logicalPathInfixDEFAULT, sourceCallableDispatcherDEFAULT)
|
|
755
|
+
|
|
756
|
+
# I can't handle parallel right now.
|
|
757
|
+
|
|
758
|
+
# TODO Implement logic that lets me amend modules instead of only overwriting them. "initializeState" could/should include state
|
|
759
|
+
# initialization for multiple algorithms.
|
|
760
|
+
astModule = _getModule(moduleIdentifier='algorithmA007822')
|
|
761
|
+
# NOTE `initializeState.transitionOnGroupsOfFolds` will collide with `initializeStateA007822.transitionOnGroupsOfFolds` if the
|
|
762
|
+
# modules are merged. This problem is a side effect of the problem with `MapFoldingState.groupsOfFolds` and
|
|
763
|
+
# `MapFoldingState.foldsTotal`. If I fix that issue, then the identifier `initializeStateA007822.transitionOnGroupsOfFolds` will
|
|
764
|
+
# naturally change to something more appropriate (and remove the collision).
|
|
765
|
+
makeInitializeState(astModule, 'initializeStateA007822', 'transitionOnGroupsOfFolds', logicalPathInfixDEFAULT)
|
|
766
|
+
|
|
767
|
+
astModule = _getModule(moduleIdentifier='algorithmA007822')
|
|
768
|
+
pathFilename = makeTheorem2(astModule, 'theorem2A007822', None, logicalPathInfixDEFAULT, None)
|
|
769
|
+
|
|
770
|
+
astModule = parsePathFilename2astModule(pathFilename)
|
|
771
|
+
pathFilename = trimTheorem2(astModule, 'theorem2A007822Trimmed', None, logicalPathInfixDEFAULT, None)
|
|
772
|
+
|
|
773
|
+
astModule = parsePathFilename2astModule(pathFilename)
|
|
774
|
+
pathFilename = numbaOnTheorem2(astModule, 'theorem2A007822Numba', None, logicalPathInfixDEFAULT, None)
|
|
775
|
+
|
|
@@ -37,7 +37,7 @@ from mapFolding import getPathFilenameFoldsTotal, MapFoldingState, packageSettin
|
|
|
37
37
|
from mapFolding.someAssemblyRequired import IfThis
|
|
38
38
|
from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2
|
|
39
39
|
from mapFolding.someAssemblyRequired.toolkitNumba import decorateCallableWithNumba, parametersNumbaLight, SpicesJobNumba
|
|
40
|
-
from mapFolding.syntheticModules.
|
|
40
|
+
from mapFolding.syntheticModules.initializeState import transitionOnGroupsOfFolds
|
|
41
41
|
from pathlib import PurePosixPath
|
|
42
42
|
from typing import cast, NamedTuple, TYPE_CHECKING
|
|
43
43
|
from typing_extensions import TypeIs
|
|
@@ -326,7 +326,7 @@ if __name__ == '__main__':
|
|
|
326
326
|
"""
|
|
327
327
|
|
|
328
328
|
if __name__ == '__main__':
|
|
329
|
-
state =
|
|
329
|
+
state = transitionOnGroupsOfFolds(MapFoldingState((2,4)))
|
|
330
330
|
pathModule = PurePosixPath(packageSettings.pathPackage, 'jobs')
|
|
331
331
|
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
|
|
332
332
|
aJob = RecipeJobTheorem2(state, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
|
|
@@ -11,7 +11,7 @@ from hunterMakesPy import autoDecodingRLE, raiseIfNone
|
|
|
11
11
|
from mapFolding import DatatypeLeavesTotal, getPathFilenameFoldsTotal, MapFoldingState
|
|
12
12
|
from mapFolding.someAssemblyRequired import IfThis
|
|
13
13
|
from mapFolding.someAssemblyRequired.RecipeJob import RecipeJobTheorem2
|
|
14
|
-
from mapFolding.syntheticModules.
|
|
14
|
+
from mapFolding.syntheticModules.initializeState import transitionOnGroupsOfFolds
|
|
15
15
|
from pathlib import Path, PurePosixPath
|
|
16
16
|
from typing import cast, NamedTuple, TYPE_CHECKING
|
|
17
17
|
import ast
|
|
@@ -212,7 +212,7 @@ def fromMapShape(mapShape: tuple[DatatypeLeavesTotal, ...]) -> None:
|
|
|
212
212
|
along one axis.
|
|
213
213
|
|
|
214
214
|
"""
|
|
215
|
-
state =
|
|
215
|
+
state = transitionOnGroupsOfFolds(MapFoldingState(mapShape))
|
|
216
216
|
pathModule = PurePosixPath(Path.home(), 'mapFolding', 'jobs')
|
|
217
217
|
pathFilenameFoldsTotal = PurePosixPath(getPathFilenameFoldsTotal(state.mapShape, pathModule))
|
|
218
218
|
aJob = RecipeJobTheorem2(state, pathModule=pathModule, pathFilenameFoldsTotal=pathFilenameFoldsTotal)
|