mapFolding 0.13.1__py3-none-any.whl → 0.14.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/_oeisFormulas/A000136.py +4 -0
- mapFolding/_oeisFormulas/A000560.py +4 -0
- mapFolding/_oeisFormulas/A000682.py +17 -0
- mapFolding/_oeisFormulas/A005315.py +4 -0
- mapFolding/_oeisFormulas/A005316.py +10 -0
- mapFolding/_oeisFormulas/A223094.py +7 -0
- mapFolding/_oeisFormulas/A259702.py +4 -0
- mapFolding/_oeisFormulas/A301620.py +6 -0
- mapFolding/_oeisFormulas/Z0Z_aOFn.py +19 -0
- mapFolding/_oeisFormulas/Z0Z_oeisMeanders.py +53 -0
- mapFolding/_oeisFormulas/__init__.py +1 -0
- mapFolding/_oeisFormulas/matrixMeanders.py +65 -0
- mapFolding/_oeisFormulas/matrixMeandersAnnex.py +84 -0
- mapFolding/_theSSOT.py +68 -26
- mapFolding/basecamp.py +2 -2
- mapFolding/beDRY.py +1 -1
- mapFolding/oeis.py +56 -167
- mapFolding/reference/A005316JavaPort.py +134 -0
- mapFolding/reference/A005316imperative.py +101 -0
- mapFolding/reference/A005316intOptimized.py +122 -0
- mapFolding/reference/A005316optimized128bit.py +79 -0
- mapFolding/reference/A005316primitiveOptimized.py +97 -0
- mapFolding/reference/A005316redis.py +118 -0
- mapFolding/reference/A005316write2disk.py +169 -0
- mapFolding/reference/irvineJavaPort.py +4 -8
- mapFolding/reference/matrixMeandersBaseline.py +65 -0
- mapFolding/reference/matrixMeandersBaselineAnnex.py +84 -0
- mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +45 -17
- mapFolding/tests/conftest.py +13 -13
- mapFolding/tests/test_computations.py +4 -4
- mapFolding/tests/test_oeis.py +7 -14
- mapfolding-0.14.0.dist-info/METADATA +78 -0
- {mapfolding-0.13.1.dist-info → mapfolding-0.14.0.dist-info}/RECORD +37 -15
- mapfolding-0.13.1.dist-info/METADATA +0 -154
- {mapfolding-0.13.1.dist-info → mapfolding-0.14.0.dist-info}/WHEEL +0 -0
- {mapfolding-0.13.1.dist-info → mapfolding-0.14.0.dist-info}/entry_points.txt +0 -0
- {mapfolding-0.13.1.dist-info → mapfolding-0.14.0.dist-info}/licenses/LICENSE +0 -0
- {mapfolding-0.13.1.dist-info → mapfolding-0.14.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
from hunterMakesPy import raiseIfNone
|
|
3
|
+
|
|
4
|
+
class BasicMeanderProblem:
|
|
5
|
+
|
|
6
|
+
def __init__(self, remainingBridges: int) -> None:
|
|
7
|
+
self.remainingBridges = remainingBridges
|
|
8
|
+
self.archStateLimit = 1 << (2 + (2 * (remainingBridges + 1)))
|
|
9
|
+
self.bridgesTotalIsOdd = (remainingBridges & 1) == 1
|
|
10
|
+
|
|
11
|
+
def initializeA005316(self) -> list[int]:
|
|
12
|
+
if self.bridgesTotalIsOdd:
|
|
13
|
+
bitPattern = (1 << 2) | 1
|
|
14
|
+
bitPattern <<= 2
|
|
15
|
+
return [bitPattern | 1 << 1]
|
|
16
|
+
else:
|
|
17
|
+
bitPattern = (1 << 2) | 1
|
|
18
|
+
return [bitPattern | bitPattern << 1]
|
|
19
|
+
|
|
20
|
+
def initializeA000682(self) -> list[int]:
|
|
21
|
+
initialStatesList: list[int] = []
|
|
22
|
+
bitPattern = 1 if self.bridgesTotalIsOdd else ((1 << 2) | 1)
|
|
23
|
+
|
|
24
|
+
packedState = bitPattern | bitPattern << 1
|
|
25
|
+
while packedState < self.archStateLimit:
|
|
26
|
+
initialStatesList.append(packedState)
|
|
27
|
+
bitPattern = ((bitPattern << 2) | 1) << 2 | 1
|
|
28
|
+
packedState = bitPattern | bitPattern << 1
|
|
29
|
+
|
|
30
|
+
return initialStatesList
|
|
31
|
+
|
|
32
|
+
def enumerate(self, packedState: int) -> list[int]: # noqa: C901
|
|
33
|
+
bitMask = 0x5555555555555555
|
|
34
|
+
bitWidth = 64
|
|
35
|
+
while bitMask < packedState:
|
|
36
|
+
bitMask |= bitMask << bitWidth
|
|
37
|
+
bitWidth += bitWidth
|
|
38
|
+
lower: int = packedState & bitMask
|
|
39
|
+
upper: int = (packedState - lower) >> 1
|
|
40
|
+
nextStatesList: list[int] = []
|
|
41
|
+
|
|
42
|
+
if lower != 1:
|
|
43
|
+
nextState: int = (lower >> 2 | (((upper << 2) ^ (1 if (lower & 1) == 0 else 0)) << 1))
|
|
44
|
+
if nextState < self.archStateLimit:
|
|
45
|
+
nextStatesList.append(nextState)
|
|
46
|
+
|
|
47
|
+
if upper != 1:
|
|
48
|
+
nextState = (((lower << 2) ^ (1 if (upper & 1) == 0 else 0)) | (upper >> 2) << 1)
|
|
49
|
+
if nextState < self.archStateLimit:
|
|
50
|
+
nextStatesList.append(nextState)
|
|
51
|
+
|
|
52
|
+
nextState = ((lower << 2) | 1 | ((upper << 2) | 1) << 1)
|
|
53
|
+
if nextState < self.archStateLimit:
|
|
54
|
+
nextStatesList.append(nextState)
|
|
55
|
+
|
|
56
|
+
if lower != 1 and upper != 1 and ((lower & 1) == 0 or (upper & 1) == 0):
|
|
57
|
+
if (lower & 1) == 0 and (upper & 1) == 1:
|
|
58
|
+
archBalance = 0
|
|
59
|
+
bitPosition = 1
|
|
60
|
+
while archBalance >= 0:
|
|
61
|
+
bitPosition <<= 2
|
|
62
|
+
archBalance += 1 if (lower & bitPosition) == 0 else -1
|
|
63
|
+
lower ^= bitPosition
|
|
64
|
+
if (upper & 1) == 0 and (lower & 1) == 1:
|
|
65
|
+
archBalance = 0
|
|
66
|
+
bitPosition = 1
|
|
67
|
+
while archBalance >= 0:
|
|
68
|
+
bitPosition <<= 2
|
|
69
|
+
archBalance += 1 if (upper & bitPosition) == 0 else -1
|
|
70
|
+
upper ^= bitPosition
|
|
71
|
+
nextState = (lower >> 2 | (upper >> 2) << 1)
|
|
72
|
+
if nextState < self.archStateLimit:
|
|
73
|
+
nextStatesList.append(nextState)
|
|
74
|
+
|
|
75
|
+
return nextStatesList
|
|
76
|
+
|
|
77
|
+
class SimpleProcessor:
|
|
78
|
+
|
|
79
|
+
def __init__(self) -> None:
|
|
80
|
+
self.createStateMachine: type | None = None
|
|
81
|
+
self.totalTransitions = 0
|
|
82
|
+
|
|
83
|
+
def setCreateStateMachine(self, stateMachineCreator: type) -> None:
|
|
84
|
+
self.createStateMachine = stateMachineCreator
|
|
85
|
+
|
|
86
|
+
def process(self, bridgesCount: int, initialStates: Iterable[int]) -> int:
|
|
87
|
+
stateCounts: list[tuple[int, int]] = [(state, 1) for state in initialStates]
|
|
88
|
+
|
|
89
|
+
self.createStateMachine = raiseIfNone(self.createStateMachine, "State machine creator must be set before processing.")
|
|
90
|
+
bridgesRemaining: int = bridgesCount
|
|
91
|
+
while bridgesRemaining > 0:
|
|
92
|
+
bridgesRemaining -= 1
|
|
93
|
+
stateCounts = self._accumulate(self.createStateMachine(bridgesRemaining), stateCounts)
|
|
94
|
+
|
|
95
|
+
return sum(count for state, count in stateCounts)
|
|
96
|
+
|
|
97
|
+
def _accumulate(self, layer: BasicMeanderProblem, previousCounts: list[tuple[int, int]]) -> list[tuple[int, int]]:
|
|
98
|
+
stateCountsDict: dict[int, int] = {}
|
|
99
|
+
transitions: int = 0
|
|
100
|
+
|
|
101
|
+
for state, count in previousCounts:
|
|
102
|
+
for nextState in layer.enumerate(state):
|
|
103
|
+
if nextState in stateCountsDict:
|
|
104
|
+
stateCountsDict[nextState] += count
|
|
105
|
+
else:
|
|
106
|
+
stateCountsDict[nextState] = count
|
|
107
|
+
transitions += 1
|
|
108
|
+
|
|
109
|
+
self.totalTransitions += transitions
|
|
110
|
+
return list(stateCountsDict.items())
|
|
111
|
+
|
|
112
|
+
def A005316(n: int) -> int:
|
|
113
|
+
processor = SimpleProcessor()
|
|
114
|
+
processor.setCreateStateMachine(BasicMeanderProblem)
|
|
115
|
+
meanderProblem = BasicMeanderProblem(n)
|
|
116
|
+
return processor.process(n, meanderProblem.initializeA005316())
|
|
117
|
+
|
|
118
|
+
def A000682(n: int) -> int:
|
|
119
|
+
processor = SimpleProcessor()
|
|
120
|
+
processor.setCreateStateMachine(BasicMeanderProblem)
|
|
121
|
+
meanderProblem = BasicMeanderProblem(n-1)
|
|
122
|
+
return processor.process(n-1, meanderProblem.initializeA000682())
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
def count(bridges: int, dictionaryCurveLocationsKnown: dict[int, int]) -> int:
|
|
2
|
+
while bridges > 0:
|
|
3
|
+
bridges -= 1
|
|
4
|
+
curveLocationsMAXIMUM = 1 << (2 * bridges + 4)
|
|
5
|
+
dictionaryCurveLocationsDiscovered: dict[int, int] = {}
|
|
6
|
+
|
|
7
|
+
for curveLocations, distinctCrossings in dictionaryCurveLocationsKnown.items():
|
|
8
|
+
bifurcationOdd = curveLocations & 0x5555555555555555555555555555555555555555555555555555555555555555
|
|
9
|
+
bifurcationEven = (curveLocations ^ bifurcationOdd) >> 1
|
|
10
|
+
|
|
11
|
+
bifurcationOddHasCurves = bifurcationOdd != 1
|
|
12
|
+
bifurcationEvenHasCurves = bifurcationEven != 1
|
|
13
|
+
bifurcationOddFinalZero = not bifurcationOdd & 1
|
|
14
|
+
bifurcationEvenFinalZero = not bifurcationEven & 1
|
|
15
|
+
|
|
16
|
+
if bifurcationOddHasCurves:
|
|
17
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | (bifurcationEven << 3) | (bifurcationOddFinalZero << 1)
|
|
18
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
19
|
+
dictionaryCurveLocationsDiscovered[curveLocationAnalysis] = dictionaryCurveLocationsDiscovered.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
20
|
+
|
|
21
|
+
if bifurcationEvenHasCurves:
|
|
22
|
+
curveLocationAnalysis = (bifurcationEven >> 1) | (bifurcationOdd << 2) | bifurcationEvenFinalZero
|
|
23
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
24
|
+
dictionaryCurveLocationsDiscovered[curveLocationAnalysis] = dictionaryCurveLocationsDiscovered.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
25
|
+
|
|
26
|
+
curveLocationAnalysis = ((bifurcationOdd | (bifurcationEven << 1)) << 2) | 3
|
|
27
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
28
|
+
dictionaryCurveLocationsDiscovered[curveLocationAnalysis] = dictionaryCurveLocationsDiscovered.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
29
|
+
|
|
30
|
+
if bifurcationOddHasCurves and bifurcationEvenHasCurves and (bifurcationOddFinalZero or bifurcationEvenFinalZero):
|
|
31
|
+
XOrHere2makePair = 0b1
|
|
32
|
+
findUnpairedBinary1 = 0
|
|
33
|
+
if bifurcationOddFinalZero and not bifurcationEvenFinalZero:
|
|
34
|
+
while findUnpairedBinary1 >= 0:
|
|
35
|
+
XOrHere2makePair <<= 2
|
|
36
|
+
findUnpairedBinary1 += 1 if (bifurcationOdd & XOrHere2makePair) == 0 else -1
|
|
37
|
+
bifurcationOdd ^= XOrHere2makePair
|
|
38
|
+
|
|
39
|
+
elif bifurcationEvenFinalZero and not bifurcationOddFinalZero:
|
|
40
|
+
while findUnpairedBinary1 >= 0:
|
|
41
|
+
XOrHere2makePair <<= 2
|
|
42
|
+
findUnpairedBinary1 += 1 if (bifurcationEven & XOrHere2makePair) == 0 else -1
|
|
43
|
+
bifurcationEven ^= XOrHere2makePair
|
|
44
|
+
|
|
45
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | ((bifurcationEven >> 2) << 1)
|
|
46
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
47
|
+
dictionaryCurveLocationsDiscovered[curveLocationAnalysis] = dictionaryCurveLocationsDiscovered.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
48
|
+
|
|
49
|
+
dictionaryCurveLocationsKnown = dictionaryCurveLocationsDiscovered
|
|
50
|
+
|
|
51
|
+
return sum(dictionaryCurveLocationsKnown.values())
|
|
52
|
+
|
|
53
|
+
def initializeA005316(n: int) -> dict[int, int]:
|
|
54
|
+
if n & 1:
|
|
55
|
+
return {22: 1}
|
|
56
|
+
else:
|
|
57
|
+
return {15: 1}
|
|
58
|
+
|
|
59
|
+
def initializeA000682(n: int) -> dict[int, int]:
|
|
60
|
+
stateToCount: dict[int, int] = {}
|
|
61
|
+
|
|
62
|
+
curveLocationsMAXIMUM = 1 << (2 * n + 4)
|
|
63
|
+
|
|
64
|
+
bitPattern = 5 - (n & 1) * 4
|
|
65
|
+
|
|
66
|
+
packedState = bitPattern | (bitPattern << 1)
|
|
67
|
+
while packedState < curveLocationsMAXIMUM:
|
|
68
|
+
stateToCount[packedState] = 1
|
|
69
|
+
bitPattern = ((bitPattern << 4) | 0b0101)
|
|
70
|
+
packedState = bitPattern | (bitPattern << 1)
|
|
71
|
+
|
|
72
|
+
return stateToCount
|
|
73
|
+
|
|
74
|
+
def A005316(n: int) -> int:
|
|
75
|
+
return count(n, initializeA005316(n))
|
|
76
|
+
|
|
77
|
+
def A000682(n: int) -> int:
|
|
78
|
+
return count(n - 1, initializeA000682(n - 1))
|
|
79
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
bifurcationOddLocator = 0x55555555555555555555555555555555
|
|
2
|
+
bitWidth = 1 << (bifurcationOddLocator.bit_length() - 1).bit_length()
|
|
3
|
+
|
|
4
|
+
def count(bridges: int, dictionaryCurveLocationsKnown: dict[int, int]) -> int:
|
|
5
|
+
while bridges > 0:
|
|
6
|
+
bridges -= 1
|
|
7
|
+
curveLocationsMAXIMUM = 1 << (2 + (2 * (bridges + 1)))
|
|
8
|
+
|
|
9
|
+
dictionaryCurveLocationsDiscovered: dict[int, int] = {}
|
|
10
|
+
|
|
11
|
+
for curveLocations, distinctCrossings in dictionaryCurveLocationsKnown.items():
|
|
12
|
+
global bifurcationOddLocator, bitWidth # noqa: PLW0603
|
|
13
|
+
|
|
14
|
+
if curveLocations > bifurcationOddLocator:
|
|
15
|
+
while curveLocations > bifurcationOddLocator:
|
|
16
|
+
bifurcationOddLocator |= bifurcationOddLocator << bitWidth
|
|
17
|
+
bitWidth <<= 1
|
|
18
|
+
|
|
19
|
+
bifurcationOdd = curveLocations & bifurcationOddLocator
|
|
20
|
+
bifurcationEven = (curveLocations ^ bifurcationOdd) >> 1
|
|
21
|
+
|
|
22
|
+
bifurcationOddHasCurves = bifurcationOdd != 1
|
|
23
|
+
bifurcationEvenHasCurves = bifurcationEven != 1
|
|
24
|
+
bifurcationOddFinalZero = (bifurcationOdd & 1) == 0
|
|
25
|
+
bifurcationEvenFinalZero = (bifurcationEven & 1) == 0
|
|
26
|
+
|
|
27
|
+
if bifurcationOddHasCurves:
|
|
28
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | (bifurcationEven << 3) | (bifurcationOddFinalZero << 1)
|
|
29
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
30
|
+
dictionaryCurveLocationsDiscovered[curveLocationAnalysis] = dictionaryCurveLocationsDiscovered.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
31
|
+
|
|
32
|
+
if bifurcationEvenHasCurves:
|
|
33
|
+
curveLocationAnalysis = (bifurcationEven >> 1) | ((bifurcationOdd << 2) | bifurcationEvenFinalZero)
|
|
34
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
35
|
+
dictionaryCurveLocationsDiscovered[curveLocationAnalysis] = dictionaryCurveLocationsDiscovered.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
36
|
+
|
|
37
|
+
curveLocationAnalysis = ((bifurcationOdd | (bifurcationEven << 1)) << 2) | 3
|
|
38
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
39
|
+
dictionaryCurveLocationsDiscovered[curveLocationAnalysis] = dictionaryCurveLocationsDiscovered.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
40
|
+
|
|
41
|
+
if bifurcationOddHasCurves and bifurcationEvenHasCurves and (bifurcationOddFinalZero or bifurcationEvenFinalZero):
|
|
42
|
+
if bifurcationOddFinalZero and not bifurcationEvenFinalZero:
|
|
43
|
+
Z0Z_idk = 0
|
|
44
|
+
Z0Z_indexIDK = 1
|
|
45
|
+
while Z0Z_idk >= 0:
|
|
46
|
+
Z0Z_indexIDK <<= 2
|
|
47
|
+
Z0Z_idk += 1 if (bifurcationOdd & Z0Z_indexIDK) == 0 else -1
|
|
48
|
+
bifurcationOdd ^= Z0Z_indexIDK
|
|
49
|
+
|
|
50
|
+
if bifurcationEvenFinalZero and not bifurcationOddFinalZero:
|
|
51
|
+
Z0Z_idk = 0
|
|
52
|
+
Z0Z_indexIDK = 1
|
|
53
|
+
while Z0Z_idk >= 0:
|
|
54
|
+
Z0Z_indexIDK <<= 2
|
|
55
|
+
Z0Z_idk += 1 if (bifurcationEven & Z0Z_indexIDK) == 0 else -1
|
|
56
|
+
bifurcationEven ^= Z0Z_indexIDK
|
|
57
|
+
|
|
58
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | ((bifurcationEven >> 2) << 1)
|
|
59
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
60
|
+
dictionaryCurveLocationsDiscovered[curveLocationAnalysis] = dictionaryCurveLocationsDiscovered.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
61
|
+
|
|
62
|
+
dictionaryCurveLocationsKnown = dictionaryCurveLocationsDiscovered
|
|
63
|
+
|
|
64
|
+
return sum(dictionaryCurveLocationsKnown.values())
|
|
65
|
+
|
|
66
|
+
def initializeA005316(n: int) -> dict[int, int]:
|
|
67
|
+
bridgesTotalIsOdd = (n & 1) == 1
|
|
68
|
+
if bridgesTotalIsOdd:
|
|
69
|
+
arrayBitPattern = (1 << 2) | 1
|
|
70
|
+
arrayBitPattern <<= 2
|
|
71
|
+
initialState = arrayBitPattern | 1 << 1
|
|
72
|
+
return {initialState: 1}
|
|
73
|
+
else:
|
|
74
|
+
arrayBitPattern = (1 << 2) | 1
|
|
75
|
+
initialState = arrayBitPattern | arrayBitPattern << 1
|
|
76
|
+
return {initialState: 1}
|
|
77
|
+
|
|
78
|
+
def initializeA000682(n: int) -> dict[int, int]:
|
|
79
|
+
bridgesTotalIsOdd = (n & 1) == 1
|
|
80
|
+
archStateLimit = 1 << (2 + (2 * (n + 1)))
|
|
81
|
+
|
|
82
|
+
dictionaryStateToTotal: dict[int, int] = {}
|
|
83
|
+
arrayBitPattern = 1 if bridgesTotalIsOdd else ((1 << 2) | 1)
|
|
84
|
+
|
|
85
|
+
arrayPackedState = arrayBitPattern | arrayBitPattern << 1
|
|
86
|
+
while arrayPackedState < archStateLimit:
|
|
87
|
+
dictionaryStateToTotal[arrayPackedState] = 1
|
|
88
|
+
arrayBitPattern = ((arrayBitPattern << 2) | 1) << 2 | 1
|
|
89
|
+
arrayPackedState = arrayBitPattern | arrayBitPattern << 1
|
|
90
|
+
|
|
91
|
+
return dictionaryStateToTotal
|
|
92
|
+
|
|
93
|
+
def A005316(n: int) -> int:
|
|
94
|
+
return count(n, initializeA005316(n))
|
|
95
|
+
|
|
96
|
+
def A000682(n: int) -> int:
|
|
97
|
+
return count(n - 1, initializeA000682(n - 1))
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import redis
|
|
2
|
+
|
|
3
|
+
def count(bridges: int, curveLocationsKnown: dict[int, int]) -> int:
|
|
4
|
+
# Initialize Redis connection
|
|
5
|
+
redisClient = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
|
|
6
|
+
|
|
7
|
+
# Load initial data into Redis
|
|
8
|
+
redisClient.flushdb()
|
|
9
|
+
for key, value in curveLocationsKnown.items():
|
|
10
|
+
redisClient.set(f"known:{key}", str(value))
|
|
11
|
+
|
|
12
|
+
while bridges > 0:
|
|
13
|
+
bridges -= 1
|
|
14
|
+
curveLocationsMAXIMUM = 1 << (2 * bridges + 4)
|
|
15
|
+
|
|
16
|
+
# Clear discovered data in Redis
|
|
17
|
+
for key in redisClient.scan_iter(match="discovered:*"):
|
|
18
|
+
redisClient.delete(key)
|
|
19
|
+
|
|
20
|
+
def storeCurveLocations(curveLocationAnalysis: int, distinctCrossings: int,
|
|
21
|
+
curveLocationsMAXIMUM: int = curveLocationsMAXIMUM,
|
|
22
|
+
redisClient: redis.Redis = redisClient) -> None:
|
|
23
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
24
|
+
keyName = f"discovered:{curveLocationAnalysis}"
|
|
25
|
+
existingValue = redisClient.get(keyName)
|
|
26
|
+
if existingValue is not None:
|
|
27
|
+
newValue = int(existingValue) + distinctCrossings
|
|
28
|
+
else:
|
|
29
|
+
newValue = distinctCrossings
|
|
30
|
+
redisClient.set(keyName, str(newValue))
|
|
31
|
+
|
|
32
|
+
# Process all known curve locations from Redis
|
|
33
|
+
for keyName in redisClient.scan_iter(match="known:*"):
|
|
34
|
+
curveLocations = int(str(keyName).split(":")[1])
|
|
35
|
+
distinctCrossings = int(str(redisClient.get(keyName)))
|
|
36
|
+
|
|
37
|
+
bifurcationOdd = curveLocations & 0x5555555555555555555555555555555555555555555555555555555555555555
|
|
38
|
+
bifurcationEven = (curveLocations ^ bifurcationOdd) >> 1
|
|
39
|
+
|
|
40
|
+
bifurcationOddHasCurves = bifurcationOdd != 1
|
|
41
|
+
bifurcationEvenHasCurves = bifurcationEven != 1
|
|
42
|
+
bifurcationOddFinalZero = not bifurcationOdd & 1
|
|
43
|
+
bifurcationEvenFinalZero = not bifurcationEven & 1
|
|
44
|
+
|
|
45
|
+
if bifurcationOddHasCurves:
|
|
46
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | (bifurcationEven << 3) | (bifurcationOddFinalZero << 1)
|
|
47
|
+
storeCurveLocations(curveLocationAnalysis, distinctCrossings)
|
|
48
|
+
|
|
49
|
+
if bifurcationEvenHasCurves:
|
|
50
|
+
curveLocationAnalysis = (bifurcationEven >> 1) | (bifurcationOdd << 2) | bifurcationEvenFinalZero
|
|
51
|
+
storeCurveLocations(curveLocationAnalysis, distinctCrossings)
|
|
52
|
+
|
|
53
|
+
curveLocationAnalysis = ((bifurcationOdd | (bifurcationEven << 1)) << 2) | 3
|
|
54
|
+
storeCurveLocations(curveLocationAnalysis, distinctCrossings)
|
|
55
|
+
|
|
56
|
+
if bifurcationOddHasCurves and bifurcationEvenHasCurves and (bifurcationOddFinalZero or bifurcationEvenFinalZero):
|
|
57
|
+
XOrHere2makePair = 0b1
|
|
58
|
+
findUnpairedBinary1 = 0
|
|
59
|
+
if bifurcationOddFinalZero and not bifurcationEvenFinalZero:
|
|
60
|
+
while findUnpairedBinary1 >= 0:
|
|
61
|
+
XOrHere2makePair <<= 2
|
|
62
|
+
findUnpairedBinary1 += 1 if (bifurcationOdd & XOrHere2makePair) == 0 else -1
|
|
63
|
+
bifurcationOdd ^= XOrHere2makePair
|
|
64
|
+
|
|
65
|
+
elif bifurcationEvenFinalZero and not bifurcationOddFinalZero:
|
|
66
|
+
while findUnpairedBinary1 >= 0:
|
|
67
|
+
XOrHere2makePair <<= 2
|
|
68
|
+
findUnpairedBinary1 += 1 if (bifurcationEven & XOrHere2makePair) == 0 else -1
|
|
69
|
+
bifurcationEven ^= XOrHere2makePair
|
|
70
|
+
|
|
71
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | ((bifurcationEven >> 2) << 1)
|
|
72
|
+
storeCurveLocations(curveLocationAnalysis, distinctCrossings)
|
|
73
|
+
|
|
74
|
+
# Move discovered data to known for next iteration
|
|
75
|
+
for keyName in redisClient.scan_iter(match="known:*"):
|
|
76
|
+
redisClient.delete(str(keyName))
|
|
77
|
+
|
|
78
|
+
for keyName in redisClient.scan_iter(match="discovered:*"):
|
|
79
|
+
newKeyName = str(keyName).replace("discovered:", "known:")
|
|
80
|
+
value = redisClient.get(str(keyName))
|
|
81
|
+
redisClient.set(newKeyName, str(value))
|
|
82
|
+
redisClient.delete(str(keyName))
|
|
83
|
+
|
|
84
|
+
# Calculate final sum from Redis
|
|
85
|
+
totalResult = 0
|
|
86
|
+
for keyName in redisClient.scan_iter(match="known:*"):
|
|
87
|
+
value = int(str(redisClient.get(str(keyName))))
|
|
88
|
+
totalResult += value
|
|
89
|
+
|
|
90
|
+
return totalResult
|
|
91
|
+
|
|
92
|
+
def initializeA005316(n: int) -> dict[int, int]:
|
|
93
|
+
if n & 1:
|
|
94
|
+
return {22: 1}
|
|
95
|
+
else:
|
|
96
|
+
return {15: 1}
|
|
97
|
+
|
|
98
|
+
def initializeA000682(n: int) -> dict[int, int]:
|
|
99
|
+
stateToCount: dict[int, int] = {}
|
|
100
|
+
|
|
101
|
+
curveLocationsMAXIMUM = 1 << (2 * n + 4)
|
|
102
|
+
|
|
103
|
+
bitPattern = 5 - (n & 1) * 4
|
|
104
|
+
|
|
105
|
+
packedState = bitPattern | (bitPattern << 1)
|
|
106
|
+
while packedState < curveLocationsMAXIMUM:
|
|
107
|
+
stateToCount[packedState] = 1
|
|
108
|
+
bitPattern = ((bitPattern << 4) | 0b0101)
|
|
109
|
+
packedState = bitPattern | (bitPattern << 1)
|
|
110
|
+
|
|
111
|
+
return stateToCount
|
|
112
|
+
|
|
113
|
+
def A005316(n: int) -> int:
|
|
114
|
+
return count(n, initializeA005316(n))
|
|
115
|
+
|
|
116
|
+
def A000682(n: int) -> int:
|
|
117
|
+
return count(n - 1, initializeA000682(n - 1))
|
|
118
|
+
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import shutil
|
|
3
|
+
import threading
|
|
4
|
+
|
|
5
|
+
pathRoot = Path.cwd() / 'curves'
|
|
6
|
+
|
|
7
|
+
curveMaximum: dict[int, int] = {0: 16,
|
|
8
|
+
1: 64,
|
|
9
|
+
2: 256,
|
|
10
|
+
3: 1024,
|
|
11
|
+
4: 4096,
|
|
12
|
+
5: 16384,
|
|
13
|
+
6: 65536,
|
|
14
|
+
7: 262144,
|
|
15
|
+
8: 1048576,
|
|
16
|
+
9: 4194304,
|
|
17
|
+
10: 16777216,
|
|
18
|
+
11: 67108864,
|
|
19
|
+
12: 268435456,
|
|
20
|
+
13: 1073741824,
|
|
21
|
+
14: 4294967296,
|
|
22
|
+
15: 17179869184,
|
|
23
|
+
16: 68719476736,
|
|
24
|
+
17: 274877906944,
|
|
25
|
+
18: 1099511627776,
|
|
26
|
+
19: 4398046511104,
|
|
27
|
+
20: 17592186044416,
|
|
28
|
+
21: 70368744177664,
|
|
29
|
+
22: 281474976710656,
|
|
30
|
+
23: 1125899906842624,
|
|
31
|
+
24: 4503599627370496,
|
|
32
|
+
25: 18014398509481984,
|
|
33
|
+
26: 72057594037927936,
|
|
34
|
+
27: 288230376151711744,
|
|
35
|
+
28: 1152921504606846976,
|
|
36
|
+
29: 4611686018427387904,
|
|
37
|
+
30: 18446744073709551616,
|
|
38
|
+
31: 73786976294838206464,
|
|
39
|
+
32: 295147905179352825856,
|
|
40
|
+
33: 1180591620717411303424,
|
|
41
|
+
34: 4722366482869645213696,
|
|
42
|
+
35: 18889465931478580854784,
|
|
43
|
+
36: 75557863725914323419136,
|
|
44
|
+
37: 302231454903657293676544,
|
|
45
|
+
38: 1208925819614629174706176,
|
|
46
|
+
39: 4835703278458516698824704,
|
|
47
|
+
40: 19342813113834066795298816,
|
|
48
|
+
41: 77371252455336267181195264,
|
|
49
|
+
42: 309485009821345068724781056,
|
|
50
|
+
43: 1237940039285380274899124224,
|
|
51
|
+
44: 4951760157141521099596496896,
|
|
52
|
+
45: 19807040628566084398385987584,
|
|
53
|
+
46: 79228162514264337593543950336,
|
|
54
|
+
47: 316912650057057350374175801344,
|
|
55
|
+
48: 1267650600228229401496703205376,
|
|
56
|
+
49: 5070602400912917605986812821504,
|
|
57
|
+
50: 20282409603651670423947251286016,
|
|
58
|
+
51: 81129638414606681695789005144064,
|
|
59
|
+
52: 324518553658426726783156020576256,
|
|
60
|
+
53: 1298074214633706907132624082305024,
|
|
61
|
+
54: 5192296858534827628530496329220096,
|
|
62
|
+
55: 20769187434139310514121985316880384,
|
|
63
|
+
56: 83076749736557242056487941267521536,
|
|
64
|
+
57: 332306998946228968225951765070086144,
|
|
65
|
+
58: 1329227995784915872903807060280344576,
|
|
66
|
+
59: 5316911983139663491615228241121378304,
|
|
67
|
+
60: 21267647932558653966460912964485513216,
|
|
68
|
+
61: 85070591730234615865843651857942052864}
|
|
69
|
+
|
|
70
|
+
def buildDictionaryCurveLocations(bridges: int) -> dict[int, int]:
|
|
71
|
+
"""Wait for the writing to finish."""
|
|
72
|
+
dictionaryCurveLocations: dict[int, int] = {}
|
|
73
|
+
for curveLocation in Path(pathRoot, str(bridges)).glob('*'):
|
|
74
|
+
dictionaryCurveLocations[int(curveLocation.stem)] = eval(curveLocation.read_text().strip().rstrip('+')) # noqa: S307
|
|
75
|
+
return dictionaryCurveLocations
|
|
76
|
+
|
|
77
|
+
def recordAnalysis(bridges: int, curveLocationAnalysis: int, distinctCrossings: int) -> None:
|
|
78
|
+
"""Record and building system should be fluid: it will write to disk when needed."""
|
|
79
|
+
def _record() -> None:
|
|
80
|
+
if curveLocationAnalysis < curveMaximum[bridges]:
|
|
81
|
+
with Path(pathRoot, str(bridges), str(curveLocationAnalysis)).open('a') as appendStream:
|
|
82
|
+
appendStream.write(f"{distinctCrossings}+")
|
|
83
|
+
|
|
84
|
+
bookkeeper = threading.Thread(target=_record)
|
|
85
|
+
bookkeeper.daemon = True
|
|
86
|
+
bookkeeper.start()
|
|
87
|
+
|
|
88
|
+
def analyzeCurves(bridges: int, curveLocations: int, distinctCrossings: int) -> None:
|
|
89
|
+
bifurcationOdd = curveLocations & 0x5555555555555555555555555555555555555555555555555555555555555555
|
|
90
|
+
bifurcationEven = (curveLocations ^ bifurcationOdd) >> 1
|
|
91
|
+
|
|
92
|
+
bifurcationOddHasCurves = bifurcationOdd != 1
|
|
93
|
+
bifurcationEvenHasCurves = bifurcationEven != 1
|
|
94
|
+
bifurcationOddFinalZero = not bifurcationOdd & 1
|
|
95
|
+
bifurcationEvenFinalZero = not bifurcationEven & 1
|
|
96
|
+
|
|
97
|
+
if bifurcationOddHasCurves:
|
|
98
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | (bifurcationEven << 3) | (bifurcationOddFinalZero << 1)
|
|
99
|
+
recordAnalysis(bridges, curveLocationAnalysis, distinctCrossings)
|
|
100
|
+
|
|
101
|
+
if bifurcationEvenHasCurves:
|
|
102
|
+
curveLocationAnalysis = (bifurcationEven >> 1) | (bifurcationOdd << 2) | bifurcationEvenFinalZero
|
|
103
|
+
recordAnalysis(bridges, curveLocationAnalysis, distinctCrossings)
|
|
104
|
+
|
|
105
|
+
curveLocationAnalysis = ((bifurcationOdd | (bifurcationEven << 1)) << 2) | 3
|
|
106
|
+
recordAnalysis(bridges, curveLocationAnalysis, distinctCrossings)
|
|
107
|
+
|
|
108
|
+
if bifurcationOddHasCurves and bifurcationEvenHasCurves and (bifurcationOddFinalZero or bifurcationEvenFinalZero):
|
|
109
|
+
XOrHere2makePair = 0b1
|
|
110
|
+
findUnpairedBinary1 = 0
|
|
111
|
+
if bifurcationOddFinalZero and not bifurcationEvenFinalZero:
|
|
112
|
+
while findUnpairedBinary1 >= 0:
|
|
113
|
+
XOrHere2makePair <<= 2
|
|
114
|
+
findUnpairedBinary1 += 1 if (bifurcationOdd & XOrHere2makePair) == 0 else -1
|
|
115
|
+
bifurcationOdd ^= XOrHere2makePair
|
|
116
|
+
|
|
117
|
+
elif bifurcationEvenFinalZero and not bifurcationOddFinalZero:
|
|
118
|
+
while findUnpairedBinary1 >= 0:
|
|
119
|
+
XOrHere2makePair <<= 2
|
|
120
|
+
findUnpairedBinary1 += 1 if (bifurcationEven & XOrHere2makePair) == 0 else -1
|
|
121
|
+
bifurcationEven ^= XOrHere2makePair
|
|
122
|
+
|
|
123
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | ((bifurcationEven >> 2) << 1)
|
|
124
|
+
recordAnalysis(bridges, curveLocationAnalysis, distinctCrossings)
|
|
125
|
+
|
|
126
|
+
def count(bridges: int, dictionaryCurveLocations: dict[int, int]) -> int:
|
|
127
|
+
shutil.rmtree(pathRoot, ignore_errors=True)
|
|
128
|
+
pathRoot.mkdir(exist_ok=True)
|
|
129
|
+
for n in range(bridges):
|
|
130
|
+
Path(pathRoot, str(n)).mkdir(exist_ok=True)
|
|
131
|
+
|
|
132
|
+
while bridges > 0:
|
|
133
|
+
bridges -= 1
|
|
134
|
+
|
|
135
|
+
for curveLocations, distinctCrossings in dictionaryCurveLocations.items():
|
|
136
|
+
"""This is now ready for concurrency."""
|
|
137
|
+
analyzeCurves(bridges, curveLocations, distinctCrossings)
|
|
138
|
+
|
|
139
|
+
dictionaryCurveLocations = buildDictionaryCurveLocations(bridges)
|
|
140
|
+
|
|
141
|
+
return sum(dictionaryCurveLocations.values())
|
|
142
|
+
|
|
143
|
+
def initializeA005316(n: int) -> dict[int, int]:
|
|
144
|
+
if n & 1:
|
|
145
|
+
return {22: 1}
|
|
146
|
+
else:
|
|
147
|
+
return {15: 1}
|
|
148
|
+
|
|
149
|
+
def initializeA000682(n: int) -> dict[int, int]:
|
|
150
|
+
stateToCount: dict[int, int] = {}
|
|
151
|
+
|
|
152
|
+
curveLocationsMAXIMUM = 1 << (2 * n + 4)
|
|
153
|
+
|
|
154
|
+
bitPattern = 5 - (n & 1) * 4
|
|
155
|
+
|
|
156
|
+
packedState = bitPattern | (bitPattern << 1)
|
|
157
|
+
while packedState < curveLocationsMAXIMUM:
|
|
158
|
+
stateToCount[packedState] = 1
|
|
159
|
+
bitPattern = ((bitPattern << 4) | 0b0101)
|
|
160
|
+
packedState = bitPattern | (bitPattern << 1)
|
|
161
|
+
|
|
162
|
+
return stateToCount
|
|
163
|
+
|
|
164
|
+
def A005316(n: int) -> int:
|
|
165
|
+
return count(n, initializeA005316(n))
|
|
166
|
+
|
|
167
|
+
def A000682(n: int) -> int:
|
|
168
|
+
return count(n - 1, initializeA000682(n - 1))
|
|
169
|
+
|
|
@@ -2,16 +2,12 @@
|
|
|
2
2
|
Ported from the Java version by Sean A. Irvine:
|
|
3
3
|
https://github.com/archmageirvine/joeis/blob/80e3e844b11f149704acbab520bc3a3a25ac34ff/src/irvine/oeis/a001/A001415.java
|
|
4
4
|
|
|
5
|
-
This implementation is a
|
|
6
|
-
by Sean A. Irvine, a contributor to the OEIS project. It provides a clean, procedural implementation
|
|
7
|
-
with straightforward variable naming and control flow that may be more approachable for
|
|
8
|
-
programmers familiar with modern languages.
|
|
5
|
+
This implementation is a Python version of a Java implementation of Lunnon's algorithm by Sean A. Irvine.
|
|
9
6
|
|
|
10
7
|
Key characteristics:
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- Uses primitive Python data structures (lists) without NumPy dependencies
|
|
8
|
+
- Identifiers tend to match Irvine.
|
|
9
|
+
- A procedural paradigm more similar to Lunnon and unlike Irvine's object-oriented implementation.
|
|
10
|
+
- Only primitive Python data structures.
|
|
15
11
|
|
|
16
12
|
Citation: https://github.com/hunterhogan/mapFolding/blob/134f2e6ecdf59fb6f6829c775475544a6aaaa800/citations/jOEIS.bibtex
|
|
17
13
|
"""
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from mapFolding._oeisFormulas.matrixMeandersAnnex import curveMaximum as curveMaximum
|
|
2
|
+
|
|
3
|
+
dictionaryCurveLocations: dict[int, int] = {}
|
|
4
|
+
|
|
5
|
+
def getCurveLocations() -> dict[int, int]:
|
|
6
|
+
global dictionaryCurveLocations # noqa: PLW0603
|
|
7
|
+
sherpa = dictionaryCurveLocations.copy()
|
|
8
|
+
dictionaryCurveLocations = {}
|
|
9
|
+
return sherpa
|
|
10
|
+
|
|
11
|
+
def recordAnalysis(curveLocationAnalysis: int, curveLocationsMAXIMUM: int, distinctCrossings: int) -> None:
|
|
12
|
+
if curveLocationAnalysis < curveLocationsMAXIMUM:
|
|
13
|
+
dictionaryCurveLocations[curveLocationAnalysis] = dictionaryCurveLocations.get(curveLocationAnalysis, 0) + distinctCrossings
|
|
14
|
+
|
|
15
|
+
def initializeCurveLocations(startingCurveLocations: dict[int, int]) -> None:
|
|
16
|
+
global dictionaryCurveLocations # noqa: PLW0603
|
|
17
|
+
dictionaryCurveLocations = startingCurveLocations.copy()
|
|
18
|
+
|
|
19
|
+
def count(bridges: int, startingCurveLocations: dict[int, int]) -> int:
|
|
20
|
+
initializeCurveLocations(startingCurveLocations)
|
|
21
|
+
|
|
22
|
+
while bridges > 0:
|
|
23
|
+
bridges -= 1
|
|
24
|
+
curveLocationsMAXIMUM, bifurcationEvenLocator, bifurcationOddLocator = curveMaximum[bridges]
|
|
25
|
+
|
|
26
|
+
for curveLocations, distinctCrossings in getCurveLocations().items():
|
|
27
|
+
bifurcationEven = (curveLocations & bifurcationEvenLocator) >> 1
|
|
28
|
+
bifurcationOdd = curveLocations & bifurcationOddLocator
|
|
29
|
+
|
|
30
|
+
bifurcationEvenFinalZero = (bifurcationEven & 0b1) == 0
|
|
31
|
+
bifurcationEvenHasCurves = bifurcationEven != 1
|
|
32
|
+
bifurcationOddFinalZero = (bifurcationOdd & 0b1) == 0
|
|
33
|
+
bifurcationOddHasCurves = bifurcationOdd != 1
|
|
34
|
+
|
|
35
|
+
if bifurcationEvenHasCurves:
|
|
36
|
+
curveLocationAnalysis = (bifurcationEven >> 1) | (bifurcationOdd << 2) | bifurcationEvenFinalZero
|
|
37
|
+
recordAnalysis(curveLocationAnalysis, curveLocationsMAXIMUM, distinctCrossings)
|
|
38
|
+
|
|
39
|
+
if bifurcationOddHasCurves:
|
|
40
|
+
curveLocationAnalysis = (bifurcationOdd >> 2) | (bifurcationEven << 3) | (bifurcationOddFinalZero << 1)
|
|
41
|
+
recordAnalysis(curveLocationAnalysis, curveLocationsMAXIMUM, distinctCrossings)
|
|
42
|
+
|
|
43
|
+
curveLocationAnalysis = ((bifurcationOdd | (bifurcationEven << 1)) << 2) | 3
|
|
44
|
+
recordAnalysis(curveLocationAnalysis, curveLocationsMAXIMUM, distinctCrossings)
|
|
45
|
+
|
|
46
|
+
if bifurcationEvenHasCurves and bifurcationOddHasCurves and (bifurcationEvenFinalZero or bifurcationOddFinalZero):
|
|
47
|
+
XOrHere2makePair = 0b1
|
|
48
|
+
findUnpairedBinary1 = 0
|
|
49
|
+
|
|
50
|
+
if bifurcationEvenFinalZero and not bifurcationOddFinalZero:
|
|
51
|
+
while findUnpairedBinary1 >= 0:
|
|
52
|
+
XOrHere2makePair <<= 2
|
|
53
|
+
findUnpairedBinary1 += 1 if (bifurcationEven & XOrHere2makePair) == 0 else -1
|
|
54
|
+
bifurcationEven ^= XOrHere2makePair
|
|
55
|
+
|
|
56
|
+
elif bifurcationOddFinalZero and not bifurcationEvenFinalZero:
|
|
57
|
+
while findUnpairedBinary1 >= 0:
|
|
58
|
+
XOrHere2makePair <<= 2
|
|
59
|
+
findUnpairedBinary1 += 1 if (bifurcationOdd & XOrHere2makePair) == 0 else -1
|
|
60
|
+
bifurcationOdd ^= XOrHere2makePair
|
|
61
|
+
|
|
62
|
+
curveLocationAnalysis = ((bifurcationEven >> 2) << 1) | (bifurcationOdd >> 2)
|
|
63
|
+
recordAnalysis(curveLocationAnalysis, curveLocationsMAXIMUM, distinctCrossings)
|
|
64
|
+
|
|
65
|
+
return sum(getCurveLocations().values())
|