Skip to content

Commit 62f055c

Browse files
committed
Refactor distinctCrossings to crossings in matrixMeandersPandas and related modules
- Updated variable names and comments to replace 'distinctCrossings' with 'crossings' in matrixMeandersPandas.py. - Adjusted related functions and data structures to reflect the new terminology. - Modified OEIS functions to use 'countTotal' instead of 'foldsTotal' for clarity. - Cleaned up references to distinctCrossings in various files, including dataBaskets and reference files. - Enhanced test coverage for Meanders OEIS sequence calculations. - Bumped version to 0.16.1 in pyproject.toml.
1 parent 4d3e04c commit 62f055c

24 files changed

+563
-417
lines changed

.github/instructions/pandas.instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Row counts:
1818
- When the number of rows is decreasing, the groupby will reduce the number of rows by a large amount.
1919
- The peak number of rows is an estimated: rows = 0.71 * e**(0.4668 * bridges+1); using the value of bridges when passed as a parameter.
2020
- For bridges = 40, the peak is an estimated 146 million rows. MEMORY USAGE IS CRITICAL.
21-
- To discover a new distinctCrossings, the peak rows will be more than 1.5 billion.
21+
- To discover a new value of "crossings", the peak rows will be more than 1.5 billion.
2222

2323
No lambda functions.
2424

easyRun/A000682.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# ruff: noqa
2+
# pyright: basic
3+
from mapFolding.basecamp import NOTcountingFolds
4+
import sys
5+
import warnings
6+
7+
if sys.version_info >= (3, 14):
8+
warnings.filterwarnings("ignore", category=FutureWarning)
9+
10+
def main():
11+
oeisID = 'A000682'
12+
n=45
13+
print(NOTcountingFolds(oeisID, n, 'matrixNumPy'))
14+
15+
from mapFolding import dictionaryOEIS
16+
if n < dictionaryOEIS[oeisID]['valueUnknown']:
17+
print(dictionaryOEIS[oeisID]['valuesKnown'][n])
18+
19+
if __name__ == "__main__":
20+
main()
21+
22+
r"""
23+
deactivate && C:\apps\mapFolding\.vtail\Scripts\activate.bat && title good && cls
24+
title running && py Z0Z_A000682.py && title I'm done || title Error
25+
"""

easyRun/A005316.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# ruff: noqa
2+
# pyright: basic
3+
from mapFolding.basecamp import A005316
4+
import warnings
5+
6+
warnings.filterwarnings("ignore", category=FutureWarning)
7+
8+
n=25
9+
print(A005316(n))
10+
11+
from mapFolding import dictionaryOEIS
12+
13+
if n < dictionaryOEIS['A005316']['valueUnknown']:
14+
print(dictionaryOEIS['A005316']['valuesKnown'][n])
15+
16+
17+
r"""
18+
deactivate && C:\apps\mapFolding\.vtail\Scripts\activate.bat && title good && cls
19+
title running && py Z0Z_A005316.py && title I'm done || title Error
20+
21+
"""

easyRun/NOTcountingFolds.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# ruff: noqa
2+
from mapFolding import dictionaryOEIS
3+
from mapFolding.basecamp import NOTcountingFolds
4+
import sys
5+
import time
6+
7+
if __name__ == '__main__':
8+
def _write() -> None:
9+
sys.stdout.write(
10+
f"{(match:=countTotal == dictionaryOEIS[oeisID]['valuesKnown'][n])}\t"
11+
f"\033[{(not match)*91}m"
12+
f"{n}\t"
13+
f"{countTotal}\t"
14+
f"{time.perf_counter() - timeStart:.2f}\t"
15+
"\033[0m\n"
16+
)
17+
18+
CPUlimit: bool | float | int | None = -2
19+
# oeisID: str | None = None
20+
oeis_n: int | None = None
21+
flow: str | None = None
22+
23+
oeisID = 'A007822'
24+
25+
flow = 'asynchronousTrimmed'
26+
flow = 'asynchronous'
27+
flow = 'asynchronousNumba'
28+
flow = 'algorithm'
29+
flow = 'theorem2Numba'
30+
31+
for n in range(5,11):
32+
33+
timeStart = time.perf_counter()
34+
countTotal = NOTcountingFolds(oeisID, n, flow, CPUlimit)
35+
36+
_write()

easyRun/__init__.py

Whitespace-only changes.

easyRun/countFolds.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# ruff: noqa
2+
# pyright: basic
3+
from collections.abc import Sequence
4+
from mapFolding import countFolds, dictionaryOEISMapFolding
5+
from os import PathLike
6+
from pathlib import PurePath
7+
import sys
8+
import time
9+
10+
if __name__ == '__main__':
11+
def _write() -> None:
12+
sys.stdout.write(
13+
f"{(match:=foldsTotal == dictionaryOEISMapFolding[oeisID]['valuesKnown'][n])}\t"
14+
f"\033[{(not match)*91}m"
15+
f"{n}\t"
16+
f"{foldsTotal}\t"
17+
f"{time.perf_counter() - timeStart:.2f}\t"
18+
"\033[0m\n"
19+
)
20+
21+
listDimensions: Sequence[int] | None = None
22+
pathLikeWriteFoldsTotal: PathLike[str] | PurePath | None = None
23+
computationDivisions: int | str | None = None
24+
CPUlimit: bool | float | int | None = None
25+
# mapShape: tuple[int, ...] | None = None
26+
flow: str | None = 'theorem2Numba'
27+
28+
oeisID: str = 'A001415'
29+
for n in range(3,8):
30+
31+
mapShape: tuple[int, ...] = dictionaryOEISMapFolding[oeisID]['getMapShape'](n)
32+
33+
timeStart = time.perf_counter()
34+
foldsTotal: int = countFolds(listDimensions=listDimensions
35+
, pathLikeWriteFoldsTotal=pathLikeWriteFoldsTotal
36+
, computationDivisions=computationDivisions
37+
, CPUlimit=CPUlimit
38+
, mapShape=mapShape
39+
, flow=flow)
40+
41+
_write()

easyRun/meanders.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# ruff: noqa
2+
# pyright: basic
3+
from mapFolding import dictionaryOEIS
4+
from mapFolding.basecamp import NOTcountingFolds
5+
import gc
6+
import multiprocessing
7+
import sys
8+
import time
9+
import warnings
10+
11+
def write() -> None:
12+
sys.stdout.write(
13+
f"{(booleanColor:=(countTotal == dictionaryOEIS[oeisID]['valuesKnown'][n]))}\t"
14+
f"\033[{(not booleanColor)*91}m"
15+
f"{n}\t"
16+
# f"{countTotal}\t"
17+
# f"{dictionaryOEISMeanders[oeisID]['valuesKnown'][n]}\t"
18+
f"{time.perf_counter() - timeStart:.2f}\t"
19+
"\033[0m\n"
20+
)
21+
22+
if __name__ == '__main__':
23+
multiprocessing.set_start_method('spawn')
24+
if sys.version_info >= (3, 14):
25+
warnings.filterwarnings("ignore", category=FutureWarning)
26+
27+
flow = 'matrixPandas'
28+
flow = 'matrixMeanders'
29+
flow = 'matrixNumPy'
30+
31+
for oeisID in [
32+
'A005316',
33+
'A000682',
34+
]:
35+
sys.stdout.write(f"\n{oeisID}\n")
36+
37+
"""TODO Identifiers. improve
38+
kOfMatrix: I don't think the paper uses 'k'. step?
39+
40+
ReidemeisterMove?
41+
flipTheExtra_0b1AsUfunc: what is extra?
42+
43+
"strand" is an interesting word.
44+
"""
45+
46+
# for n in range(44,45):
47+
48+
# for n in range(43,56):
49+
# for n in range(46,47):
50+
# for n in range(43,47):
51+
# for n in range(38,43):
52+
# for n in range(28,38):
53+
# for n in [*range(2, 10), *range(28,33)]:
54+
# for n in range(28,33):
55+
# for n in range(2, 28):
56+
# for n in range(2, 10):
57+
for n in range(1, 6):
58+
59+
gc.collect()
60+
timeStart = time.perf_counter()
61+
countTotal = NOTcountingFolds(oeisID, n, flow)
62+
if n < dictionaryOEIS[oeisID]['valueUnknown']:
63+
write()
64+
else:
65+
sys.stdout.write(f"{n} {countTotal} {time.perf_counter() - timeStart:.2f}\n")
66+
67+
r"""
68+
deactivate && C:\apps\mapFolding\.vtail\Scripts\activate.bat && title good && cls
69+
title running && py Z0Z_aOFn.py && title I'm done || title Error
70+
71+
"""

mapFolding/_theSSOT.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,14 @@ class mapFoldingPackageSettings(PackageSettings):
9292
"""Local directory path for storing cached OEIS sequence data and metadata."""
9393
OEISidManuallySet: dict[str, MetadataOEISidManuallySet] = {
9494
'A000560': {'valuesTestValidation': [random.randint(3, 12)]},
95-
'A000682': {'valuesTestValidation': [random.randint(3, 12)]},
96-
'A001010': {'valuesTestValidation': [random.randint(3, 11)]},
97-
'A001011': {'valuesTestValidation': [random.randint(3, 7)]},
95+
'A000682': {'valuesTestValidation': [random.randint(3, 12), 32]},
96+
'A001010': {'valuesTestValidation': [3, 4, random.randint(5, 11)]},
97+
'A001011': {'valuesTestValidation': [3, 4, random.randint(5, 7)]},
9898
'A005315': {'valuesTestValidation': [random.randint(3, 9)]},
9999
'A005316': {'valuesTestValidation': [random.randint(3, 13)]},
100100
'A007822': {'valuesTestValidation': [random.randint(2, 8)]}, #, 'valuesBenchmark': [7], 'valuesTestParallelization': [*range(2, 4)]},
101101
'A060206': {'valuesTestValidation': [random.randint(3, 9)]},
102-
'A077460': {'valuesTestValidation': [random.randint(3, 8)]},
102+
'A077460': {'valuesTestValidation': [3, 4, random.randint(5, 8)]},
103103
'A078591': {'valuesTestValidation': [random.randint(3, 10)]},
104104
'A178961': {'valuesTestValidation': [random.randint(3, 11)]},
105105
'A223094': {'valuesTestValidation': [random.randint(3, 11)]},

mapFolding/algorithms/matrixMeanders.py

Lines changed: 20 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from functools import cache
1+
from mapFolding.algorithms.matrixMeandersBeDry import walkDyckPath
22
from mapFolding.dataBaskets import MatrixMeandersState
33

44
def outfitDictionaryBitGroups(state: MatrixMeandersState) -> dict[tuple[int, int], int]:
@@ -12,49 +12,11 @@ def outfitDictionaryBitGroups(state: MatrixMeandersState) -> dict[tuple[int, int
1212
Returns
1313
-------
1414
dictionaryBitGroups : dict[tuple[int, int], int]
15-
A dictionary of `(bitsAlpha, bitsZulu)` to `distinctCrossings`.
15+
A dictionary of `(bitsAlpha, bitsZulu)` to `crossings`.
1616
"""
1717
state.bitWidth = max(state.dictionaryMeanders.keys()).bit_length()
18-
return {(arcCode & state.locatorBits, (arcCode >> 1) & state.locatorBits): distinctCrossings
19-
for arcCode, distinctCrossings in state.dictionaryMeanders.items()}
20-
21-
@cache
22-
def walkDyckPath(intWithExtra_0b1: int) -> int:
23-
"""Find the bit position for flipping paired curve endpoints in meander transfer matrices.
24-
25-
Parameters
26-
----------
27-
intWithExtra_0b1 : int
28-
Binary representation of curve locations with an extra bit encoding parity information.
29-
30-
Returns
31-
-------
32-
flipExtra_0b1_Here : int
33-
Bit mask indicating the position where the balance condition fails, formatted as 2^(2k).
34-
35-
3L33T H@X0R
36-
------------
37-
Binary search for first negative balance in shifted bit pairs. Returns 2^(2k) mask for
38-
bit position k where cumulative balance counter transitions from non-negative to negative.
39-
40-
Mathematics
41-
-----------
42-
Implements the Dyck path balance verification algorithm from Jensen's transfer matrix
43-
enumeration. Computes the position where ∑(i=0 to k) (-1)^b_i < 0 for the first time,
44-
where b_i are the bits of the input at positions 2i.
45-
46-
"""
47-
findTheExtra_0b1: int = 0
48-
flipExtra_0b1_Here: int = 1
49-
while True:
50-
flipExtra_0b1_Here <<= 2
51-
if (intWithExtra_0b1 & flipExtra_0b1_Here) == 0:
52-
findTheExtra_0b1 += 1
53-
else:
54-
findTheExtra_0b1 -= 1
55-
if findTheExtra_0b1 < 0:
56-
break
57-
return flipExtra_0b1_Here
18+
return {(arcCode & state.locatorBits, (arcCode >> 1) & state.locatorBits): crossings
19+
for arcCode, crossings in state.dictionaryMeanders.items()}
5820

5921
def count(state: MatrixMeandersState) -> MatrixMeandersState:
6022
"""Count meanders with matrix transfer algorithm using Python `int` (*int*eger) contained in a Python `dict` (*dict*ionary).
@@ -77,25 +39,25 @@ def count(state: MatrixMeandersState) -> MatrixMeandersState:
7739
dictionaryBitGroups = outfitDictionaryBitGroups(state)
7840
state.dictionaryMeanders = {}
7941

80-
for (bitsAlpha, bitsZulu), distinctCrossings in dictionaryBitGroups.items():
42+
for (bitsAlpha, bitsZulu), crossings in dictionaryBitGroups.items():
8143
bitsAlphaHasArcs: bool = bitsAlpha > 1
8244
bitsZuluHasArcs: bool = bitsZulu > 1
8345
bitsAlphaIsEven = bitsZuluIsEven = 0
8446

85-
arcCurveAnalysis = ((bitsAlpha | (bitsZulu << 1)) << 2) | 3
47+
arcCodeAnalysis = ((bitsAlpha | (bitsZulu << 1)) << 2) | 3
8648
# simple
87-
if arcCurveAnalysis < state.MAXIMUMarcCode:
88-
state.dictionaryMeanders[arcCurveAnalysis] = state.dictionaryMeanders.get(arcCurveAnalysis, 0) + distinctCrossings
49+
if arcCodeAnalysis < state.MAXIMUMarcCode:
50+
state.dictionaryMeanders[arcCodeAnalysis] = state.dictionaryMeanders.get(arcCodeAnalysis, 0) + crossings
8951

9052
if bitsAlphaHasArcs:
91-
arcCurveAnalysis = (bitsAlpha >> 2) | (bitsZulu << 3) | ((bitsAlphaIsEven := 1 - (bitsAlpha & 1)) << 1)
92-
if arcCurveAnalysis < state.MAXIMUMarcCode:
93-
state.dictionaryMeanders[arcCurveAnalysis] = state.dictionaryMeanders.get(arcCurveAnalysis, 0) + distinctCrossings
53+
arcCodeAnalysis = (bitsAlpha >> 2) | (bitsZulu << 3) | ((bitsAlphaIsEven := 1 - (bitsAlpha & 1)) << 1)
54+
if arcCodeAnalysis < state.MAXIMUMarcCode:
55+
state.dictionaryMeanders[arcCodeAnalysis] = state.dictionaryMeanders.get(arcCodeAnalysis, 0) + crossings
9456

9557
if bitsZuluHasArcs:
96-
arcCurveAnalysis = (bitsZulu >> 1) | (bitsAlpha << 2) | (bitsZuluIsEven := 1 - (bitsZulu & 1))
97-
if arcCurveAnalysis < state.MAXIMUMarcCode:
98-
state.dictionaryMeanders[arcCurveAnalysis] = state.dictionaryMeanders.get(arcCurveAnalysis, 0) + distinctCrossings
58+
arcCodeAnalysis = (bitsZulu >> 1) | (bitsAlpha << 2) | (bitsZuluIsEven := 1 - (bitsZulu & 1))
59+
if arcCodeAnalysis < state.MAXIMUMarcCode:
60+
state.dictionaryMeanders[arcCodeAnalysis] = state.dictionaryMeanders.get(arcCodeAnalysis, 0) + crossings
9961

10062
if bitsAlphaHasArcs and bitsZuluHasArcs and (bitsAlphaIsEven or bitsZuluIsEven):
10163
# aligned
@@ -104,16 +66,16 @@ def count(state: MatrixMeandersState) -> MatrixMeandersState:
10466
elif bitsZuluIsEven and not bitsAlphaIsEven:
10567
bitsZulu ^= walkDyckPath(bitsZulu) # noqa: PLW2901
10668

107-
arcCurveAnalysis: int = ((bitsZulu >> 2) << 1) | (bitsAlpha >> 2)
108-
if arcCurveAnalysis < state.MAXIMUMarcCode:
109-
state.dictionaryMeanders[arcCurveAnalysis] = state.dictionaryMeanders.get(arcCurveAnalysis, 0) + distinctCrossings
69+
arcCodeAnalysis: int = ((bitsZulu >> 2) << 1) | (bitsAlpha >> 2)
70+
if arcCodeAnalysis < state.MAXIMUMarcCode:
71+
state.dictionaryMeanders[arcCodeAnalysis] = state.dictionaryMeanders.get(arcCodeAnalysis, 0) + crossings
11072

11173
dictionaryBitGroups = {}
11274

11375
return state
11476

11577
def doTheNeedful(state: MatrixMeandersState) -> int:
116-
"""Compute `distinctCrossings` with a transfer matrix algorithm.
78+
"""Compute `crossings` with a transfer matrix algorithm.
11779
11880
Parameters
11981
----------
@@ -122,8 +84,8 @@ def doTheNeedful(state: MatrixMeandersState) -> int:
12284
12385
Returns
12486
-------
125-
distinctCrossings : int
126-
The computed value of `distinctCrossings`.
87+
crossings : int
88+
The computed value of `crossings`.
12789
12890
Notes
12991
-----

mapFolding/algorithms/matrixMeandersBeDry.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def areIntegersWide(state: MatrixMeandersNumPyState, *, dataframe: pandas.DataFr
3737
state : MatrixMeandersState
3838
The current state of the computation, including `dictionaryMeanders`.
3939
dataframe : pandas.DataFrame | None = None
40-
Optional DataFrame containing 'analyzed' and 'distinctCrossings' columns. If provided, use this instead of `state.dictionaryMeanders`.
40+
Optional DataFrame containing 'analyzed' and 'crossings' columns. If provided, use this instead of `state.dictionaryMeanders`.
4141
fixedSizeMAXIMUMarcCode : bool = False
4242
Set this to `True` if you cast `state.MAXIMUMarcCode` to the same fixed size integer type as `state.datatypeArcCode`.
4343
@@ -57,30 +57,30 @@ def areIntegersWide(state: MatrixMeandersNumPyState, *, dataframe: pandas.DataFr
5757
`MAXIMUMarcCode` to a fixed size merely delays the transition from one function to the other by one iteration.
5858
5959
If you start with small values in `dictionaryMeanders`, however, then the flow goes to the function with fixed size
60-
integers and usually stays there until `distinctCrossings` is huge, which is near the end of the computation. If you cast
60+
integers and usually stays there until `crossings` is huge, which is near the end of the computation. If you cast
6161
`MAXIMUMarcCode` into a 64-bit unsigned integer, however, then around `state.kOfMatrix == 28`, the bit width of
6262
`MAXIMUMarcCode` might exceed the limit. That will cause the flow to go to the function that does not have fixed size
6363
integers for a few iterations before returning to the function with fixed size integers.
6464
"""
6565
if dataframe is not None:
6666
arcCodeWidest = int(dataframe['analyzed'].max()).bit_length()
67-
distinctCrossingsWidest = int(dataframe['distinctCrossings'].max()).bit_length()
67+
crossingsWidest = int(dataframe['crossings'].max()).bit_length()
6868
elif array is not None:
6969
arcCodeWidest = int(array[state.slicerArcCode].max()).bit_length()
70-
distinctCrossingsWidest = int(array[state.slicerDistinctCrossings].max()).bit_length()
70+
crossingsWidest = int(array[state.slicerCrossings].max()).bit_length()
7171
elif not state.dictionaryMeanders:
7272
arcCodeWidest = int(state.arrayMeanders[state.slicerArcCode].max()).bit_length()
73-
distinctCrossingsWidest = int(state.arrayMeanders[state.slicerDistinctCrossings].max()).bit_length()
73+
crossingsWidest = int(state.arrayMeanders[state.slicerCrossings].max()).bit_length()
7474
else:
7575
arcCodeWidest: int = max(state.dictionaryMeanders.keys()).bit_length()
76-
distinctCrossingsWidest: int = max(state.dictionaryMeanders.values()).bit_length()
76+
crossingsWidest: int = max(state.dictionaryMeanders.values()).bit_length()
7777

7878
MAXIMUMarcCode: int = 0
7979
if fixedSizeMAXIMUMarcCode:
8080
MAXIMUMarcCode = state.MAXIMUMarcCode
8181

8282
return (arcCodeWidest > raiseIfNone(state.bitWidthLimitArcCode)
83-
or distinctCrossingsWidest > raiseIfNone(state.bitWidthLimitDistinctCrossings)
83+
or crossingsWidest > raiseIfNone(state.bitWidthLimitCrossings)
8484
or MAXIMUMarcCode > raiseIfNone(state.bitWidthLimitArcCode)
8585
)
8686

0 commit comments

Comments
 (0)