mapFolding 0.15.4__py3-none-any.whl → 0.16.0__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 +7 -9
- mapFolding/_theSSOT.py +1 -0
- mapFolding/algorithms/daoOfMapFolding.py +1 -2
- mapFolding/algorithms/getBucketsTotal.py +137 -0
- mapFolding/algorithms/matrixMeanders.py +457 -286
- mapFolding/algorithms/oeisIDbyFormula.py +310 -76
- mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +84 -0
- mapFolding/basecamp.py +99 -14
- mapFolding/dataBaskets.py +74 -0
- mapFolding/oeis.py +3 -2
- mapFolding/reference/A000682facts.py +662 -0
- mapFolding/reference/A005316facts.py +62 -0
- mapFolding/reference/matrixMeandersAnalysis/__init__.py +1 -0
- mapFolding/reference/matrixMeandersAnalysis/evenEven.py +144 -0
- mapFolding/reference/matrixMeandersAnalysis/oddEven.py +54 -0
- mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +55 -0
- mapFolding/someAssemblyRequired/A007822/__init__.py +0 -0
- mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +185 -0
- mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +71 -0
- mapFolding/someAssemblyRequired/RecipeJob.py +2 -2
- mapFolding/someAssemblyRequired/__init__.py +9 -2
- mapFolding/someAssemblyRequired/_toolIfThis.py +4 -3
- mapFolding/someAssemblyRequired/_toolkitContainers.py +8 -8
- mapFolding/someAssemblyRequired/infoBooth.py +27 -30
- mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +1 -1
- mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +5 -2
- mapFolding/someAssemblyRequired/makingModules_count.py +301 -0
- mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +120 -0
- mapFolding/someAssemblyRequired/mapFolding/__init__.py +0 -0
- mapFolding/someAssemblyRequired/mapFolding/makeMapFoldingModules.py +220 -0
- mapFolding/someAssemblyRequired/toolkitMakeModules.py +152 -0
- mapFolding/someAssemblyRequired/toolkitNumba.py +1 -1
- mapFolding/someAssemblyRequired/transformationTools.py +1 -0
- mapFolding/syntheticModules/A007822/__init__.py +1 -0
- mapFolding/syntheticModules/{algorithmA007822Numba.py → A007822/algorithmNumba.py} +2 -4
- mapFolding/syntheticModules/A007822/asynchronous.py +148 -0
- mapFolding/syntheticModules/A007822/asynchronousAnnex.py +68 -0
- mapFolding/syntheticModules/A007822/asynchronousTheorem2.py +53 -0
- mapFolding/syntheticModules/A007822/asynchronousTrimmed.py +47 -0
- mapFolding/syntheticModules/dataPackingA007822.py +1 -1
- mapFolding/tests/test_computations.py +2 -2
- mapFolding/trim_memory.py +62 -0
- mapFolding/zCuzDocStoopid/__init__.py +1 -0
- mapFolding/zCuzDocStoopid/makeDocstrings.py +63 -0
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.0.dist-info}/METADATA +9 -2
- mapfolding-0.16.0.dist-info/RECORD +100 -0
- mapFolding/someAssemblyRequired/A007822rawMaterials.py +0 -46
- mapFolding/someAssemblyRequired/makeAllModules.py +0 -764
- mapfolding-0.15.4.dist-info/RECORD +0 -78
- /mapFolding/syntheticModules/{algorithmA007822.py → A007822/algorithm.py} +0 -0
- /mapFolding/syntheticModules/{initializeStateA007822.py → A007822/initializeState.py} +0 -0
- /mapFolding/syntheticModules/{theorem2A007822.py → A007822/theorem2.py} +0 -0
- /mapFolding/syntheticModules/{theorem2A007822Numba.py → A007822/theorem2Numba.py} +0 -0
- /mapFolding/syntheticModules/{theorem2A007822Trimmed.py → A007822/theorem2Trimmed.py} +0 -0
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.0.dist-info}/WHEEL +0 -0
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.0.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.0.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.15.4.dist-info → mapfolding-0.16.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Matrix Meanders Buckets Estimation Formula.
|
|
3
|
+
|
|
4
|
+
This module provides a function to estimate the number of buckets in matrix meanders
|
|
5
|
+
analysis based on parameters n and k. The formula was derived through regression
|
|
6
|
+
analysis on empirical data and achieves an R² score of 0.9978.
|
|
7
|
+
|
|
8
|
+
Author: Generated from Jupyter notebook analysis
|
|
9
|
+
Date: September 2025
|
|
10
|
+
"""
|
|
11
|
+
import math
|
|
12
|
+
|
|
13
|
+
def estimateBucketsFromParametersNandK(parameterN: int, parameterK: int) -> float:
|
|
14
|
+
"""
|
|
15
|
+
Estimate the number of buckets in matrix meanders analysis based on parameters n and k.
|
|
16
|
+
|
|
17
|
+
This function implements a log-polynomial regression model derived from empirical data analysis
|
|
18
|
+
of matrix meanders with even-even configurations. The model was trained on 34 data points
|
|
19
|
+
and achieved an R² score of 0.9978, indicating excellent predictive performance.
|
|
20
|
+
|
|
21
|
+
The underlying formula is:
|
|
22
|
+
buckets = exp(0.087760 + 0.447340*n - 0.058715*k - 0.014116*n² + 0.072333*n*k - 0.090631*k²) - 1
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
parameterN : int
|
|
27
|
+
The n parameter (must be positive integer, typically even)
|
|
28
|
+
parameterK : int
|
|
29
|
+
The k parameter (must be positive integer, typically even)
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
float
|
|
34
|
+
Estimated number of buckets
|
|
35
|
+
|
|
36
|
+
Raises
|
|
37
|
+
------
|
|
38
|
+
ValueError
|
|
39
|
+
If parameterN or parameterK are not positive integers
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
--------
|
|
43
|
+
>>> estimateBucketsFromParametersNandK(20, 10)
|
|
44
|
+
3656.4
|
|
45
|
+
>>> estimateBucketsFromParametersNandK(44, 22)
|
|
46
|
+
32715318.1
|
|
47
|
+
|
|
48
|
+
Notes
|
|
49
|
+
-----
|
|
50
|
+
This formula is based on empirical data and is most accurate for values
|
|
51
|
+
within the training range (n: 4-44, k: 2-22). Extrapolation beyond this
|
|
52
|
+
range should be done with caution.
|
|
53
|
+
|
|
54
|
+
The underlying mathematical relationship shows that buckets grow exponentially
|
|
55
|
+
with both n and k, with complex polynomial interactions captured in the logarithmic space.
|
|
56
|
+
|
|
57
|
+
Performance Metrics:
|
|
58
|
+
- R² Score: 0.9978
|
|
59
|
+
- Mean Absolute Error: 4.02% across all training examples
|
|
60
|
+
- Median Error: 2.69%
|
|
61
|
+
- Maximum Error: 18.86% (on smallest values)
|
|
62
|
+
"""
|
|
63
|
+
# Input validation
|
|
64
|
+
if not isinstance(parameterN, int) or parameterN <= 0:
|
|
65
|
+
raise ValueError(f"parameterN must be a positive integer, got {parameterN}")
|
|
66
|
+
if not isinstance(parameterK, int) or parameterK <= 0:
|
|
67
|
+
raise ValueError(f"parameterK must be a positive integer, got {parameterK}")
|
|
68
|
+
|
|
69
|
+
# Convert to float for calculations
|
|
70
|
+
n = float(parameterN)
|
|
71
|
+
k = float(parameterK)
|
|
72
|
+
|
|
73
|
+
# Log-polynomial formula coefficients (derived from regression analysis)
|
|
74
|
+
# Formula: log(buckets + 1) = intercept + c1*n + c2*k + c3*n² + c4*n*k + c5*k²
|
|
75
|
+
interceptValue = 0.087760
|
|
76
|
+
coefficientN = 0.447340
|
|
77
|
+
coefficientK = -0.058715
|
|
78
|
+
coefficientNSquared = -0.014116
|
|
79
|
+
coefficientNTimesK = 0.072333
|
|
80
|
+
coefficientKSquared = -0.090631
|
|
81
|
+
|
|
82
|
+
# Calculate log(buckets + 1)
|
|
83
|
+
logBucketsPlusOne = (interceptValue +
|
|
84
|
+
coefficientN * n +
|
|
85
|
+
coefficientK * k +
|
|
86
|
+
coefficientNSquared * (n * n) +
|
|
87
|
+
coefficientNTimesK * (n * k) +
|
|
88
|
+
coefficientKSquared * (k * k))
|
|
89
|
+
|
|
90
|
+
# Transform back to original scale: buckets = exp(log(buckets + 1)) - 1
|
|
91
|
+
estimatedBuckets = math.exp(logBucketsPlusOne) - 1.0
|
|
92
|
+
|
|
93
|
+
return max(0.0, estimatedBuckets) # Ensure non-negative result
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def validateFormulaAccuracy() -> None:
|
|
97
|
+
"""
|
|
98
|
+
Validate the formula against known test cases from the training data.
|
|
99
|
+
|
|
100
|
+
This function demonstrates the accuracy of the formula by testing it
|
|
101
|
+
against several known data points from the original dataset.
|
|
102
|
+
"""
|
|
103
|
+
# Test cases from the original dataset (n, k, expected_buckets)
|
|
104
|
+
testCases = [
|
|
105
|
+
(4, 2, 4),
|
|
106
|
+
(20, 10, 3592),
|
|
107
|
+
(36, 18, 1666843),
|
|
108
|
+
(44, 22, 35674291)
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
print("Formula Validation Results:")
|
|
112
|
+
print("-" * 50)
|
|
113
|
+
print(f"{'n':<4} {'k':<4} {'Expected':<12} {'Predicted':<12} {'Error %':<8}")
|
|
114
|
+
print("-" * 50)
|
|
115
|
+
|
|
116
|
+
totalError = 0.0
|
|
117
|
+
for n, k, expected in testCases:
|
|
118
|
+
predicted = estimateBucketsFromParametersNandK(n, k)
|
|
119
|
+
error = abs((expected - predicted) / expected) * 100
|
|
120
|
+
totalError += error
|
|
121
|
+
|
|
122
|
+
# Format large numbers appropriately
|
|
123
|
+
expectedStr = f"{expected:.0f}" if expected < 1e6 else f"{expected:.2e}"
|
|
124
|
+
predictedStr = f"{predicted:.1f}" if predicted < 1e6 else f"{predicted:.2e}"
|
|
125
|
+
|
|
126
|
+
print(f"{n:<4} {k:<4} {expectedStr:<12} {predictedStr:<12} {error:<8.1f}")
|
|
127
|
+
|
|
128
|
+
avgError = totalError / len(testCases)
|
|
129
|
+
print("-" * 50)
|
|
130
|
+
print(f"Average Error: {avgError:.2f}%")
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
# Run validation when script is executed directly
|
|
135
|
+
validateFormulaAccuracy()
|
|
136
|
+
|
|
137
|
+
# Demonstrate usage
|
|
138
|
+
print("\nUsage Examples:")
|
|
139
|
+
print("-" * 30)
|
|
140
|
+
|
|
141
|
+
examples = [(8, 4), (20, 10), (36, 18)]
|
|
142
|
+
for n, k in examples:
|
|
143
|
+
result = estimateBucketsFromParametersNandK(n, k)
|
|
144
|
+
print(f"estimateBucketsFromParametersNandK({n}, {k}) = {result:.1f}")
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from math import exp as math_exp, log as math_log
|
|
2
|
+
|
|
3
|
+
def estimateBuckets(n: int, k: int) -> float:
|
|
4
|
+
"""Estimate the number of buckets for given integers n and k.
|
|
5
|
+
|
|
6
|
+
Model form (log-space):
|
|
7
|
+
log(estimate) = a
|
|
8
|
+
+ b * log(n)
|
|
9
|
+
+ c * log(k)
|
|
10
|
+
+ d * log(n)*log(k)
|
|
11
|
+
+ e * (k / n)
|
|
12
|
+
+ f * (n / k)
|
|
13
|
+
|
|
14
|
+
Coefficients were obtained via ordinary least squares fit on log(buckets)
|
|
15
|
+
using the dataset in df_oddEven.csv (38 observations). The regression achieved
|
|
16
|
+
R^2 ≈ {coefficient_determination:.5f} (log space) with MAPE ≈ {mean_absolute_percentage_error:.2f}% on training data.
|
|
17
|
+
|
|
18
|
+
NOTE: This is an empirical approximation; extrapolation outside the range
|
|
19
|
+
n ∈ [{min(n_values)}, {max(n_values)}], k ∈ [{min(k_values)}, {max(k_values)}] may be unreliable.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
n : int
|
|
24
|
+
Primary size parameter (must be > 0)
|
|
25
|
+
k : int
|
|
26
|
+
Secondary size parameter (must be > 0)
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
float
|
|
31
|
+
Estimated bucket count (positive real number). Caller may round if an
|
|
32
|
+
integer is desired.
|
|
33
|
+
"""
|
|
34
|
+
if not isinstance(n, int) or n <= 0:
|
|
35
|
+
raise ValueError(f'allegedInt n must be positive int, got {n!r}')
|
|
36
|
+
if not isinstance(k, int) or k <= 0:
|
|
37
|
+
raise ValueError(f'allegedInt k must be positive int, got {k!r}')
|
|
38
|
+
|
|
39
|
+
a = -679.088264366881
|
|
40
|
+
b = 864.829109159972
|
|
41
|
+
c = -873.871846814867
|
|
42
|
+
d = 3.487829177620
|
|
43
|
+
e = 943.512567960048
|
|
44
|
+
f = -193.640628682536
|
|
45
|
+
|
|
46
|
+
ln_n = math_log(n)
|
|
47
|
+
ln_k = math_log(k)
|
|
48
|
+
value_log = (a
|
|
49
|
+
+ b * ln_n
|
|
50
|
+
+ c * ln_k
|
|
51
|
+
+ d * ln_n * ln_k
|
|
52
|
+
+ e * (k / n)
|
|
53
|
+
+ f * (n / k))
|
|
54
|
+
return math_exp(value_log)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from astToolkit import extractFunctionDef, Make # noqa: D100
|
|
2
|
+
from hunterMakesPy import raiseIfNone
|
|
3
|
+
from mapFolding.someAssemblyRequired import (
|
|
4
|
+
identifierCallableSourceDEFAULT, identifierCallableSourceDispatcherDEFAULT, identifierCountingDEFAULT,
|
|
5
|
+
identifierDataclassInstanceDEFAULT, logicalPathInfixDEFAULT)
|
|
6
|
+
import ast
|
|
7
|
+
|
|
8
|
+
identifierDataclass: str = identifierDataclassInstanceDEFAULT
|
|
9
|
+
identifierCounting: str = identifierCountingDEFAULT
|
|
10
|
+
logicalPathInfixA007822: str = logicalPathInfixDEFAULT + '.A007822'
|
|
11
|
+
sourceCallableDispatcherA007822: str = identifierCallableSourceDispatcherDEFAULT
|
|
12
|
+
sourceCallableIdentifierA007822: str = identifierCallableSourceDEFAULT
|
|
13
|
+
|
|
14
|
+
identifier_filterAsymmetricFolds = 'filterAsymmetricFolds'
|
|
15
|
+
|
|
16
|
+
ImaString = f"""
|
|
17
|
+
def {identifier_filterAsymmetricFolds}({identifierDataclass}: MapFoldingState) -> MapFoldingState:
|
|
18
|
+
{identifierDataclass}.indexLeaf = 0
|
|
19
|
+
leafConnectee = 0
|
|
20
|
+
while leafConnectee < {identifierDataclass}.leavesTotal + 1:
|
|
21
|
+
leafNumber = int({identifierDataclass}.leafBelow[{identifierDataclass}.indexLeaf])
|
|
22
|
+
{identifierDataclass}.leafComparison[leafConnectee] = (leafNumber - {identifierDataclass}.indexLeaf + {identifierDataclass}.leavesTotal) % {identifierDataclass}.leavesTotal
|
|
23
|
+
{identifierDataclass}.indexLeaf = leafNumber
|
|
24
|
+
leafConnectee += 1
|
|
25
|
+
|
|
26
|
+
indexInMiddle = {identifierDataclass}.leavesTotal // 2
|
|
27
|
+
{identifierDataclass}.indexMiniGap = 0
|
|
28
|
+
while {identifierDataclass}.indexMiniGap < {identifierDataclass}.leavesTotal + 1:
|
|
29
|
+
ImaSymmetricFold = True
|
|
30
|
+
leafConnectee = 0
|
|
31
|
+
while leafConnectee < indexInMiddle:
|
|
32
|
+
if {identifierDataclass}.leafComparison[({identifierDataclass}.indexMiniGap + leafConnectee) % ({identifierDataclass}.leavesTotal + 1)] != {identifierDataclass}.leafComparison[({identifierDataclass}.indexMiniGap + {identifierDataclass}.leavesTotal - 1 - leafConnectee) % ({identifierDataclass}.leavesTotal + 1)]:
|
|
33
|
+
ImaSymmetricFold = False
|
|
34
|
+
break
|
|
35
|
+
leafConnectee += 1
|
|
36
|
+
if ImaSymmetricFold:
|
|
37
|
+
{identifierDataclass}.{identifierCounting} += 1
|
|
38
|
+
{identifierDataclass}.indexMiniGap += 1
|
|
39
|
+
|
|
40
|
+
return {identifierDataclass}
|
|
41
|
+
""" # noqa: E501
|
|
42
|
+
|
|
43
|
+
FunctionDef_filterAsymmetricFolds: ast.FunctionDef = raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_filterAsymmetricFolds))
|
|
44
|
+
del ImaString
|
|
45
|
+
|
|
46
|
+
ImaString = f"{identifierDataclass} = {identifier_filterAsymmetricFolds}({identifierDataclass})"
|
|
47
|
+
A007822incrementCount = ast.parse(ImaString).body[0]
|
|
48
|
+
del ImaString
|
|
49
|
+
|
|
50
|
+
ImaString = f'{identifierDataclass}.{identifierCounting} = ({identifierDataclass}.{identifierCounting} + 1) // 2'
|
|
51
|
+
A007822adjustFoldsTotal = ast.parse(ImaString).body[0]
|
|
52
|
+
del ImaString
|
|
53
|
+
|
|
54
|
+
astExprCall_filterAsymmetricFoldsDataclass: ast.Expr = Make.Expr(Make.Call(Make.Name(identifier_filterAsymmetricFolds), listParameters=[Make.Attribute(Make.Name(identifierDataclass), 'leafBelow')]))
|
|
55
|
+
astExprCall_filterAsymmetricFoldsLeafBelow: ast.Expr = Make.Expr(Make.Call(Make.Name(identifier_filterAsymmetricFolds), listParameters=[Make.Name('leafBelow')]))
|
|
File without changes
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""addSymmetryCheckAsynchronous."""
|
|
2
|
+
from astToolkit import Be, extractFunctionDef, Grab, Make, NodeChanger, NodeTourist, parsePathFilename2astModule, Then
|
|
3
|
+
from hunterMakesPy import raiseIfNone
|
|
4
|
+
from mapFolding import packageSettings
|
|
5
|
+
from mapFolding.someAssemblyRequired import IfThis, logicalPathInfixAlgorithmDEFAULT
|
|
6
|
+
from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import (
|
|
7
|
+
A007822adjustFoldsTotal, astExprCall_filterAsymmetricFoldsDataclass, identifier_filterAsymmetricFolds,
|
|
8
|
+
identifierCounting, identifierDataclass, logicalPathInfixA007822, sourceCallableDispatcherA007822,
|
|
9
|
+
sourceCallableIdentifierA007822)
|
|
10
|
+
from mapFolding.someAssemblyRequired.makingModules_count import makeTheorem2, numbaOnTheorem2, trimTheorem2
|
|
11
|
+
from mapFolding.someAssemblyRequired.toolkitMakeModules import getModule, getPathFilename, write_astModule
|
|
12
|
+
from os import PathLike
|
|
13
|
+
from pathlib import PurePath
|
|
14
|
+
import ast
|
|
15
|
+
|
|
16
|
+
identifier_initializeConcurrencyManager = 'initializeConcurrencyManager'
|
|
17
|
+
|
|
18
|
+
astExprCall_initializeConcurrencyManager = Make.Expr(Make.Call(Make.Name(identifier_initializeConcurrencyManager)))
|
|
19
|
+
identifier_getAsymmetricFoldsTotal = 'getAsymmetricFoldsTotal'
|
|
20
|
+
AssignTotal2CountingIdentifier: ast.Assign = Make.Assign(
|
|
21
|
+
[Make.Attribute(Make.Name(identifierDataclass), identifierCounting, context=Make.Store())]
|
|
22
|
+
, value=Make.Call(Make.Name(identifier_getAsymmetricFoldsTotal))
|
|
23
|
+
)
|
|
24
|
+
identifier_processCompletedFutures = '_processCompletedFutures'
|
|
25
|
+
|
|
26
|
+
def addSymmetryCheckAsynchronous(astModule: ast.Module, moduleIdentifier: str, callableIdentifier: str | None = None, logicalPathInfix: PathLike[str] | PurePath | str | None = None, sourceCallableDispatcher: str | None = None) -> PurePath: # noqa: ARG001
|
|
27
|
+
"""Add symmetry check to the counting function."""
|
|
28
|
+
astFunctionDef_count: ast.FunctionDef = raiseIfNone(NodeTourist(
|
|
29
|
+
findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableIdentifierA007822))
|
|
30
|
+
, doThat = Then.extractIt
|
|
31
|
+
).captureLastMatch(astModule))
|
|
32
|
+
|
|
33
|
+
NodeChanger(Be.Return, Then.insertThisAbove([A007822adjustFoldsTotal])).visit(astFunctionDef_count)
|
|
34
|
+
|
|
35
|
+
NodeChanger(
|
|
36
|
+
findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(identifierDataclass, identifierCounting))
|
|
37
|
+
, doThat=Then.replaceWith(astExprCall_filterAsymmetricFoldsDataclass)
|
|
38
|
+
).visit(astFunctionDef_count)
|
|
39
|
+
|
|
40
|
+
NodeChanger(
|
|
41
|
+
findThis=Be.While.testIs(IfThis.isCallIdentifier('activeLeafGreaterThan0'))
|
|
42
|
+
, doThat=Grab.orelseAttribute(Then.replaceWith([AssignTotal2CountingIdentifier]))
|
|
43
|
+
).visit(astFunctionDef_count)
|
|
44
|
+
|
|
45
|
+
NodeChanger(
|
|
46
|
+
findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableIdentifierA007822))
|
|
47
|
+
, doThat=Then.replaceWith(astFunctionDef_count)
|
|
48
|
+
).visit(astModule)
|
|
49
|
+
|
|
50
|
+
astFunctionDef_doTheNeedful: ast.FunctionDef = raiseIfNone(NodeTourist(
|
|
51
|
+
findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableDispatcher))
|
|
52
|
+
, doThat = Then.extractIt
|
|
53
|
+
).captureLastMatch(astModule))
|
|
54
|
+
|
|
55
|
+
astFunctionDef_doTheNeedful.body.insert(0, astExprCall_initializeConcurrencyManager)
|
|
56
|
+
|
|
57
|
+
NodeChanger(
|
|
58
|
+
findThis=Be.FunctionDef.nameIs(IfThis.isIdentifier(sourceCallableDispatcher))
|
|
59
|
+
, doThat=Then.replaceWith(astFunctionDef_doTheNeedful)
|
|
60
|
+
).visit(astModule)
|
|
61
|
+
|
|
62
|
+
astImportFrom = ast.ImportFrom(f'{packageSettings.identifierPackage}.{logicalPathInfix}.{moduleIdentifier}Annex'
|
|
63
|
+
, [Make.alias(identifier_filterAsymmetricFolds), Make.alias(identifier_getAsymmetricFoldsTotal), Make.alias(identifier_initializeConcurrencyManager)], 0)
|
|
64
|
+
|
|
65
|
+
astModule.body.insert(0, astImportFrom)
|
|
66
|
+
|
|
67
|
+
pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
|
|
68
|
+
pathFilenameAnnex: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier + 'Annex')
|
|
69
|
+
|
|
70
|
+
write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
|
|
71
|
+
del astModule
|
|
72
|
+
# ----------------- Ingredients Module Annex ------------------------------------------------------------------------------
|
|
73
|
+
ImaString = """from concurrent.futures import Future as ConcurrentFuture, ProcessPoolExecutor
|
|
74
|
+
from hunterMakesPy import raiseIfNone
|
|
75
|
+
from mapFolding import Array1DLeavesTotal
|
|
76
|
+
from queue import Empty, Queue
|
|
77
|
+
from threading import Thread
|
|
78
|
+
import numpy"""
|
|
79
|
+
|
|
80
|
+
astModule = ast.parse(ImaString)
|
|
81
|
+
del ImaString
|
|
82
|
+
|
|
83
|
+
ImaString = f"""concurrencyManager = None
|
|
84
|
+
{identifierCounting}Total: int = 0
|
|
85
|
+
processingThread = None
|
|
86
|
+
queueFutures: Queue[ConcurrentFuture[int]] = Queue()
|
|
87
|
+
"""
|
|
88
|
+
astModule.body.extend(ast.parse(ImaString).body)
|
|
89
|
+
del ImaString
|
|
90
|
+
|
|
91
|
+
ImaString = f"""def {identifier_initializeConcurrencyManager}(maxWorkers: int | None = None, {identifierCounting}: int = 0) -> None:
|
|
92
|
+
global concurrencyManager, queueFutures, {identifierCounting}Total, processingThread
|
|
93
|
+
concurrencyManager = ProcessPoolExecutor(max_workers=maxWorkers)
|
|
94
|
+
queueFutures = Queue()
|
|
95
|
+
{identifierCounting}Total = {identifierCounting}
|
|
96
|
+
processingThread = Thread(target={identifier_processCompletedFutures})
|
|
97
|
+
processingThread.start()
|
|
98
|
+
"""
|
|
99
|
+
astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_initializeConcurrencyManager)))
|
|
100
|
+
del ImaString
|
|
101
|
+
|
|
102
|
+
ImaString = f"""def {identifier_processCompletedFutures}() -> None:
|
|
103
|
+
global queueFutures, {identifierCounting}Total
|
|
104
|
+
while True:
|
|
105
|
+
try:
|
|
106
|
+
claimTicket: ConcurrentFuture[int] = queueFutures.get(timeout=1)
|
|
107
|
+
if claimTicket is None:
|
|
108
|
+
break
|
|
109
|
+
{identifierCounting}Total += claimTicket.result()
|
|
110
|
+
except Empty:
|
|
111
|
+
continue
|
|
112
|
+
"""
|
|
113
|
+
astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_processCompletedFutures)))
|
|
114
|
+
del ImaString
|
|
115
|
+
|
|
116
|
+
ImaString = f"""def _{identifier_filterAsymmetricFolds}(leafBelow: Array1DLeavesTotal) -> int:
|
|
117
|
+
{identifierCounting} = 0
|
|
118
|
+
leafComparison: Array1DLeavesTotal = numpy.zeros_like(leafBelow)
|
|
119
|
+
leavesTotal = leafBelow.size - 1
|
|
120
|
+
|
|
121
|
+
indexLeaf = 0
|
|
122
|
+
leafConnectee = 0
|
|
123
|
+
while leafConnectee < leavesTotal + 1:
|
|
124
|
+
leafNumber = int(leafBelow[indexLeaf])
|
|
125
|
+
leafComparison[leafConnectee] = (leafNumber - indexLeaf + leavesTotal) % leavesTotal
|
|
126
|
+
indexLeaf = leafNumber
|
|
127
|
+
leafConnectee += 1
|
|
128
|
+
|
|
129
|
+
indexInMiddle = leavesTotal // 2
|
|
130
|
+
indexDistance = 0
|
|
131
|
+
while indexDistance < leavesTotal + 1:
|
|
132
|
+
ImaSymmetricFold = True
|
|
133
|
+
leafConnectee = 0
|
|
134
|
+
while leafConnectee < indexInMiddle:
|
|
135
|
+
if leafComparison[(indexDistance + leafConnectee) % (leavesTotal + 1)] != leafComparison[(indexDistance + leavesTotal - 1 - leafConnectee) % (leavesTotal + 1)]:
|
|
136
|
+
ImaSymmetricFold = False
|
|
137
|
+
break
|
|
138
|
+
leafConnectee += 1
|
|
139
|
+
if ImaSymmetricFold:
|
|
140
|
+
{identifierCounting} += 1
|
|
141
|
+
indexDistance += 1
|
|
142
|
+
return {identifierCounting}
|
|
143
|
+
"""
|
|
144
|
+
astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), f'_{identifier_filterAsymmetricFolds}')))
|
|
145
|
+
del ImaString
|
|
146
|
+
|
|
147
|
+
ImaString = f"""
|
|
148
|
+
def {identifier_filterAsymmetricFolds}(leafBelow: Array1DLeavesTotal) -> None:
|
|
149
|
+
global concurrencyManager, queueFutures
|
|
150
|
+
queueFutures.put(raiseIfNone(concurrencyManager).submit(_{identifier_filterAsymmetricFolds}, leafBelow.copy()))
|
|
151
|
+
"""
|
|
152
|
+
astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_filterAsymmetricFolds)))
|
|
153
|
+
del ImaString
|
|
154
|
+
|
|
155
|
+
ImaString = f"""
|
|
156
|
+
def {identifier_getAsymmetricFoldsTotal}() -> int:
|
|
157
|
+
global concurrencyManager, queueFutures, processingThread
|
|
158
|
+
raiseIfNone(concurrencyManager).shutdown(wait=True)
|
|
159
|
+
queueFutures.put(None)
|
|
160
|
+
raiseIfNone(processingThread).join()
|
|
161
|
+
return {identifierCounting}Total
|
|
162
|
+
"""
|
|
163
|
+
astModule.body.append(raiseIfNone(extractFunctionDef(ast.parse(ImaString), identifier_getAsymmetricFoldsTotal)))
|
|
164
|
+
del ImaString
|
|
165
|
+
|
|
166
|
+
write_astModule(astModule, pathFilenameAnnex, packageSettings.identifierPackage)
|
|
167
|
+
|
|
168
|
+
return pathFilename
|
|
169
|
+
|
|
170
|
+
def _makeA007822AsynchronousModules() -> None:
|
|
171
|
+
|
|
172
|
+
astModule = getModule(logicalPathInfix=logicalPathInfixAlgorithmDEFAULT)
|
|
173
|
+
pathFilename = addSymmetryCheckAsynchronous(astModule, 'asynchronous', None, logicalPathInfixA007822, sourceCallableDispatcherA007822)
|
|
174
|
+
|
|
175
|
+
astModule = getModule(logicalPathInfix=logicalPathInfixA007822, moduleIdentifier='asynchronous')
|
|
176
|
+
pathFilename = makeTheorem2(astModule, 'asynchronousTheorem2', None, logicalPathInfixA007822, None)
|
|
177
|
+
|
|
178
|
+
astModule = parsePathFilename2astModule(pathFilename)
|
|
179
|
+
pathFilename = trimTheorem2(astModule, 'asynchronousTrimmed', None, logicalPathInfixA007822, None)
|
|
180
|
+
|
|
181
|
+
# astModule = parsePathFilename2astModule(pathFilename)
|
|
182
|
+
# pathFilename = numbaOnTheorem2(astModule, 'asynchronousNumba', None, logicalPathInfixA007822, identifier_filterAsymmetricFolds)
|
|
183
|
+
|
|
184
|
+
if __name__ == '__main__':
|
|
185
|
+
_makeA007822AsynchronousModules()
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""addSymmetryCheck."""
|
|
2
|
+
from astToolkit import Be, Make, NodeChanger, NodeTourist, parsePathFilename2astModule, Then
|
|
3
|
+
from hunterMakesPy import raiseIfNone
|
|
4
|
+
from mapFolding import packageSettings
|
|
5
|
+
from mapFolding.someAssemblyRequired import (
|
|
6
|
+
identifierCallableSourceDEFAULT, identifierCountingDEFAULT, identifierDataclassInstanceDEFAULT, IfThis)
|
|
7
|
+
from mapFolding.someAssemblyRequired.A007822.A007822rawMaterials import (
|
|
8
|
+
A007822adjustFoldsTotal, A007822incrementCount, FunctionDef_filterAsymmetricFolds, logicalPathInfixA007822,
|
|
9
|
+
sourceCallableDispatcherA007822, sourceCallableIdentifierA007822)
|
|
10
|
+
from mapFolding.someAssemblyRequired.makingModules_count import (
|
|
11
|
+
makeDaoOfMapFoldingNumba, makeTheorem2, numbaOnTheorem2, trimTheorem2)
|
|
12
|
+
from mapFolding.someAssemblyRequired.makingModules_doTheNeedful import makeInitializeState, makeUnRePackDataclass
|
|
13
|
+
from mapFolding.someAssemblyRequired.toolkitMakeModules import (
|
|
14
|
+
getLogicalPath, getModule, getPathFilename, write_astModule)
|
|
15
|
+
from os import PathLike
|
|
16
|
+
from pathlib import PurePath
|
|
17
|
+
import ast
|
|
18
|
+
|
|
19
|
+
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
|
|
20
|
+
"""Add logic to check for symmetric folds."""
|
|
21
|
+
# NOTE HEY HEY! Are you trying to figure out why there is more than one copy of `filterAsymmetricFolds`? See the TODO NOTE, below.
|
|
22
|
+
|
|
23
|
+
astFunctionDef_count: ast.FunctionDef = raiseIfNone(NodeTourist(
|
|
24
|
+
findThis = Be.FunctionDef.nameIs(IfThis.isIdentifier(identifierCallableSourceDEFAULT))
|
|
25
|
+
, doThat = Then.extractIt
|
|
26
|
+
).captureLastMatch(astModule))
|
|
27
|
+
astFunctionDef_count.name = sourceCallableIdentifierA007822
|
|
28
|
+
|
|
29
|
+
NodeChanger(Be.Return, Then.insertThisAbove([A007822adjustFoldsTotal])).visit(astFunctionDef_count)
|
|
30
|
+
|
|
31
|
+
NodeChanger(
|
|
32
|
+
findThis=Be.AugAssign.targetIs(IfThis.isAttributeNamespaceIdentifier(identifierDataclassInstanceDEFAULT, identifierCountingDEFAULT))
|
|
33
|
+
, doThat=Then.replaceWith(A007822incrementCount)
|
|
34
|
+
).visit(astFunctionDef_count)
|
|
35
|
+
|
|
36
|
+
# TODO NOTE This will insert a copy of `filterAsymmetricFolds` for each `ast.ImportFrom` in the source module. Find or make a
|
|
37
|
+
# system to replace the `Ingredients` paradigm.
|
|
38
|
+
NodeChanger(Be.ImportFrom, Then.insertThisBelow([FunctionDef_filterAsymmetricFolds])).visit(astModule)
|
|
39
|
+
|
|
40
|
+
pathFilename: PurePath = getPathFilename(packageSettings.pathPackage, logicalPathInfix, moduleIdentifier)
|
|
41
|
+
|
|
42
|
+
write_astModule(astModule, pathFilename, packageSettings.identifierPackage)
|
|
43
|
+
|
|
44
|
+
return pathFilename
|
|
45
|
+
|
|
46
|
+
def _makeA007822Modules() -> None:
|
|
47
|
+
astModule = getModule(logicalPathInfix='algorithms')
|
|
48
|
+
pathFilename = addSymmetryCheck(astModule, 'algorithm', None, logicalPathInfixA007822, None)
|
|
49
|
+
|
|
50
|
+
astModule = getModule(logicalPathInfix=logicalPathInfixA007822, moduleIdentifier='algorithm')
|
|
51
|
+
pathFilename: PurePath = makeDaoOfMapFoldingNumba(astModule, 'algorithmNumba', None, logicalPathInfixA007822, sourceCallableDispatcherA007822)
|
|
52
|
+
|
|
53
|
+
# NOTE I can't handle parallel right now.
|
|
54
|
+
|
|
55
|
+
astModule = getModule(logicalPathInfix=logicalPathInfixA007822, moduleIdentifier='algorithm')
|
|
56
|
+
makeInitializeState(astModule, 'initializeState', 'transitionOnGroupsOfFolds', logicalPathInfixA007822)
|
|
57
|
+
|
|
58
|
+
astModule = getModule(logicalPathInfix=logicalPathInfixA007822, moduleIdentifier='algorithm')
|
|
59
|
+
pathFilename = makeTheorem2(astModule, 'theorem2', None, logicalPathInfixA007822, None)
|
|
60
|
+
|
|
61
|
+
astModule = parsePathFilename2astModule(pathFilename)
|
|
62
|
+
pathFilename = trimTheorem2(astModule, 'theorem2Trimmed', None, logicalPathInfixA007822, None)
|
|
63
|
+
|
|
64
|
+
astModule = parsePathFilename2astModule(pathFilename)
|
|
65
|
+
pathFilename = numbaOnTheorem2(astModule, 'theorem2Numba', None, logicalPathInfixA007822, None)
|
|
66
|
+
|
|
67
|
+
astImportFrom: ast.ImportFrom = Make.ImportFrom(getLogicalPath(packageSettings.identifierPackage, logicalPathInfixA007822, 'theorem2Numba'), list_alias=[Make.alias(sourceCallableIdentifierA007822)])
|
|
68
|
+
makeUnRePackDataclass(astImportFrom, 'dataPackingA007822')
|
|
69
|
+
|
|
70
|
+
if __name__ == '__main__':
|
|
71
|
+
_makeA007822Modules()
|
|
@@ -6,7 +6,7 @@ from mapFolding import (
|
|
|
6
6
|
DatatypeElephino as TheDatatypeElephino, DatatypeFoldsTotal as TheDatatypeFoldsTotal,
|
|
7
7
|
DatatypeLeavesTotal as TheDatatypeLeavesTotal, getPathFilenameFoldsTotal, getPathRootJobDEFAULT, MapFoldingState,
|
|
8
8
|
packageSettings)
|
|
9
|
-
from mapFolding.someAssemblyRequired import
|
|
9
|
+
from mapFolding.someAssemblyRequired import identifierDataclassInstanceDEFAULT, ShatteredDataclass
|
|
10
10
|
from mapFolding.someAssemblyRequired.transformationTools import shatter_dataclassesDOTdataclass
|
|
11
11
|
from pathlib import Path, PurePosixPath
|
|
12
12
|
import dataclasses
|
|
@@ -98,7 +98,7 @@ class RecipeJobTheorem2:
|
|
|
98
98
|
"""Logical path to the dataclass module."""
|
|
99
99
|
sourceDataclassIdentifier: str = 'MapFoldingState'
|
|
100
100
|
"""Name of the source dataclass."""
|
|
101
|
-
sourceDataclassInstance: str =
|
|
101
|
+
sourceDataclassInstance: str = identifierDataclassInstanceDEFAULT
|
|
102
102
|
"""Instance identifier for the dataclass."""
|
|
103
103
|
|
|
104
104
|
sourcePathPackage: PurePosixPath | None = PurePosixPath(packageSettings.pathPackage) # noqa: RUF009
|
|
@@ -73,8 +73,15 @@ calculations through the strategic application of compiler optimization techniqu
|
|
|
73
73
|
"""
|
|
74
74
|
|
|
75
75
|
from mapFolding.someAssemblyRequired.infoBooth import (
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
dictionaryEstimatesMapFolding as dictionaryEstimatesMapFolding,
|
|
77
|
+
identifierCallableSourceDEFAULT as identifierCallableSourceDEFAULT,
|
|
78
|
+
identifierCallableSourceDispatcherDEFAULT as identifierCallableSourceDispatcherDEFAULT,
|
|
79
|
+
identifierCountingDEFAULT as identifierCountingDEFAULT,
|
|
80
|
+
identifierDataclassInstanceDEFAULT as identifierDataclassInstanceDEFAULT,
|
|
81
|
+
identifierModuleDataPackingDEFAULT as identifierModuleDataPackingDEFAULT,
|
|
82
|
+
identifierModuleSourceAlgorithmDEFAULT as identifierModuleSourceAlgorithmDEFAULT,
|
|
83
|
+
logicalPathInfixAlgorithmDEFAULT as logicalPathInfixAlgorithmDEFAULT,
|
|
84
|
+
logicalPathInfixDEFAULT as logicalPathInfixDEFAULT,
|
|
78
85
|
)
|
|
79
86
|
|
|
80
87
|
from mapFolding.someAssemblyRequired._toolIfThis import IfThis as IfThis
|
|
@@ -67,7 +67,7 @@ class IfThis(astToolkit_IfThis):
|
|
|
67
67
|
|
|
68
68
|
"""
|
|
69
69
|
return lambda node: (Be.Compare.leftIs(IfThis.isAttributeNamespaceIdentifier(namespace, identifier))(node)
|
|
70
|
-
and Be.Compare.opsIs(
|
|
70
|
+
and Be.Compare.opsIs(Be.at(0, Be.LtE))(node)
|
|
71
71
|
)
|
|
72
72
|
|
|
73
73
|
@staticmethod
|
|
@@ -94,8 +94,9 @@ class IfThis(astToolkit_IfThis):
|
|
|
94
94
|
|
|
95
95
|
"""
|
|
96
96
|
return lambda node: (Be.Compare.leftIs(IfThis.isAttributeNamespaceIdentifier(namespace, identifier))(node)
|
|
97
|
-
and Be.
|
|
98
|
-
and IfThis.isConstant_value(0)(node
|
|
97
|
+
and Be.Compare.opsIs(Be.at(0, Be.Gt))(node)
|
|
98
|
+
and Be.Compare.comparatorsIs(Be.at(0, IfThis.isConstant_value(0)))(node)
|
|
99
|
+
)
|
|
99
100
|
|
|
100
101
|
@staticmethod
|
|
101
102
|
def isIfAttributeNamespaceIdentifierGreaterThan0(namespace: str, identifier: str) -> Callable[[ast.AST], TypeIs[ast.If]]:
|
|
@@ -62,10 +62,10 @@ class ShatteredDataclass:
|
|
|
62
62
|
countingVariableName: ast.Name
|
|
63
63
|
"""AST name node representing the counting variable identifier."""
|
|
64
64
|
|
|
65
|
-
field2AnnAssign: dict[str, ast.AnnAssign | ast.Assign] = dataclasses.field(default_factory=
|
|
65
|
+
field2AnnAssign: dict[str, ast.AnnAssign | ast.Assign] = dataclasses.field(default_factory=dict[str, ast.AnnAssign | ast.Assign])
|
|
66
66
|
"""Maps field names to their corresponding AST assignment expressions for initialization."""
|
|
67
67
|
|
|
68
|
-
Z0Z_field2AnnAssign: dict[str, tuple[ast.AnnAssign | ast.Assign, str]] = dataclasses.field(default_factory=
|
|
68
|
+
Z0Z_field2AnnAssign: dict[str, tuple[ast.AnnAssign | ast.Assign, str]] = dataclasses.field(default_factory=dict[str, tuple[ast.AnnAssign | ast.Assign, str]])
|
|
69
69
|
"""Temporary mapping for field assignments with constructor type information."""
|
|
70
70
|
|
|
71
71
|
fragments4AssignmentOrParameters: ast.Tuple = dummyTuple
|
|
@@ -74,22 +74,22 @@ class ShatteredDataclass:
|
|
|
74
74
|
imports: LedgerOfImports = dataclasses.field(default_factory=LedgerOfImports)
|
|
75
75
|
"""Import records for the dataclass and its constituent field types."""
|
|
76
76
|
|
|
77
|
-
list_argAnnotated4ArgumentsSpecification: list[ast.arg] = dataclasses.field(default_factory=
|
|
77
|
+
list_argAnnotated4ArgumentsSpecification: list[ast.arg] = dataclasses.field(default_factory=list[ast.arg])
|
|
78
78
|
"""Function argument nodes with type annotations for parameter specification."""
|
|
79
79
|
|
|
80
|
-
list_keyword_field__field4init: list[ast.keyword] = dataclasses.field(default_factory=
|
|
80
|
+
list_keyword_field__field4init: list[ast.keyword] = dataclasses.field(default_factory=list[ast.keyword])
|
|
81
81
|
"""Keyword arguments for dataclass initialization using field=field format."""
|
|
82
82
|
|
|
83
|
-
listAnnotations: list[ast.expr] = dataclasses.field(default_factory=
|
|
83
|
+
listAnnotations: list[ast.expr] = dataclasses.field(default_factory=list[ast.expr])
|
|
84
84
|
"""Type annotations for each dataclass field in declaration order."""
|
|
85
85
|
|
|
86
|
-
listName4Parameters: list[ast.Name] = dataclasses.field(default_factory=
|
|
86
|
+
listName4Parameters: list[ast.Name] = dataclasses.field(default_factory=list[ast.Name])
|
|
87
87
|
"""Name nodes for each dataclass field used as function parameters."""
|
|
88
88
|
|
|
89
|
-
listUnpack: list[ast.AnnAssign] = dataclasses.field(default_factory=
|
|
89
|
+
listUnpack: list[ast.AnnAssign] = dataclasses.field(default_factory=list[ast.AnnAssign])
|
|
90
90
|
"""Annotated assignment statements to extract individual fields from dataclass instances."""
|
|
91
91
|
|
|
92
|
-
map_stateDOTfield2Name: dict[ast.AST, ast.Name] = dataclasses.field(default_factory=
|
|
92
|
+
map_stateDOTfield2Name: dict[ast.AST, ast.Name] = dataclasses.field(default_factory=dict[ast.AST, ast.Name])
|
|
93
93
|
"""Maps dataclass attribute access expressions to field name nodes for find-replace operations."""
|
|
94
94
|
|
|
95
95
|
repack: ast.Assign = dummyAssign
|