mapFolding 0.16.2__tar.gz → 0.17.0__tar.gz

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.
Files changed (139) hide show
  1. {mapfolding-0.16.2/mapFolding.egg-info → mapfolding-0.17.0}/PKG-INFO +11 -8
  2. {mapfolding-0.16.2 → mapfolding-0.17.0}/easyRun/A000682.py +2 -2
  3. mapfolding-0.17.0/easyRun/NOTcountingFolds.py +44 -0
  4. {mapfolding-0.16.2 → mapfolding-0.17.0}/easyRun/countFolds.py +9 -2
  5. mapfolding-0.17.0/easyRun/generateAllModules.py +14 -0
  6. {mapfolding-0.16.2 → mapfolding-0.17.0}/easyRun/meanders.py +4 -4
  7. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/__init__.py +1 -0
  8. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/_theSSOT.py +3 -2
  9. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/_theTypes.py +3 -0
  10. mapfolding-0.17.0/mapFolding/algorithms/A000136constraintPropagation.py +95 -0
  11. mapfolding-0.17.0/mapFolding/algorithms/A000136elimination.py +163 -0
  12. mapfolding-0.17.0/mapFolding/algorithms/A000136eliminationParallel.py +77 -0
  13. mapfolding-0.17.0/mapFolding/algorithms/A086345.py +75 -0
  14. mapfolding-0.17.0/mapFolding/algorithms/matrixMeanders.py +129 -0
  15. mapfolding-0.17.0/mapFolding/algorithms/matrixMeandersNumPyndas.py +841 -0
  16. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/algorithms/oeisIDbyFormula.py +2 -2
  17. mapfolding-0.17.0/mapFolding/algorithms/symmetricFolds.py +35 -0
  18. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/basecamp.py +100 -153
  19. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/dataBaskets.py +142 -65
  20. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/filesystemToolkit.py +4 -32
  21. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/oeis.py +5 -12
  22. mapfolding-0.17.0/mapFolding/reference/A086345Wu.py +25 -0
  23. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/irvineJavaPort.py +3 -3
  24. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/matrixMeandersAnalysis/signatures.py +3 -0
  25. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +1 -1
  26. mapfolding-0.17.0/mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +19 -0
  27. mapfolding-0.17.0/mapFolding/someAssemblyRequired/A007822/_asynchronousAnnex.py +51 -0
  28. mapfolding-0.17.0/mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +102 -0
  29. mapfolding-0.17.0/mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +89 -0
  30. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/RecipeJob.py +84 -34
  31. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/__init__.py +4 -8
  32. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/_toolkitContainers.py +38 -7
  33. mapfolding-0.17.0/mapFolding/someAssemblyRequired/infoBooth.py +67 -0
  34. mapfolding-0.17.0/mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +313 -0
  35. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +63 -96
  36. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/makingModules_count.py +26 -30
  37. mapfolding-0.17.0/mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +59 -0
  38. {mapfolding-0.16.2/mapFolding/someAssemblyRequired/mapFolding → mapfolding-0.17.0/mapFolding/someAssemblyRequired/mapFoldingModules}/makeMapFoldingModules.py +30 -35
  39. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/meanders/makeMeandersModules.py +13 -11
  40. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/toolkitMakeModules.py +5 -31
  41. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/toolkitNumba.py +3 -2
  42. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/transformationTools.py +12 -15
  43. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/A007822/algorithm.py +45 -50
  44. mapfolding-0.17.0/mapFolding/syntheticModules/A007822/asynchronous.py +206 -0
  45. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/A007822/initializeState.py +19 -23
  46. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/asynchronousTheorem2.py → mapfolding-0.17.0/mapFolding/syntheticModules/A007822/theorem2.py +21 -15
  47. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/A007822/theorem2Numba.py +23 -25
  48. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/asynchronousTrimmed.py → mapfolding-0.17.0/mapFolding/syntheticModules/A007822/theorem2Trimmed.py +20 -11
  49. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/countParallelNumba.py +1 -2
  50. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/daoOfMapFoldingNumba.py +5 -4
  51. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/initializeState.py +1 -1
  52. mapfolding-0.17.0/mapFolding/syntheticModules/meanders/bigInt.py +89 -0
  53. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/theorem2.py +1 -1
  54. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/asynchronousNumba.py → mapfolding-0.17.0/mapFolding/syntheticModules/theorem2Numba.py +6 -12
  55. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/theorem2Trimmed.py +2 -2
  56. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/tests/test_computations.py +29 -3
  57. {mapfolding-0.16.2 → mapfolding-0.17.0/mapFolding.egg-info}/PKG-INFO +11 -8
  58. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding.egg-info/SOURCES.txt +11 -19
  59. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding.egg-info/requires.txt +10 -6
  60. {mapfolding-0.16.2 → mapfolding-0.17.0}/pyproject.toml +12 -8
  61. mapfolding-0.16.2/easyRun/NOTcountingFolds.py +0 -36
  62. mapfolding-0.16.2/mapFolding/_dataPacking.py +0 -68
  63. mapfolding-0.16.2/mapFolding/algorithms/matrixMeanders.py +0 -88
  64. mapfolding-0.16.2/mapFolding/algorithms/matrixMeandersBeDry.py +0 -182
  65. mapfolding-0.16.2/mapFolding/algorithms/matrixMeandersNumPy.py +0 -333
  66. mapfolding-0.16.2/mapFolding/algorithms/matrixMeandersPandas.py +0 -334
  67. mapfolding-0.16.2/mapFolding/reference/meandersDumpingGround/A005316intOptimized.py +0 -122
  68. mapfolding-0.16.2/mapFolding/reference/meandersDumpingGround/A005316optimized128bit.py +0 -79
  69. mapfolding-0.16.2/mapFolding/reference/meandersDumpingGround/matrixMeandersBaseline.py +0 -65
  70. mapfolding-0.16.2/mapFolding/reference/meandersDumpingGround/matrixMeandersBaselineAnnex.py +0 -84
  71. mapfolding-0.16.2/mapFolding/reference/meandersDumpingGround/matrixMeandersSimpleQueue.py +0 -90
  72. mapfolding-0.16.2/mapFolding/someAssemblyRequired/A007822/A007822rawMaterials.py +0 -54
  73. mapfolding-0.16.2/mapFolding/someAssemblyRequired/A007822/makeA007822AsynchronousModules.py +0 -259
  74. mapfolding-0.16.2/mapFolding/someAssemblyRequired/A007822/makeA007822Modules.py +0 -75
  75. mapfolding-0.16.2/mapFolding/someAssemblyRequired/infoBooth.py +0 -49
  76. mapfolding-0.16.2/mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +0 -337
  77. mapfolding-0.16.2/mapFolding/someAssemblyRequired/makingModules_doTheNeedful.py +0 -121
  78. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/algorithmNumba.py +0 -94
  79. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/asynchronous.py +0 -150
  80. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/asynchronousAnnex.py +0 -66
  81. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/asynchronousAnnexNumba.py +0 -70
  82. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/theorem2.py +0 -75
  83. mapfolding-0.16.2/mapFolding/syntheticModules/A007822/theorem2Trimmed.py +0 -69
  84. mapfolding-0.16.2/mapFolding/syntheticModules/dataPacking.py +0 -26
  85. mapfolding-0.16.2/mapFolding/syntheticModules/dataPackingA007822.py +0 -92
  86. mapfolding-0.16.2/mapFolding/syntheticModules/meanders/bigInt.py +0 -52
  87. mapfolding-0.16.2/mapFolding/syntheticModules/theorem2Numba.py +0 -52
  88. {mapfolding-0.16.2 → mapfolding-0.17.0}/LICENSE +0 -0
  89. {mapfolding-0.16.2 → mapfolding-0.17.0}/README.md +0 -0
  90. {mapfolding-0.16.2 → mapfolding-0.17.0}/easyRun/A005316.py +0 -0
  91. {mapfolding-0.16.2 → mapfolding-0.17.0}/easyRun/__init__.py +0 -0
  92. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/algorithms/__init__.py +0 -0
  93. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/algorithms/daoOfMapFolding.py +0 -0
  94. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +0 -0
  95. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/beDRY.py +0 -0
  96. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/py.typed +0 -0
  97. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/A000682facts.py +0 -0
  98. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/A005316facts.py +0 -0
  99. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/__init__.py +0 -0
  100. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/flattened.py +0 -0
  101. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/hunterNumba.py +0 -0
  102. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/jaxCount.py +0 -0
  103. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/jobsCompleted/[2x19]/p2x19.py +0 -0
  104. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/jobsCompleted/__init__.py +0 -0
  105. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/jobsCompleted/p2x19/p2x19.py +0 -0
  106. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/lunnonNumpy.py +0 -0
  107. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/lunnonWhile.py +0 -0
  108. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/matrixMeandersAnalysis/__init__.py +0 -0
  109. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/matrixMeandersAnalysis/prefixNotationNotes.py +0 -0
  110. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/A005316JavaPort.py +0 -0
  111. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/A005316imperative.py +0 -0
  112. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/A005316primitiveOptimized.py +0 -0
  113. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/A005316redis.py +0 -0
  114. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/A005316write2disk.py +0 -0
  115. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/matrixMeanders64retired.py +0 -0
  116. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/matrixMeandersBaselineV2.py +0 -0
  117. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/meandersDumpingGround/matrixMeandersSlicePop.py +0 -0
  118. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/rotatedEntryPoint.py +0 -0
  119. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/reference/total_countPlus1vsPlusN.py +0 -0
  120. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/A007822/__init__.py +0 -0
  121. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/_toolIfThis.py +0 -0
  122. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/getLLVMforNoReason.py +0 -0
  123. {mapfolding-0.16.2/mapFolding/someAssemblyRequired/mapFolding → mapfolding-0.17.0/mapFolding/someAssemblyRequired/mapFoldingModules}/__init__.py +0 -0
  124. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/someAssemblyRequired/meanders/__init__.py +0 -0
  125. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/A007822/__init__.py +0 -0
  126. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/__init__.py +0 -0
  127. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/syntheticModules/meanders/__init__.py +0 -0
  128. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/tests/__init__.py +0 -0
  129. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/tests/conftest.py +0 -0
  130. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/tests/test_filesystem.py +0 -0
  131. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/tests/test_oeis.py +0 -0
  132. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/tests/test_other.py +0 -0
  133. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/tests/test_tasks.py +0 -0
  134. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/zCuzDocStoopid/__init__.py +0 -0
  135. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding/zCuzDocStoopid/makeDocstrings.py +0 -0
  136. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding.egg-info/dependency_links.txt +0 -0
  137. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding.egg-info/entry_points.txt +0 -0
  138. {mapfolding-0.16.2 → mapfolding-0.17.0}/mapFolding.egg-info/top_level.txt +0 -0
  139. {mapfolding-0.16.2 → mapfolding-0.17.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapFolding
3
- Version: 0.16.2
3
+ Version: 0.17.0
4
4
  Summary: Map folding, meanders, stamp folding, semi-meanders. Experiment with algorithm transformations, and analyze computational states.
5
5
  Author-email: Hunter Hogan <HunterHogan@pm.me>
6
6
  License: CC-BY-NC-4.0
@@ -31,36 +31,39 @@ Classifier: Topic :: Software Development :: Compilers
31
31
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
32
32
  Classifier: Topic :: Software Development :: Pre-processors
33
33
  Classifier: Typing :: Typed
34
- Requires-Python: >=3.12
34
+ Requires-Python: <3.14,>=3.12
35
35
  Description-Content-Type: text/markdown
36
36
  License-File: LICENSE
37
- Requires-Dist: astToolkit
38
- Requires-Dist: autoflake
39
- Requires-Dist: hunterMakesPy
40
- Requires-Dist: isort
37
+ Requires-Dist: astToolkit>=0.9.0
38
+ Requires-Dist: hunterMakesPy>=0.3.0
41
39
  Requires-Dist: numpy
42
40
  Requires-Dist: platformdirs
43
41
  Provides-Extra: development
42
+ Requires-Dist: ipykernel; extra == "development"
43
+ Requires-Dist: ipywidgets; extra == "development"
44
44
  Requires-Dist: memray; sys_platform == "linux" and extra == "development"
45
- Requires-Dist: mypy; extra == "development"
46
- Requires-Dist: pyupgrade; extra == "development"
47
45
  Requires-Dist: py-spy; extra == "development"
48
46
  Requires-Dist: setuptools-scm; extra == "development"
49
47
  Provides-Extra: numba
50
48
  Requires-Dist: numba; extra == "numba"
51
49
  Requires-Dist: numba_progress; extra == "numba"
52
50
  Provides-Extra: pandas
51
+ Requires-Dist: ortools; extra == "pandas"
53
52
  Requires-Dist: pandas; extra == "pandas"
54
53
  Requires-Dist: pyarrow; extra == "pandas"
55
54
  Requires-Dist: pyarrow-stubs; extra == "pandas"
55
+ Provides-Extra: sympy
56
+ Requires-Dist: sympy; extra == "sympy"
56
57
  Provides-Extra: testing
57
58
  Requires-Dist: numba; extra == "testing"
59
+ Requires-Dist: ortools; extra == "testing"
58
60
  Requires-Dist: pandas; extra == "testing"
59
61
  Requires-Dist: pyarrow; extra == "testing"
60
62
  Requires-Dist: pytest-cov; extra == "testing"
61
63
  Requires-Dist: pytest-env; extra == "testing"
62
64
  Requires-Dist: pytest-xdist; extra == "testing"
63
65
  Requires-Dist: pytest; extra == "testing"
66
+ Requires-Dist: sympy; extra == "testing"
64
67
  Dynamic: license-file
65
68
 
66
69
  # mapFolding
@@ -10,7 +10,7 @@ if sys.version_info >= (3, 14):
10
10
  def main():
11
11
  oeisID = 'A000682'
12
12
  n=45
13
- print(NOTcountingFolds(oeisID, n, 'matrixNumPy'))
13
+ print(NOTcountingFolds(oeisID, n, 'matrixMeanders'))
14
14
 
15
15
  from mapFolding import dictionaryOEIS
16
16
  if n < dictionaryOEIS[oeisID]['valueUnknown']:
@@ -21,5 +21,5 @@ if __name__ == "__main__":
21
21
 
22
22
  r"""
23
23
  deactivate && C:\apps\mapFolding\.vtail\Scripts\activate.bat && title good && cls
24
- title running && start "running" /B /HIGH /wait py -X faulthandler=0 -X tracemalloc=0 -X frozen_modules=on easyRun\A000682.py && title I'm done || title Error
24
+ title running && start "running" /B /HIGH /wait py -X faulthandler=0 -X tracemalloc=0 -X frozen_modules=on easyRun\A000682.py & title I'm done
25
25
  """
@@ -0,0 +1,44 @@
1
+ # ruff: noqa
2
+ from collections import ChainMap
3
+ from mapFolding import dictionaryOEIS, dictionaryOEISMapFolding
4
+ from mapFolding.basecamp import NOTcountingFolds
5
+ import sys
6
+ import time
7
+
8
+ dictionaryONE = ChainMap(dictionaryOEISMapFolding, dictionaryOEIS) # pyright: ignore[reportArgumentType]
9
+
10
+ if __name__ == '__main__':
11
+ def _write() -> None:
12
+ sys.stdout.write(
13
+ f"{(match:=countTotal == dictionaryONE[oeisID]['valuesKnown'][n])}\t"
14
+ f"\033[{(not match)*91}m"
15
+ f"{n}\t"
16
+ f"{countTotal}\t"
17
+ f"{time.perf_counter() - timeStart:.2f}\t"
18
+ "\033[0m\n"
19
+ )
20
+
21
+ CPUlimit: bool | float | int | None = -2
22
+ flow: str | None = None
23
+
24
+ oeisID = 'A007822'
25
+
26
+ flow = 'algorithm'
27
+ flow = 'asynchronous'
28
+ flow = 'theorem2Trimmed'
29
+ flow = 'theorem2Numba'
30
+ flow = 'theorem2'
31
+
32
+ # for n in range(13,16):
33
+ for n in range(1,4):
34
+
35
+ timeStart = time.perf_counter()
36
+ countTotal = NOTcountingFolds(oeisID, n, flow, CPUlimit)
37
+
38
+ _write()
39
+
40
+ r"""
41
+ deactivate && C:\apps\mapFolding\.vtail\Scripts\activate.bat && title good && cls
42
+ title running && start "working" /B /HIGH /wait py -X faulthandler=0 -X tracemalloc=0 -X frozen_modules=on easyRun\NOTcountingFolds.py & title I'm done
43
+ """
44
+
@@ -23,14 +23,21 @@ if __name__ == '__main__':
23
23
  computationDivisions: int | str | None = None
24
24
  CPUlimit: bool | float | int | None = None
25
25
  # mapShape: tuple[int, ...] | None = None
26
- flow: str | None = 'theorem2Numba'
26
+ flow = 'daoOfMapFolding'
27
+ flow = 'numba'
28
+ flow = 'theorem2'
29
+ flow = 'theorem2Numba'
30
+ flow: str | None = 'theorem2Trimmed'
31
+
27
32
 
28
33
  oeisID: str = 'A001415'
29
- for n in range(3,8):
34
+ oeisID: str = 'A000136'
35
+ for n in range(1,4):
30
36
 
31
37
  mapShape: tuple[int, ...] = dictionaryOEISMapFolding[oeisID]['getMapShape'](n)
32
38
 
33
39
  timeStart = time.perf_counter()
40
+ # foldsTotal: int = countFolds(listDimensions=None, pathLikeWriteFoldsTotal=None, computationDivisions=None, CPUlimit=None, mapShape=(2, 3), flow='theorem2Trimmed')
34
41
  foldsTotal: int = countFolds(listDimensions=listDimensions
35
42
  , pathLikeWriteFoldsTotal=pathLikeWriteFoldsTotal
36
43
  , computationDivisions=computationDivisions
@@ -0,0 +1,14 @@
1
+ """Generate all modules that require some assembly."""
2
+ from mapFolding.someAssemblyRequired.A007822.makeA007822AsynchronousModules import makeA007822AsynchronousModules
3
+ from mapFolding.someAssemblyRequired.A007822.makeA007822Modules import makeA007822Modules
4
+ from mapFolding.someAssemblyRequired.mapFoldingModules.makeMapFoldingModules import makeMapFoldingModules
5
+ from mapFolding.someAssemblyRequired.meanders.makeMeandersModules import makeMeandersModules
6
+
7
+ # TODO from mapFolding.zCuzDocStoopid import makeDocstrings
8
+
9
+ makeMapFoldingModules()
10
+
11
+ makeA007822Modules()
12
+ makeA007822AsynchronousModules()
13
+
14
+ makeMeandersModules()
@@ -24,12 +24,12 @@ if __name__ == '__main__':
24
24
  if sys.version_info >= (3, 14):
25
25
  warnings.filterwarnings("ignore", category=FutureWarning)
26
26
 
27
- flow = 'matrixMeanders'
28
27
  flow = 'matrixPandas'
28
+ flow = 'matrixMeanders'
29
29
  flow = 'matrixNumPy'
30
30
 
31
31
  for oeisID in [
32
- # 'A005316',
32
+ 'A005316',
33
33
  'A000682',
34
34
  ]:
35
35
  sys.stdout.write(f"\n{oeisID}\n")
@@ -46,8 +46,8 @@ if __name__ == '__main__':
46
46
 
47
47
  nList: list[int] = []
48
48
  nList.extend(range(2, 10))
49
- # nList.extend(range(2, 28))
50
- nList.extend(range(28,33))
49
+ # nList.extend(range(10, 28))
50
+ # nList.extend(range(28,33))
51
51
  # nList.extend(range(33,38))
52
52
  # nList.extend(range(38,43))
53
53
  # nList.extend(range(43,45))
@@ -4,6 +4,7 @@ from mapFolding._theTypes import (
4
4
  Array1DElephino as Array1DElephino,
5
5
  Array1DFoldsTotal as Array1DFoldsTotal,
6
6
  Array1DLeavesTotal as Array1DLeavesTotal,
7
+ Array2DLeavesTotal as Array2DLeavesTotal,
7
8
  Array3DLeavesTotal as Array3DLeavesTotal,
8
9
  axisOfLength as axisOfLength,
9
10
  DatatypeElephino as DatatypeElephino,
@@ -43,7 +43,7 @@ class mapFoldingPackageSettings(PackageSettings):
43
43
  concurrencyPackage: str = 'multiprocessing'
44
44
  """Package identifier for concurrent execution operations."""
45
45
  # ruff: noqa: S311
46
- # TODO I made a `TypedDict` before I knew how to make dataclasses and classes. Think about other data structures.
46
+ # TODO I made this a `TypedDict` before I knew how to make dataclasses and classes. Think about other data structures.
47
47
  OEISidMapFoldingManuallySet: dict[str, MetadataOEISidMapFoldingManuallySet] = {
48
48
  'A000136': {
49
49
  'getMapShape': lambda n: (1, n),
@@ -89,7 +89,6 @@ identifierPackageFALLBACK = "mapFolding"
89
89
  packageSettings = mapFoldingPackageSettings(identifierPackageFALLBACK=identifierPackageFALLBACK, OEISidMapFoldingManuallySet=OEISidMapFoldingManuallySet)
90
90
  """Global package settings."""
91
91
 
92
- """Local directory path for storing cached OEIS sequence data and metadata."""
93
92
  OEISidManuallySet: dict[str, MetadataOEISidManuallySet] = {
94
93
  'A000560': {'valuesTestValidation': [random.randint(3, 12)]},
95
94
  'A000682': {'valuesTestValidation': [random.randint(3, 12), 32]},
@@ -101,6 +100,7 @@ OEISidManuallySet: dict[str, MetadataOEISidManuallySet] = {
101
100
  'A060206': {'valuesTestValidation': [random.randint(3, 9)]},
102
101
  'A077460': {'valuesTestValidation': [3, 4, random.randint(5, 8)]},
103
102
  'A078591': {'valuesTestValidation': [random.randint(3, 10)]},
103
+ 'A086345': {'valuesTestValidation': [random.randint(3, 10), random.randint(11, 20), random.randint(21, 30), random.randint(31, 40)]},
104
104
  'A178961': {'valuesTestValidation': [random.randint(3, 11)]},
105
105
  'A223094': {'valuesTestValidation': [random.randint(3, 11)]},
106
106
  'A259702': {'valuesTestValidation': [random.randint(3, 13)]},
@@ -117,3 +117,4 @@ packageSettings = mapFoldingPackageSettings(
117
117
 
118
118
  # TODO integrate into packageSettings
119
119
  pathCache: Path = packageSettings.pathPackage / ".cache"
120
+ """Local directory path for storing cached OEIS sequence data and metadata."""
@@ -44,6 +44,9 @@ different data structure."""
44
44
  Array3DLeavesTotal: TypeAlias = ndarray[tuple[int, int, int], dtype[NumPyLeavesTotal]] # noqa: UP040 The TypeAlias may be used to construct ("cast") a value to the type. And the identifier may be changed to a different type.
45
45
  """A `numpy.ndarray` with three axes and elements of type `NumPyLeavesTotal`."""
46
46
 
47
+ Array2DLeavesTotal: TypeAlias = ndarray[tuple[int, int], dtype[NumPyLeavesTotal]] # noqa: UP040 The TypeAlias may be used to construct ("cast") a value to the type. And the identifier may be changed to a different type.
48
+ """A `numpy.ndarray` with two axes and elements of type `NumPyLeavesTotal`."""
49
+
47
50
  Array1DLeavesTotal: TypeAlias = ndarray[tuple[int], dtype[NumPyLeavesTotal]] # noqa: UP040 The TypeAlias may be used to construct ("cast") a value to the type. And the identifier may be changed to a different type.
48
51
  """A `numpy.ndarray` with one axis and elements of type `NumPyLeavesTotal`."""
49
52
 
@@ -0,0 +1,95 @@
1
+ from ortools.sat.python import cp_model
2
+
3
+ def findValidFoldings(leavesTotal: int, workersMaximum: int) -> list[list[int]]: # noqa: ARG001
4
+ model = cp_model.CpModel()
5
+ listIndexAsIntVar: list[cp_model.IntVar] = [model.NewIntVar(0, leavesTotal - 1, f"leafIndexAtPosition[{positionIndex}]") for positionIndex in range(leavesTotal)]
6
+ indexOfLeafInIndexOfPosition: list[cp_model.IntVar] = [model.NewIntVar(0, leavesTotal - 1, f"positionOfLeafIndex[{leafNumber}]") for leafNumber in range(1, leavesTotal + 1)]
7
+ model.AddInverse(listIndexAsIntVar, indexOfLeafInIndexOfPosition)
8
+ model.Add(listIndexAsIntVar[0] == 0) # Fix leaf 1 at position 0
9
+
10
+ if leavesTotal > 2:
11
+ leavesTotalIsOdd: bool = leavesTotal % 2 == 1
12
+ if leavesTotalIsOdd:
13
+ leafTwoOccupiesPositionTwo: cp_model.IntVar = model.NewBoolVar("leafTwoOccupiesPositionTwo")
14
+ model.Add(indexOfLeafInIndexOfPosition[1] == 2).OnlyEnforceIf(leafTwoOccupiesPositionTwo)
15
+ model.Add(indexOfLeafInIndexOfPosition[1] != 2).OnlyEnforceIf(leafTwoOccupiesPositionTwo.Not())
16
+ model.Add(listIndexAsIntVar[1] == leavesTotal - 1).OnlyEnforceIf(leafTwoOccupiesPositionTwo)
17
+ else:
18
+ model.Add(indexOfLeafInIndexOfPosition[1] != 2)
19
+
20
+ if leavesTotal > 3:
21
+ leafTwoOccupiesFinalPosition: cp_model.IntVar = model.NewBoolVar("leafTwoOccupiesFinalPosition")
22
+ model.Add(indexOfLeafInIndexOfPosition[1] == leavesTotal - 1).OnlyEnforceIf(leafTwoOccupiesFinalPosition)
23
+ model.Add(indexOfLeafInIndexOfPosition[1] != leavesTotal - 1).OnlyEnforceIf(leafTwoOccupiesFinalPosition.Not())
24
+ leavesTotalIsEven: bool = leavesTotal % 2 == 0
25
+ if leavesTotalIsEven:
26
+ leafThreeOccupiesIndexTwoFromEnd: cp_model.IntVar = model.NewBoolVar("leafThreeOccupiesIndexTwoFromEnd")
27
+ model.Add(indexOfLeafInIndexOfPosition[2] == leavesTotal - 3).OnlyEnforceIf(leafThreeOccupiesIndexTwoFromEnd)
28
+ model.Add(indexOfLeafInIndexOfPosition[2] != leavesTotal - 3).OnlyEnforceIf(leafThreeOccupiesIndexTwoFromEnd.Not())
29
+ lastLeafOccupiesPenultimatePosition: cp_model.IntVar = model.NewBoolVar("lastLeafOccupiesPenultimatePosition")
30
+ model.Add(listIndexAsIntVar[leavesTotal - 2] == leavesTotal - 1).OnlyEnforceIf(lastLeafOccupiesPenultimatePosition)
31
+ model.Add(listIndexAsIntVar[leavesTotal - 2] != leavesTotal - 1).OnlyEnforceIf(lastLeafOccupiesPenultimatePosition.Not())
32
+ model.AddBoolOr([
33
+ leafTwoOccupiesFinalPosition.Not(),
34
+ leafThreeOccupiesIndexTwoFromEnd.Not(),
35
+ lastLeafOccupiesPenultimatePosition,
36
+ ])
37
+ else:
38
+ model.Add(indexOfLeafInIndexOfPosition[2] != leavesTotal - 3).OnlyEnforceIf(leafTwoOccupiesFinalPosition)
39
+
40
+ listForbiddenInequalitiesDeconstructed: list[tuple[tuple[int, int], tuple[int, int], tuple[int, int]]] = []
41
+ for k in range(1, leavesTotal):
42
+ for r in range(2, leavesTotal):
43
+ if r == k or (k - r) % 2 != 0:
44
+ continue
45
+ k1: int = k + 1
46
+ r1: int = r + 1
47
+
48
+ """All 8 forbidden forms, index of:
49
+ [k < r < k+1 < r+1] [r < k+1 < r+1 < k] [k+1 < r+1 < k < r] [r+1 < k < r < k+1]
50
+ [r < k < r+1 < k+1] [k < r+1 < k+1 < r] [r+1 < k+1 < r < k] [k+1 < r < k < r+1]
51
+ """
52
+ listForbiddenInequalitiesDeconstructed.extend([
53
+ ((k-1, r-1), (r-1, k1-1), (k1-1, r1-1)),
54
+ ((k1-1, r1-1), (r1-1, k-1), (k-1, r-1)),
55
+ ((r1-1, k-1), (k-1, r-1), (r-1, k1-1)),
56
+ ((k-1, r1-1), (r1-1, k1-1), (k1-1, r-1)),
57
+ # ((r-1, k1-1), (k1-1, r1-1), (r1-1, k-1)), ((r-1, k-1), (k-1, r1-1), (r1-1, k1-1)), ((r1-1, k1-1), (k1-1, r-1), (r-1, k-1)), ((k1-1, r-1), (r-1, k-1), (k-1, r1-1)), # noqa: ERA001
58
+ ])
59
+ for tupleIndices in listForbiddenInequalitiesDeconstructed:
60
+ listOfInequalities: list[cp_model.IntVar] = []
61
+ for indexLeft, indexRight in tupleIndices:
62
+ inequalityOf2Indices: cp_model.IntVar = model.NewBoolVar(f"order_{indexLeft}_{indexRight}")
63
+ model.Add(indexOfLeafInIndexOfPosition[indexLeft] < indexOfLeafInIndexOfPosition[indexRight]).OnlyEnforceIf(inequalityOf2Indices)
64
+ model.Add(indexOfLeafInIndexOfPosition[indexLeft] >= indexOfLeafInIndexOfPosition[indexRight]).OnlyEnforceIf(inequalityOf2Indices.Not())
65
+ listOfInequalities.append(inequalityOf2Indices)
66
+ # At least one inequality must be false to avoid forbidden pattern
67
+ model.AddBoolOr([inequality.Not() for inequality in listOfInequalities])
68
+
69
+ solver = cp_model.CpSolver()
70
+ solver.parameters.enumerate_all_solutions = True
71
+
72
+ solver.parameters.cp_model_presolve = True
73
+ solver.parameters.use_combined_no_overlap = True
74
+ solver.parameters.use_disjunctive_constraint_in_cumulative = True
75
+ solver.parameters.use_objective_shaving_search = True
76
+ solver.parameters.use_precedences_in_disjunctive_constraint = True
77
+ # solver.parameters.num_workers = 2 # noqa: ERA001
78
+ solver.parameters.num_workers = 1
79
+
80
+ class FoldingCollector(cp_model.CpSolverSolutionCallback):
81
+ def __init__(self, leafIndexAtPositionInput: list[cp_model.IntVar]) -> None:
82
+ super().__init__()
83
+ self.leafIndexAtPositionInput = leafIndexAtPositionInput
84
+ self.listFoldings: list[list[int]] = []
85
+
86
+ def OnSolutionCallback(self) -> None:
87
+ self.listFoldings.append([self.Value(positionVariable) + 1 for positionVariable in self.leafIndexAtPositionInput]) # pyright: ignore[reportUnknownMemberType]
88
+
89
+ foldingCollector = FoldingCollector(listIndexAsIntVar)
90
+ solver.Solve(model, foldingCollector)
91
+ return foldingCollector.listFoldings
92
+
93
+ def doTheNeedful(leavesTotal: int, workersMaximum: int = 1) -> int:
94
+ """Count the number of valid foldings for a given number of leaves."""
95
+ return len(findValidFoldings(leavesTotal, workersMaximum)) * leavesTotal
@@ -0,0 +1,163 @@
1
+ from itertools import permutations, starmap
2
+ from typing import Final
3
+
4
+ def isThisValid(folding: tuple[int, ...]) -> bool:
5
+ """Verify that a folding sequence is possible.
6
+
7
+ Parameters
8
+ ----------
9
+ folding : list[int]
10
+ List of integers representing the folding sequence.
11
+
12
+ Returns
13
+ -------
14
+ valid : bool
15
+ True if the folding sequence is valid, False otherwise.
16
+
17
+ Notes
18
+ -----
19
+ All 8 forbidden forms
20
+ [k, r, k+1, r+1] [r, k+1, r+1, k] [k+1, r+1, k, r] [r+1, k, r, k+1]
21
+ [r, k, r+1, k+1] [k, r+1, k+1, r] [r+1, k+1, r, k] [k+1, r, k, r+1]
22
+
23
+ I selected the four forms in which k precedes r. Because of the flow, I _think_ that is why these four are sufficient.
24
+
25
+ Citation
26
+ --------
27
+ John E. Koehler, Folding a strip of stamps, Journal of Combinatorial Theory, Volume 5, Issue 2, 1968, Pages 135-152, ISSN
28
+ 0021-9800, https://doi.org/10.1016/S0021-9800(68)80048-1.
29
+ (https://www.sciencedirect.com/science/article/pii/S0021980068800481)
30
+
31
+ See Also
32
+ --------
33
+ - "[Annotated, corrected, scanned copy]" at https://oeis.org/A001011.
34
+ - Citation in BibTeX format "citations/KOEHLER1968135.bib".
35
+ """
36
+ leavesTotal: int = len(folding)
37
+ for index, leaf in enumerate(folding[0:-1]): # `[0:-1]` No room to interpose
38
+ if leaf == leavesTotal:
39
+ continue
40
+ indexLeafRightSide: int = folding.index(leaf+1)
41
+ leafIsOdd: int = leaf & 1
42
+
43
+ for indexInterposer, interposer in enumerate(folding[index + 1:None], start=index + 1): # [k != r]
44
+ if leafIsOdd != (interposer & 1): # [k%2 == r%2]
45
+ continue
46
+ if interposer == leavesTotal:
47
+ continue
48
+
49
+ indexInterposerRightSide: int = folding.index(interposer + 1)
50
+
51
+ if (index < indexInterposer < indexLeafRightSide < indexInterposerRightSide # [k, r, k+1, r+1]
52
+ or index < indexInterposerRightSide < indexLeafRightSide < indexInterposer # [k, r+1, k+1, r]
53
+ or indexLeafRightSide < indexInterposerRightSide < index < indexInterposer # [k+1, r+1, k, r]
54
+ or indexInterposerRightSide < index < indexInterposer < indexLeafRightSide # [r+1, k, r, k+1]
55
+ ):
56
+ return False
57
+ return True
58
+
59
+ def count(prefix: list[int], permutands: list[int], postfix: list[int]) -> int:
60
+ """Count the number of valid foldings for a given fixed start and remaining leaves.
61
+
62
+ Parameters
63
+ ----------
64
+ prefix : list[int]
65
+ List of integers representing the fixed start of the folding sequence.
66
+ permutands : list[int]
67
+ List of elements to permute into permutations.
68
+ postfix : list[int]
69
+ List of integers representing the fixed end of the folding sequence.
70
+
71
+ Returns
72
+ -------
73
+ groupsOfFolds : int
74
+ Number of valid foldings, which each represent a group of folds, for the given configuration.
75
+ """
76
+ groupsOfFolds: int = 0
77
+ for aPermutation in permutations(permutands):
78
+ groupsOfFolds += isThisValid((*prefix, *aPermutation, *postfix))
79
+ return groupsOfFolds
80
+
81
+ def staging(prefix: list[int], permutands: list[int]) -> int:
82
+ """Segregate sequences with a final `2`: necessary as part of excluding leading `1,2`.
83
+
84
+ Parameters
85
+ ----------
86
+ prefix : list[int]
87
+ List of integers representing the fixed start of the folding sequence.
88
+ permutands : list[int]
89
+ List of elements to permute into permutations.
90
+
91
+ Notes
92
+ -----
93
+ Transformation indices:
94
+
95
+ 1,3,4,5,6,2,
96
+ 1,2,6,5,4,3,
97
+
98
+ All valid sequences that end with '2' are in the first half.
99
+ All valid sequences that start with '1,2' are in the second half.
100
+ The remaining valid sequences are evenly split between the two halves.
101
+ Therefore:
102
+ 1. Filter out all '1,2' before checking validity.
103
+ 2. If a valid sequence ends in '2', add 2 to the total count.
104
+ 3. If a valid sequence does not end in '2', add 1 to the total count.
105
+
106
+ `leaf = leavesTotal` is evenly distributed in each half like this: (ex. from A007822(7))
107
+ ^1,14, ,14,$ 612
108
+ ,14,$ ^1,14, 1486
109
+ """
110
+ groupsOfFolds: int = 0
111
+ postfix: list[int] = []
112
+ if 2 in permutands:
113
+ postfix.append(2)
114
+ postfixComplement: list[int] = permutands.copy()
115
+ postfixComplement.remove(2)
116
+ groupsOfFolds += count(prefix, postfixComplement, postfix) * 2
117
+ for leafPostfix in postfixComplement:
118
+ groupsOfFolds += count(prefix, [leaf for leaf in permutands if leaf != leafPostfix], [leafPostfix])
119
+ else:
120
+ groupsOfFolds += count(prefix, permutands, postfix)
121
+ return groupsOfFolds
122
+
123
+ def doTheNeedful(n: int) -> int:
124
+ """Count the number of valid foldings for a given number of leaves."""
125
+ leavesTotal: Final[int] = n
126
+ listToPermute: list[tuple[list[int], list[int]]] = []
127
+
128
+ prefix: list[int] = [1]
129
+ listLeaves: Final[list[int]] = list(range(leavesTotal, 1, -1))
130
+
131
+ permutands: list[int] = listLeaves.copy()
132
+
133
+ # ------- Exclude leading 2 -------------------------------
134
+ # NOTE 1,{3..n},{2..n}...
135
+ excludeLeading2: list[int] = permutands.copy()
136
+ excludeLeading2.remove(2)
137
+ listToPermute.extend([([*prefix, leafPrefix], [leaf for leaf in permutands if leaf != leafPrefix]) for leafPrefix in excludeLeading2])
138
+ del excludeLeading2
139
+
140
+ # ------- Exclude interposed 2 ----------------------------
141
+ # NOTE 1,{3..n},{3..n},{2..n}...
142
+ # NOTE 1,{n,if n&1},{2..n-1}...
143
+ for aTuple in listToPermute.copy():
144
+ if len(aTuple[0]) != 2 or leavesTotal < 4:
145
+ continue
146
+ interposer: int = aTuple[0][1]
147
+ excludeInterposed2: list[int] = permutands.copy()
148
+ excludeInterposed2.remove(2)
149
+ excludeInterposed2.remove(interposer)
150
+ if interposer == leavesTotal and interposer & 1:
151
+ listToPermute.append(([*aTuple[0], 2], excludeInterposed2))
152
+ listToPermute.extend([([*aTuple[0], leafPrefix], [leaf for leaf in permutands if leaf not in (leafPrefix, interposer)]) for leafPrefix in excludeInterposed2])
153
+ listToPermute.remove(aTuple)
154
+ del aTuple, excludeInterposed2, interposer
155
+
156
+ return sum(starmap(staging, listToPermute)) * leavesTotal
157
+
158
+ # ------- Exclude interposed 3 ----------------------------
159
+ # NOTE 1,{3..n},{3..n},{2..n}...,{3..n}
160
+ # NOTE 1,{3..n},{3..n},{3..n}...,{4..n},{3..n},{2}
161
+ # NOTE 1,{3..n-1},...,{n,if ~n&1},{2}
162
+ # NOTE 1,{n,if n&1},{2..n-1}...
163
+
@@ -0,0 +1,77 @@
1
+ from concurrent.futures import Future, ProcessPoolExecutor
2
+ from itertools import permutations
3
+
4
+ def isThisValid(folding: list[int]) -> bool:
5
+ """Verify that a folding sequence is possible.
6
+
7
+ Parameters
8
+ ----------
9
+ folding : list[int]
10
+ List of integers representing the folding sequence.
11
+
12
+ Returns
13
+ -------
14
+ valid : bool
15
+ True if the folding sequence is valid, False otherwise.
16
+ """
17
+ leavesTotal: int = len(folding)
18
+ for index, leaf in enumerate(folding[0:-1]): # Last leaf cannot interpose
19
+ if leaf == leavesTotal:
20
+ continue
21
+ indexLeafRightSide: int = folding.index(leaf+1)
22
+ leafIsOdd: int = leaf & 1
23
+
24
+ for indexInterposer, interposer in enumerate(folding[index + 1:None], start=index + 1): # [k != r]
25
+ if leafIsOdd != (interposer & 1): # [k%2 == r%2]
26
+ continue
27
+ if interposer == leavesTotal:
28
+ continue
29
+
30
+ indexInterposerRightSide: int = folding.index(interposer + 1)
31
+
32
+ if (index < indexInterposer < indexLeafRightSide < indexInterposerRightSide # [k, r, k+1, r+1]
33
+ or index < indexInterposerRightSide < indexLeafRightSide < indexInterposer # [k, r+1, k+1, r]
34
+ or indexLeafRightSide < indexInterposerRightSide < index < indexInterposer # [k+1, r+1, k, r]
35
+ or indexInterposerRightSide < index < indexInterposer < indexLeafRightSide # [r+1, k, r, k+1]
36
+ ):
37
+ return False
38
+ return True
39
+
40
+ def count(fixed: list[int], permutands: list[int]) -> int:
41
+ """Count the number of valid foldings for a given fixed start and remaining leaves.
42
+
43
+ Parameters
44
+ ----------
45
+ fixed : list[int]
46
+ List of integers representing the fixed start of the folding sequence.
47
+ permutands : list[int]
48
+ List of elements to permute into permutations.
49
+ """
50
+ validTotal: int = 0
51
+ for aPermutation in permutations(permutands):
52
+ validTotal += isThisValid([*fixed, *aPermutation])
53
+ return validTotal
54
+
55
+ def doTheNeedful(n: int, processesMaximum: int) -> int:
56
+ """Count the number of valid foldings for a given number of leaves."""
57
+ validTotal: int = 0
58
+ listLeavesTruncated: list[int] = list(range(2, n + 1))
59
+ # NOTE Design goals:
60
+ # Minimize creation/destruction of processes.
61
+ # Use all processes until the end.
62
+ # A valid sequence takes many times more cycles to process than a sequence that is proved invalid in the first few elements.
63
+ # So, dividing purely on the number of sequences is not optimal.
64
+ # Prefer generators of lists over lists of lists.
65
+
66
+ # In the current system, each `Future` leads to a returned value, which is then summed. But, I don't care about any specific
67
+ # `Future`. I would rather have the processes "consume" work from a common well and return their results when the work is done.
68
+ workers: int = min(processesMaximum, n - 1)
69
+ with ProcessPoolExecutor(max_workers=workers) as processPool:
70
+ listFutures: list[Future[int]] = []
71
+ for index in range(len(listLeavesTruncated)):
72
+ permutands: list[int] = listLeavesTruncated.copy()
73
+ fixedLeaves: list[int] = [1, permutands.pop(index)]
74
+ listFutures.append(processPool.submit(count, fixedLeaves, permutands))
75
+ for futureCount in listFutures:
76
+ validTotal += futureCount.result()
77
+ return validTotal * n
@@ -0,0 +1,75 @@
1
+ """Directly based on code Chai Wah Wu, https://oeis.org/wiki/User:Chai_Wah_Wu, posted on OEIS."""
2
+ from fractions import Fraction
3
+ from functools import cache
4
+ from itertools import combinations
5
+ from math import factorial, gcd
6
+ from sympy import divisors
7
+ from sympy.functions.combinatorial.numbers import mobius
8
+ from sympy.utilities.iterables import partitions
9
+
10
+ @cache
11
+ def _GoCountryDancing(romeo: int, copiesRomeo: int, sierra: int, copiesSierra: int) -> int:
12
+ return copiesRomeo * copiesSierra * gcd(romeo, sierra)
13
+
14
+ @cache
15
+ def _goRight(integer: int, copies: int) -> int:
16
+ return ((integer - 1) >> 1) * copies + (integer * copies * (copies - 1) >> 1)
17
+
18
+ @cache
19
+ def _deFactorial(integer: int, copies: int) -> int:
20
+ return integer ** copies * factorial(copies)
21
+
22
+ @cache
23
+ def _blender(n: int) -> int:
24
+ sumReBletionary: int = 0
25
+ for partitionary in partitions(n):
26
+ numbinations: int = 0
27
+ nummaNumma: int = 0
28
+ denominator: int = 1
29
+ for (romeo, copiesRomeo), (sierra, copiesSierra) in combinations(partitionary.items(), 2):
30
+ numbinations += _GoCountryDancing(romeo, copiesRomeo, sierra, copiesSierra)
31
+ for integer, copies in partitionary.items():
32
+ nummaNumma += _goRight(integer, copies)
33
+ denominator *= _deFactorial(integer, copies)
34
+ numerator: int = 3 ** (numbinations + nummaNumma)
35
+ sumReBletionary += Fraction(numerator, denominator)
36
+ return sumReBletionary
37
+
38
+ @cache
39
+ def _recurser(n: int) -> int:
40
+ sumReBlender: int = 0
41
+ for k in range(1, n):
42
+ sumReBlender += _recurser(k) * _blender(n - k)
43
+ return n * _blender(n) - sumReBlender
44
+
45
+ def A086345(n: int) -> int:
46
+ """Compute 'Number of connected oriented graphs (i.e., connected directed graphs with no bidirected edges) on n nodes'.
47
+
48
+ Parameters
49
+ ----------
50
+ n : int
51
+ Index (n-dex) for a(n) in the sequence of values. "n" (lower case) and "a(n)" are conventions in mathematics.
52
+
53
+ Returns
54
+ -------
55
+ a(n) : int
56
+ Number of connected oriented graphs (i.e., connected directed graphs with no bidirected edges) on n nodes.
57
+
58
+ Notes
59
+ -----
60
+ - The largest performance gains are from caching the recursion and `sympy.utilities.iterables.partitions` functions.
61
+ - Interestingly, there is a small but noticeable penalty for choosing comprehension instead of `for`.
62
+
63
+ Would You Like to Know More?
64
+ ----------------------------
65
+ OEIS : webpage
66
+ https://oeis.org/A086345
67
+ """
68
+ if n == 0:
69
+ aOFn: int = 1
70
+ else:
71
+ aOFn: int = 0
72
+ for aDivisor in divisors(n, generator=True):
73
+ aOFn += mobius(aDivisor) * _recurser(n//aDivisor)
74
+ aOFn //= n
75
+ return aOFn