mapFolding 0.17.1__py3-none-any.whl → 0.18.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.
Files changed (248) hide show
  1. easyRun/NOTcountingFolds.py +7 -11
  2. easyRun/countFolds.py +11 -10
  3. easyRun/meanders.py +6 -8
  4. mapFolding/__init__.py +24 -36
  5. mapFolding/_e/Z0Z_analysisPython/SORTZ0Z_hypothesis.py +189 -0
  6. mapFolding/_e/Z0Z_analysisPython/SORTZ0Z_p2d6.py +143 -0
  7. mapFolding/_e/Z0Z_analysisPython/__init__.py +4 -0
  8. mapFolding/_e/Z0Z_analysisPython/exclusionData/__init__.py +0 -0
  9. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/200.py +369 -0
  10. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/2001.py +694 -0
  11. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/200/344/270/211.py +514 -0
  12. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/200/344/270/2111.py +480 -0
  13. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/200/344/272/214.py +511 -0
  14. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/200/344/272/2141.py +515 -0
  15. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/200/344/272/214/344/270/211.py +485 -0
  16. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/200/344/272/214/344/270/2111.py +442 -0
  17. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/211.py +313 -0
  18. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/270/2111.py +343 -0
  19. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/272/214.py +400 -0
  20. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/272/2141.py +497 -0
  21. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/272/214/344/270/211.py +463 -0
  22. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/344/272/214/344/270/2111.py +441 -0
  23. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266.py +35 -0
  24. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/2661.py +35 -0
  25. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/200.py +382 -0
  26. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/2001.py +630 -0
  27. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/200/344/270/211.py +488 -0
  28. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/200/344/270/2111.py +475 -0
  29. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/200/344/272/214.py +473 -0
  30. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/200/344/272/2141.py +500 -0
  31. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/200/344/272/214/344/270/211.py +465 -0
  32. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/200/344/272/214/344/270/2111.py +439 -0
  33. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/211.py +599 -0
  34. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/270/2111.py +536 -0
  35. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/272/214.py +506 -0
  36. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/272/2141.py +533 -0
  37. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/272/214/344/270/211.py +489 -0
  38. mapFolding/_e/Z0Z_analysisPython/exclusionData/aggregated/351/246/226/351/233/266/344/272/214/344/270/2111.py +474 -0
  39. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200.py +1186 -0
  40. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/2001.py +2158 -0
  41. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/2001Negative.py +2158 -0
  42. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200Negative.py +1186 -0
  43. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/270/211.py +1397 -0
  44. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/270/2111.py +1291 -0
  45. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/270/2111Negative.py +1291 -0
  46. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/270/211Negative.py +1397 -0
  47. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/272/214.py +1240 -0
  48. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/272/2141.py +1420 -0
  49. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/272/2141Negative.py +1420 -0
  50. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/272/214Negative.py +1240 -0
  51. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/272/214/344/270/211.py +1366 -0
  52. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/272/214/344/270/2111.py +1274 -0
  53. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/272/214/344/270/2111Negative.py +1274 -0
  54. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/200/344/272/214/344/270/211Negative.py +1366 -0
  55. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/211.py +1186 -0
  56. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/2111.py +1186 -0
  57. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/2111Negative.py +1186 -0
  58. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/270/211Negative.py +1186 -0
  59. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/272/214.py +1102 -0
  60. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/272/2141.py +1422 -0
  61. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/272/2141Negative.py +1422 -0
  62. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/272/214Negative.py +1102 -0
  63. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/272/214/344/270/211.py +1240 -0
  64. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/272/214/344/270/2111.py +1228 -0
  65. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/272/214/344/270/2111Negative.py +1228 -0
  66. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/344/272/214/344/270/211Negative.py +1240 -0
  67. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266.py +32 -0
  68. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/2661.py +1162 -0
  69. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/2661Negative.py +1162 -0
  70. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266Negative.py +32 -0
  71. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200.py +1186 -0
  72. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/2001.py +1926 -0
  73. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/2001Negative.py +1926 -0
  74. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200Negative.py +1186 -0
  75. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/270/211.py +1291 -0
  76. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/270/2111.py +1176 -0
  77. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/270/2111Negative.py +1176 -0
  78. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/270/211Negative.py +1291 -0
  79. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/272/214.py +1228 -0
  80. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/272/2141.py +1324 -0
  81. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/272/2141Negative.py +1324 -0
  82. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/272/214Negative.py +1228 -0
  83. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/272/214/344/270/211.py +1274 -0
  84. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/272/214/344/270/2111.py +1038 -0
  85. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/272/214/344/270/2111Negative.py +1038 -0
  86. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/200/344/272/214/344/270/211Negative.py +1274 -0
  87. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/211.py +2158 -0
  88. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/2111.py +1926 -0
  89. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/2111Negative.py +1926 -0
  90. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/270/211Negative.py +2158 -0
  91. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/272/214.py +1422 -0
  92. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/272/2141.py +1364 -0
  93. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/272/2141Negative.py +1364 -0
  94. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/272/214Negative.py +1422 -0
  95. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/272/214/344/270/211.py +1420 -0
  96. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/272/214/344/270/2111.py +1324 -0
  97. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/272/214/344/270/2111Negative.py +1324 -0
  98. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d5/351/246/226/351/233/266/344/272/214/344/270/211Negative.py +1420 -0
  99. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200.py +3133 -0
  100. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/2001.py +6039 -0
  101. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/2001Negative.py +6039 -0
  102. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200Negative.py +3133 -0
  103. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/270/211.py +3527 -0
  104. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/270/2111.py +2300 -0
  105. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/270/2111Negative.py +2300 -0
  106. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/270/211Negative.py +3527 -0
  107. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/272/214.py +3597 -0
  108. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/272/2141.py +3317 -0
  109. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/272/2141Negative.py +3317 -0
  110. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/272/214Negative.py +3597 -0
  111. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/272/214/344/270/211.py +3161 -0
  112. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/272/214/344/270/2111.py +2877 -0
  113. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/272/214/344/270/2111Negative.py +2877 -0
  114. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/200/344/272/214/344/270/211Negative.py +3161 -0
  115. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/211.py +2981 -0
  116. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/2111.py +3055 -0
  117. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/2111Negative.py +3055 -0
  118. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/270/211Negative.py +2981 -0
  119. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/272/214.py +3221 -0
  120. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/272/2141.py +3988 -0
  121. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/272/2141Negative.py +3988 -0
  122. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/272/214Negative.py +3221 -0
  123. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/272/214/344/270/211.py +3652 -0
  124. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/272/214/344/270/2111.py +2863 -0
  125. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/272/214/344/270/2111Negative.py +2863 -0
  126. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/344/272/214/344/270/211Negative.py +3652 -0
  127. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200.py +2485 -0
  128. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/2001.py +4566 -0
  129. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/2001Negative.py +4566 -0
  130. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200Negative.py +2485 -0
  131. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/270/211.py +3006 -0
  132. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/270/2111.py +2485 -0
  133. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/270/2111Negative.py +2485 -0
  134. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/270/211Negative.py +3006 -0
  135. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/272/214.py +3304 -0
  136. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/272/2141.py +3015 -0
  137. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/272/2141Negative.py +3015 -0
  138. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/272/214Negative.py +3304 -0
  139. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/272/214/344/270/211.py +2939 -0
  140. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/272/214/344/270/2111.py +2589 -0
  141. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/272/214/344/270/2111Negative.py +2589 -0
  142. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/200/344/272/214/344/270/211Negative.py +2939 -0
  143. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/211.py +3899 -0
  144. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/2111.py +2996 -0
  145. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/2111Negative.py +2996 -0
  146. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/270/211Negative.py +3899 -0
  147. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/272/214.py +3223 -0
  148. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/272/2141.py +3020 -0
  149. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/272/2141Negative.py +3020 -0
  150. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/272/214Negative.py +3223 -0
  151. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/272/214/344/270/211.py +3250 -0
  152. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/272/214/344/270/2111.py +2667 -0
  153. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/272/214/344/270/2111Negative.py +2667 -0
  154. mapFolding/_e/Z0Z_analysisPython/exclusionData/collatedp2d6/351/246/226/351/233/266/344/272/214/344/270/211Negative.py +3250 -0
  155. mapFolding/_e/Z0Z_analysisPython/measure.py +162 -0
  156. mapFolding/_e/Z0Z_analysisPython/positionAnalysis.py +403 -0
  157. mapFolding/_e/Z0Z_analysisPython/positionAnalysisPileRanges2d6.py +110 -0
  158. mapFolding/_e/Z0Z_analysisPython/theExcluderBeast.py +640 -0
  159. mapFolding/_e/Z0Z_analysisPython/toolkit.py +166 -0
  160. mapFolding/_e/Z0Z_analysisPython/toolkitCSVsequences.py +188 -0
  161. mapFolding/_e/Z0Z_analysisPython/workBenchPatternFinder.py +284 -0
  162. mapFolding/_e/Z0Z_notes/__init__.py +0 -0
  163. mapFolding/_e/Z0Z_notes/knowledgeDump.py +214 -0
  164. mapFolding/_e/__init__.py +45 -0
  165. mapFolding/_e/_beDRY.py +547 -0
  166. mapFolding/_e/_dataDynamic.py +1164 -0
  167. mapFolding/_e/_measure.py +579 -0
  168. mapFolding/_e/_semiotics.py +363 -0
  169. mapFolding/_e/_theTypes.py +31 -0
  170. mapFolding/_e/algorithms/__init__.py +1 -0
  171. mapFolding/_e/algorithms/constraintPropagation.py +158 -0
  172. mapFolding/_e/algorithms/elimination.py +118 -0
  173. mapFolding/_e/algorithms/eliminationCrease.py +66 -0
  174. mapFolding/_e/algorithms/iff.py +584 -0
  175. mapFolding/_e/basecamp.py +89 -0
  176. mapFolding/_e/dataBaskets.py +123 -0
  177. mapFolding/_e/dataRaw/__init__.py +0 -0
  178. mapFolding/_e/easyRun/__init__.py +0 -0
  179. mapFolding/_e/easyRun/eliminateFolds.py +72 -0
  180. mapFolding/_e/easyRun/pinning.py +62 -0
  181. mapFolding/_e/filters.py +384 -0
  182. mapFolding/_e/pin2/344/270/212nDimensions.py +882 -0
  183. mapFolding/_e/pin2/344/270/212nDimensionsAnnex.py +551 -0
  184. mapFolding/_e/pin2/344/270/212nDimensionsByCrease.py +190 -0
  185. mapFolding/_e/pin2/344/270/212nDimensionsByDomain.py +459 -0
  186. mapFolding/_e/pinIt.py +436 -0
  187. mapFolding/_semiotics.py +42 -0
  188. mapFolding/_theSSOT.py +11 -56
  189. mapFolding/_theTypes.py +52 -67
  190. mapFolding/algorithms/matrixMeandersNumPyndas.py +18 -18
  191. mapFolding/algorithms/oeisIDbyFormula.py +4 -4
  192. mapFolding/algorithms/zCuzDocStoopidoeisIDbyFormula.py +3 -3
  193. mapFolding/basecamp.py +11 -80
  194. mapFolding/beDRY.py +107 -111
  195. mapFolding/dataBaskets.py +0 -56
  196. mapFolding/filesystemToolkit.py +15 -11
  197. mapFolding/oeis.py +17 -16
  198. mapFolding/reference/matrixMeandersAnalysis/prefixNotationNotes.py +2 -2
  199. mapFolding/reference/meandersDumpingGround/matrixMeandersBaselineV2.py +0 -1
  200. mapFolding/reference/meandersDumpingGround/matrixMeandersNumPyV1finalForm.py +8 -10
  201. mapFolding/someAssemblyRequired/RecipeJob.py +5 -5
  202. mapFolding/someAssemblyRequired/makeJobTheorem2Numba.py +5 -2
  203. mapFolding/someAssemblyRequired/makeJobTheorem2codon.py +9 -11
  204. mapFolding/someAssemblyRequired/mapFoldingModules/makeMapFoldingModules.py +2 -1
  205. mapFolding/someAssemblyRequired/transformationTools.py +1 -1
  206. mapFolding/tests/Z0Z_test_e_excluder.py +155 -0
  207. mapFolding/tests/conftest.py +193 -314
  208. mapFolding/tests/dataSamples/A001417.py +455 -0
  209. mapFolding/tests/dataSamples/__init__.py +1 -0
  210. mapFolding/tests/dataSamples/measurementData.py +1818 -0
  211. mapFolding/tests/dataSamples/p2DnDomain3_2_/351/246/226/344/270/200_/351/246/226/351/233/266/344/270/200.py +17 -0
  212. mapFolding/tests/dataSamples/p2DnDomain3_/351/246/226/344/270/200.py +17 -0
  213. mapFolding/tests/dataSamples/p2DnDomain5_4.py +17 -0
  214. mapFolding/tests/dataSamples/p2DnDomain6_5.py +17 -0
  215. mapFolding/tests/dataSamples/p2DnDomain6_7_5_4.py +17 -0
  216. mapFolding/tests/dataSamples/p2DnDomain7_6.py +17 -0
  217. mapFolding/tests/dataSamples/p2DnDomain/351/246/226/344/272/214_/351/246/226/351/233/266/344/270/200/344/272/214.py +17 -0
  218. mapFolding/tests/dataSamples/p2DnDomain/351/246/226/344/272/214_/351/246/226/351/233/266/344/272/214_/351/246/226/351/233/266/344/270/200/344/272/214_/351/246/226/344/270/200/344/272/214.py +17 -0
  219. mapFolding/tests/dataSamples/p2DnDomain/351/246/226/351/233/266/344/270/200/344/272/214_/351/246/226/344/270/200/344/272/214.py +15 -0
  220. mapFolding/tests/dataSamples/p2DnDomain/351/246/226/351/233/266/344/272/214_/351/246/226/344/272/214.py +15 -0
  221. mapFolding/tests/dataSamples/semioticsData.py +135 -0
  222. mapFolding/tests/test_computations.py +134 -80
  223. mapFolding/tests/test_e_computations.py +42 -0
  224. mapFolding/tests/test_e_dataDynamic.py +189 -0
  225. mapFolding/tests/test_e_measurements.py +257 -0
  226. mapFolding/tests/test_e_pinning.py +61 -0
  227. mapFolding/tests/test_e_semiotics.py +128 -0
  228. mapFolding/tests/test_filesystem.py +39 -17
  229. mapFolding/tests/{test_other.py → test_parameterValidation.py} +3 -3
  230. mapFolding/tests/{test_tasks.py → test_taskDivisions.py} +42 -23
  231. mapFolding/zCuzDocStoopid/makeDocstrings.py +3 -2
  232. {mapfolding-0.17.1.dist-info → mapfolding-0.18.0.dist-info}/METADATA +11 -8
  233. mapfolding-0.18.0.dist-info/RECORD +305 -0
  234. {mapfolding-0.17.1.dist-info → mapfolding-0.18.0.dist-info}/WHEEL +1 -1
  235. easyRun/eliminateFolds.py +0 -60
  236. mapFolding/algorithms/constraintPropagation.py +0 -184
  237. mapFolding/algorithms/elimination.py +0 -131
  238. mapFolding/algorithms/eliminationCount.py +0 -26
  239. mapFolding/algorithms/eliminationPinned.py +0 -35
  240. mapFolding/algorithms/iff.py +0 -206
  241. mapFolding/algorithms/patternFinder.py +0 -280
  242. mapFolding/algorithms/pinning2Dn.py +0 -345
  243. mapFolding/algorithms/pinning2DnAnnex.py +0 -43
  244. mapFolding/tests/verify.py +0 -323
  245. mapfolding-0.17.1.dist-info/RECORD +0 -112
  246. {mapfolding-0.17.1.dist-info → mapfolding-0.18.0.dist-info}/entry_points.txt +0 -0
  247. {mapfolding-0.17.1.dist-info → mapfolding-0.18.0.dist-info}/licenses/LICENSE +0 -0
  248. {mapfolding-0.17.1.dist-info → mapfolding-0.18.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1164 @@
1
+ from bisect import bisect_right
2
+ from collections import defaultdict
3
+ from collections.abc import Callable, Iterable, Iterator, Sequence
4
+ from cytoolz.dicttoolz import merge
5
+ from cytoolz.functoolz import curry as syntacticCurry
6
+ from functools import cache
7
+ from gmpy2 import bit_flip, bit_mask, is_even, is_odd
8
+ from hunterMakesPy import raiseIfNone
9
+ from hunterMakesPy.filesystemToolkit import writePython
10
+ from mapFolding import ansiColorReset, ansiColors, decreasing, inclusive, packageSettings
11
+ from mapFolding._e import (
12
+ dimensionFourthNearest首, dimensionIndex, dimensionNearestTail, dimensionNearest首, dimensionSecondNearest首,
13
+ dimensionThirdNearest首, getPileRangeOfLeaves, getSumsOfProductsOfDimensionsNearest首, howManyDimensionsHaveOddParity,
14
+ JeanValjean, Leaf, leafInSubHyperplane, leafOrigin, mapShapeIs2上nDimensions, PermutationSpace, Pile, pileOrigin,
15
+ reverseLookup, 一, 三, 二, 四, 零, 首一, 首一二, 首三, 首二, 首零, 首零一, 首零一二, 首零二)
16
+ from mapFolding._e.dataBaskets import EliminationState
17
+ from mapFolding._e.filters import between, consecutive, exclude, leafIsPinned
18
+ from more_itertools import all_unique, loops
19
+ from operator import add, neg, sub
20
+ from pathlib import Path, PurePath
21
+ from typing import Any
22
+ import pandas
23
+ import sys
24
+
25
+ #======== Creases =================================
26
+
27
+ def getLeavesCreaseAnte(state: EliminationState, leaf: Leaf) -> Iterator[Leaf]:
28
+ """1) `leaf` has at most `dimensionsTotal - 1` many creases.
29
+
30
+ 2) The list is ordered by increasing dimension number, which corresponds to an increasing absolute magnitude of _change_ in `leaf` number.
31
+
32
+ 3) The list of creases *might* be a list of Gray codes.
33
+ """
34
+ return iter(_getCreases(state, leaf, increase=False))
35
+
36
+ def getLeavesCreasePost(state: EliminationState, leaf: Leaf) -> Iterator[Leaf]:
37
+ """1) `leaf` has at most `dimensionsTotal - 1` many creases.
38
+
39
+ 2) The list is ordered by increasing dimension number, which corresponds to an increasing absolute magnitude of _change_ in `leaf` number.
40
+
41
+ 3) The list of creases *might* be a list of Gray codes.
42
+ """
43
+ return iter(_getCreases(state, leaf, increase=True))
44
+
45
+ def _getCreases(state: EliminationState, leaf: Leaf, *, increase: bool = True) -> tuple[Leaf, ...]:
46
+ return _makeCreases(leaf, state.dimensionsTotal)[increase]
47
+ @cache
48
+ def _makeCreases(leaf: Leaf, dimensionsTotal: int) -> tuple[tuple[Leaf, ...], tuple[Leaf, ...]]:
49
+ listLeavesCrease: list[Leaf] = [int(bit_flip(leaf, dimensionIndex)) for dimensionIndex in range(dimensionsTotal)]
50
+
51
+ if leaf == leafOrigin: # A special case I've been unable to figure out how to incorporate in the formula.
52
+ listLeavesCreasePost: list[Leaf] = [1]
53
+ listLeavesCreaseAnte: list[Leaf] = []
54
+ else:
55
+ slicingIndices: int = is_odd(howManyDimensionsHaveOddParity(leaf))
56
+
57
+ slicerAnte: slice = slice(slicingIndices, dimensionNearest首(leaf) * bit_flip(slicingIndices, 0) or None)
58
+ slicerPost: slice = slice(bit_flip(slicingIndices, 0), dimensionNearest首(leaf) * slicingIndices or None)
59
+
60
+ if is_even(leaf):
61
+ if slicerAnte.start == 1:
62
+ slicerAnte = slice(slicerAnte.start + dimensionNearestTail(leaf), slicerAnte.stop)
63
+ if slicerPost.start == 1:
64
+ slicerPost = slice(slicerPost.start + dimensionNearestTail(leaf), slicerPost.stop)
65
+ listLeavesCreaseAnte: list[Leaf] = listLeavesCrease[slicerAnte]
66
+ listLeavesCreasePost: list[Leaf] = listLeavesCrease[slicerPost]
67
+
68
+ if leaf == 1: # A special case I've been unable to figure out how to incorporate in the formula.
69
+ listLeavesCreaseAnte = [0]
70
+ return (tuple(listLeavesCreaseAnte), tuple(listLeavesCreasePost))
71
+
72
+ #======== (mathematical) ranges of piles ====================
73
+ # TODO Ideally, figure out the formula for pile ranges instead of deconstructing leaf domains. Second best, DRYer code.
74
+
75
+ #-------- Boolean filters for (mathematical) ranges of piles -----------------------------------
76
+
77
+ @syntacticCurry
78
+ def filterCeiling(pile: Pile, dimensionsTotal: int, leaf: Leaf) -> bool:
79
+ return pile < int(bit_mask(dimensionsTotal) ^ bit_mask(dimensionsTotal - dimensionNearest首(leaf))) - howManyDimensionsHaveOddParity(leaf) + 2 - (leaf == leafOrigin)
80
+
81
+ @syntacticCurry
82
+ def filterFloor(pile: Pile, leaf: Leaf) -> bool:
83
+ return int(bit_flip(0, dimensionNearestTail(leaf) + 1)) + howManyDimensionsHaveOddParity(leaf) - 1 - (leaf == leafOrigin) <= pile
84
+
85
+ @syntacticCurry
86
+ def filterParity(pile: Pile, leaf: Leaf) -> bool:
87
+ return (pile & 1) == ((int(bit_flip(0, dimensionNearestTail(leaf) + 1)) + howManyDimensionsHaveOddParity(leaf) - 1 - (leaf == leafOrigin)) & 1)
88
+
89
+ @syntacticCurry
90
+ def filterDoubleParity(pile: Pile, dimensionsTotal: int, leaf: Leaf) -> bool:
91
+ if leaf != 首零(dimensionsTotal)+零:
92
+ return True
93
+ return (pile >> 1 & 1) == ((int(bit_flip(0, dimensionNearestTail(leaf) + 1)) + howManyDimensionsHaveOddParity(leaf) - 1 - (leaf == leafOrigin)) >> 1 & 1)
94
+
95
+ def getPileRange(state: EliminationState, pile: Pile) -> Iterator[Leaf]:
96
+ return iter(_getPileRange(pile, state.dimensionsTotal, state.mapShape, state.leavesTotal))
97
+ @cache
98
+ def _getPileRange(pile: Pile, dimensionsTotal: int, mapShape: tuple[int, ...], leavesTotal: int) -> tuple[Leaf, ...]:
99
+ if mapShapeIs2上nDimensions(mapShape):
100
+ parityMatch: Callable[[Leaf], bool] = filterParity(pile)
101
+ pileAboveFloor: Callable[[Leaf], bool] = filterFloor(pile)
102
+ pileBelowCeiling: Callable[[Leaf], bool] = filterCeiling(pile, dimensionsTotal)
103
+ matchLargerStep: Callable[[Leaf], bool] = filterDoubleParity(pile, dimensionsTotal)
104
+
105
+ pileRange: Iterable[Leaf] = range(leavesTotal)
106
+ pileRange = filter(parityMatch, pileRange)
107
+ pileRange = filter(pileAboveFloor, pileRange)
108
+ pileRange = filter(pileBelowCeiling, pileRange)
109
+ return tuple(filter(matchLargerStep, pileRange))
110
+
111
+ return tuple(range(leavesTotal))
112
+
113
+ def getDictionaryPileRanges(state: EliminationState) -> dict[Pile, tuple[Leaf, ...]]:
114
+ """At `pile`, which `leaf` values may be found in a `folding`: the mathematical range, not a Python `range` object."""
115
+ return {pile: tuple(getPileRange(state, pile)) for pile in range(state.leavesTotal)}
116
+
117
+ #======== Leaf domains ====================================
118
+
119
+ def getLeafDomain(state: EliminationState, leaf: Leaf) -> range:
120
+ return _getLeafDomain(leaf, state.dimensionsTotal, state.mapShape, state.leavesTotal)
121
+ @cache
122
+ def _getLeafDomain(leaf: Leaf, dimensionsTotal: int, mapShape: tuple[int, ...], leavesTotal: int) -> range:
123
+ """The subroutines assume `dimensionLength == 2`, but I think the concept could be extended to other `mapShape`."""
124
+ state: EliminationState = EliminationState(mapShape)
125
+ if mapShapeIs2上nDimensions(state.mapShape):
126
+ originPinned: bool = leaf == leafOrigin
127
+ return range(
128
+ state.sumsOfProductsOfDimensions[dimensionNearestTail(leaf) + inclusive] # `start`, first value included in the `range`.
129
+ + howManyDimensionsHaveOddParity(leaf)
130
+ - originPinned
131
+
132
+ , state.sumsOfProductsOfDimensionsNearest首[dimensionNearest首(leaf)] # `stop`, first value excluded from the `range`.
133
+ + 2
134
+ - howManyDimensionsHaveOddParity(leaf)
135
+ - originPinned
136
+
137
+ , 2 + (2 * (leaf == 首零(dimensionsTotal)+零)) # `step`
138
+ )
139
+ return range(leavesTotal)
140
+
141
+ """leaf domains are directly tied to sumsOfProductsOfDimensions and sumsOfProductsOfDimensionsNearest首
142
+
143
+ 2d6
144
+ (0, 32, 48, 56, 60, 62, 63) = sumsOfProductsOfDimensionsNearest首
145
+ (0, 1, 3, 7, 15, 31, 63, 127) = sumsOfProductsOfDimensions
146
+
147
+ leaf descends from 63 in sumsOfProductsOfDimensionsNearest首
148
+ first pile is dimensionsTotal and ascends by addends in sumsOfProductsOfDimensions
149
+
150
+ leaf63 starts at pile6 = 6+0
151
+ leaf62 starts at pile7 = 6+1
152
+ leaf60 starts at pile10 = 7+3
153
+ leaf56 starts at pile17 = 10+7
154
+ leaf48 starts at pile32 = 17+15
155
+ leaf32 starts at pile63 = 32+31
156
+
157
+ 2d5
158
+ sumsOfProductsOfDimensionsNearest首
159
+ (0, 16, 24, 28, 30, 31)
160
+
161
+ 31, 5+0
162
+ 30, 5+1
163
+ 28, 6+3
164
+ 24, 9+7
165
+ 16, 16+15
166
+
167
+ sumsOfProductsOfDimensions
168
+ (0, 1, 3, 7, 15, 31, 63)
169
+
170
+ {0: [0],
171
+ 1: [1],
172
+ 2: [3, 5, 9, 17],
173
+ 3: [2, 7, 11, 13, 19, 21, 25],
174
+ 4: [3, 5, 6, 9, 10, 15, 18, 23, 27, 29],
175
+ 5: [2, 7, 11, 13, 14, 19, 21, 22, 25, 26, 31],
176
+ 6: [3, 5, 6, 9, 10, 15, 17, 18, 23, 27, 29, 30],
177
+ 7: [2, 4, 7, 11, 13, 14, 19, 21, 22, 25, 26, 31],
178
+ 8: [3, 5, 6, 9, 10, 12, 15, 18, 20, 23, 27, 29, 30],
179
+ 9: [2, 4, 7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
180
+ 10: [3, 5, 6, 9, 10, 12, 15, 17, 18, 20, 23, 27, 29, 30],
181
+ 11: [2, 4, 7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
182
+ 12: [3, 5, 6, 9, 10, 12, 15, 18, 20, 23, 27, 29, 30],
183
+ 13: [2, 4, 7, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
184
+ 14: [3, 5, 6, 9, 10, 12, 15, 17, 18, 20, 23, 27, 29, 30],
185
+ 15: [2, 4, 7, 8, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
186
+ 16: [3, 5, 6, 9, 10, 12, 15, 18, 20, 23, 24, 27, 29, 30],
187
+ 17: [2, 4, 7, 8, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
188
+ 18: [5, 6, 9, 10, 12, 15, 17, 18, 20, 23, 24, 27, 29, 30],
189
+ 19: [4, 7, 8, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
190
+ 20: [5, 6, 9, 10, 12, 15, 18, 20, 23, 24, 27, 29, 30],
191
+ 21: [4, 7, 8, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
192
+ 22: [5, 6, 9, 10, 12, 15, 17, 18, 20, 23, 24, 27, 29, 30],
193
+ 23: [4, 7, 8, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
194
+ 24: [5, 6, 9, 10, 12, 15, 18, 20, 23, 24, 27, 29, 30],
195
+ 25: [4, 8, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
196
+ 26: [9, 10, 12, 15, 17, 18, 20, 23, 24, 27, 29, 30],
197
+ 27: [8, 11, 13, 14, 19, 21, 22, 25, 26, 28, 31],
198
+ 28: [9, 10, 12, 18, 20, 23, 24, 27, 29, 30],
199
+ 29: [8, 19, 21, 22, 25, 26, 28],
200
+ 30: [17, 18, 20, 24],
201
+ 31: [16]}
202
+ """
203
+
204
+ """products of dimensions and sums of products emerge from the formulas in `getLeafDomain`.
205
+ state = EliminationState((2,) * 6)
206
+ domainsOfDimensionOrigins = tuple(getLeafDomain(state, leaf) for leaf in state.productsOfDimensions)[0:-1]
207
+ sumsOfDimensionOrigins = tuple(accumulate(state.productsOfDimensions))[0:-1]
208
+ sumsOfDimensionOriginsReversed = tuple(accumulate(state.productsOfDimensions[::-1], initial=-state.leavesTotal))[1:None]
209
+ for dimensionOrigin, domain, sumOrigins, sumReversed in zip(state.productsOfDimensions, domainsOfDimensionOrigins, sumsOfDimensionOrigins, sumsOfDimensionOriginsReversed, strict=False):
210
+ print(f"{dimensionOrigin:<2}\t{domain.start == sumOrigins = }\t{sumOrigins}\t{sumReversed+2}\t{domain.stop == sumReversed+2 = }")
211
+ 1 domain.start == sumOrigins = True 1 2 domain.stop == sumReversed+2 = True
212
+ 2 domain.start == sumOrigins = True 3 34 domain.stop == sumReversed+2 = True
213
+ 4 domain.start == sumOrigins = True 7 50 domain.stop == sumReversed+2 = True
214
+ 8 domain.start == sumOrigins = True 15 58 domain.stop == sumReversed+2 = True
215
+ 16 domain.start == sumOrigins = True 31 62 domain.stop == sumReversed+2 = True
216
+ 32 domain.start == sumOrigins = True 63 64 domain.stop == sumReversed+2 = True
217
+
218
+ (Note to self: in `sumReversed+2`, consider if this is better explained by `sumReversed - descending + inclusive` or something similar.)
219
+
220
+ The piles of dimension origins (sums of products of dimensions) emerge from the following formulas!
221
+
222
+ (Note: the function below is included to capture the function as it existed at this point in development. I hope the package has improved/evolved by the time you read this.)
223
+ def getLeafDomain(state: EliminationState, leaf: int) -> range:
224
+ def workhorse(leaf: int, dimensionsTotal: int, mapShape: tuple[int, ...], leavesTotal: int) -> range:
225
+ originPinned = leaf == leafOrigin
226
+ return range(
227
+ int(bit_flip(0, howMany0coordinatesAtTail(leaf) + 1)) # `start`, first value included in the `range`.
228
+ + howManyDimensionsHaveOddParity(leaf)
229
+ - 1 - originPinned
230
+ , int(bit_mask(dimensionsTotal) ^ bit_mask(dimensionsTotal - dimensionNearest首(leaf))) # `stop`, first value excluded from the `range`.
231
+ - howManyDimensionsHaveOddParity(leaf)
232
+ + 2 - originPinned
233
+ , 2 + (2 * (leaf == 首零(dimensionsTotal)+零)) # `step`
234
+ )
235
+ return workhorse(leaf, state.dimensionsTotal, state.mapShape, state.leavesTotal)
236
+ """
237
+
238
+ def getDomainDimension一(state: EliminationState) -> tuple[tuple[int, int, int, int], ...]:
239
+ """The beans and cornbread and beans and cornbread dimension.
240
+
241
+ (leaf一零, leaf一, leaf首一, leaf首零一)
242
+ ^^^ Can you see the symmetry? ^^^
243
+
244
+ Accurate in at least six dimensions.
245
+ """
246
+ domain一零: tuple[int, ...] = tuple(getLeafDomain(state, 一+零))
247
+ domain首一: tuple[int, ...] = tuple(getLeafDomain(state, 首一(state.dimensionsTotal)))
248
+ return _getDomainDimension一(domain一零, domain首一, state.dimensionsTotal)
249
+ @cache
250
+ def _getDomainDimension一(domain一零: tuple[int, ...], domain首一: tuple[int, ...], dimensionsTotal: int) -> tuple[tuple[int, int, int, int], ...]:
251
+ domainCombined: list[tuple[int, int, int, int]] = []
252
+
253
+ for pileOfLeaf一零 in domain一零:
254
+ domainOfLeaf首一: tuple[int, ...] = domain首一
255
+ pilesTotal: int = len(domainOfLeaf首一)
256
+
257
+ listIndicesPilesExcluded: list[int] = []
258
+
259
+ if pileOfLeaf一零 <= 首二(dimensionsTotal):
260
+ pass
261
+
262
+ elif 首二(dimensionsTotal) < pileOfLeaf一零 < 首一(dimensionsTotal):
263
+ listIndicesPilesExcluded.extend([*range(1, pilesTotal // 2), *range(1 + pilesTotal // 2, 3 * pilesTotal // 4)])
264
+
265
+ elif pileOfLeaf一零 == 首一(dimensionsTotal):
266
+ listIndicesPilesExcluded.extend([*range(1, pilesTotal // 2)])
267
+
268
+ elif 首一(dimensionsTotal) < pileOfLeaf一零 < 首零(dimensionsTotal)-一:
269
+ listIndicesPilesExcluded.extend([*range(3 * pilesTotal // 4)])
270
+
271
+ elif pileOfLeaf一零 == 首零(dimensionsTotal)-一:
272
+ listIndicesPilesExcluded.extend([*range(1, 3 * pilesTotal // 4)])
273
+
274
+ elif pileOfLeaf一零 == 首零(dimensionsTotal):
275
+ listIndicesPilesExcluded.extend([*range(2, pilesTotal // 2)])
276
+
277
+ domainOfLeaf首一 = tuple(exclude(domainOfLeaf首一, listIndicesPilesExcluded))
278
+
279
+ domainCombined.extend([(pileOfLeaf一零, pileOfLeaf一零 + 1, pileOfLeaf首一, pileOfLeaf首一 + 1) for pileOfLeaf首一 in domainOfLeaf首一])
280
+
281
+ return tuple(filter(all_unique, domainCombined))
282
+
283
+ def getDomainDimension二(state: EliminationState) -> tuple[tuple[int, int, int, int], ...]:
284
+ """(leaf二一, leaf二一零, leaf二零, leaf二)."""
285
+ domain二零and二: tuple[tuple[int, int], ...] = getDomain二零and二(state)
286
+ domain二一零and二一: tuple[tuple[int, int], ...] = getDomain二一零and二一(state)
287
+ return _getDomainDimension二(domain二零and二, domain二一零and二一, state.dimensionsTotal)
288
+ @cache
289
+ def _getDomainDimension二(domain二零and二: tuple[tuple[int, int], ...], domain二一零and二一: tuple[tuple[int, int], ...], dimensionsTotal: int) -> tuple[tuple[int, int, int, int], ...]:
290
+ domain0corners: tuple[tuple[int, int], ...] = tuple(filter(consecutive, domain二零and二))
291
+ domain一corners: tuple[tuple[int, int], ...] = tuple(filter(consecutive, domain二一零and二一))
292
+ pilesTotal: int = len(domain一corners)
293
+
294
+ domainCombined: list[tuple[int, int, int, int]] = []
295
+
296
+ productsOfDimensions: tuple[int, ...] = tuple(int(bit_flip(0, dimension)) for dimension in range(dimensionsTotal + 1))
297
+
298
+ #======== By exclusion of the indices, add pairs of corners (160 tuples) ====================
299
+ for index, (pileOfLeaf二一零, pileOfLeaf二一) in enumerate(domain一corners):
300
+ listIndicesPilesExcluded: list[int] = []
301
+
302
+ dimensionTail: int = dimensionNearestTail(pileOfLeaf二一)
303
+
304
+ #-------- `excludeBelow` `index` ---------------------------------
305
+ excludeBelow: int = index
306
+ listIndicesPilesExcluded.extend(range(excludeBelow))
307
+
308
+ #-------- `excludeAbove` `index` ---------------------------------
309
+ excludeAbove: int = pilesTotal
310
+ if pileOfLeaf二一 <= 首一(dimensionsTotal):
311
+ if dimensionTail == 1:
312
+ excludeAbove = pilesTotal // 2 + index
313
+ if howManyDimensionsHaveOddParity(pileOfLeaf二一) == 2:
314
+ excludeAbove -= 1
315
+
316
+ if (howManyDimensionsHaveOddParity(pileOfLeaf二一) == 1 and (2 < dimensionNearest首(pileOfLeaf二一))):
317
+ excludeAbove += 2
318
+
319
+ if (howManyDimensionsHaveOddParity(pileOfLeaf二一) == 1
320
+ and (dimensionNearest首(pileOfLeaf二一) - raiseIfNone(dimensionSecondNearest首(pileOfLeaf二一)) < 2)
321
+ ):
322
+ addend: int = productsOfDimensions[dimensionsTotal-2] + 4
323
+ excludeAbove = domain0corners.index((pileOfLeaf二一 + addend, pileOfLeaf二一零 + addend))
324
+
325
+ else:
326
+ excludeAbove = 3 * pilesTotal // 4 + 2
327
+ if index == 0:
328
+ excludeAbove = 1
329
+ elif index <= 2:
330
+ addend = 三 + sum(productsOfDimensions[1:dimensionsTotal-2])
331
+ excludeAbove = domain0corners.index((pileOfLeaf二一 + addend, pileOfLeaf二一零 + addend))
332
+ listIndicesPilesExcluded.extend(range(excludeAbove, pilesTotal))
333
+
334
+ #-------- Exclude "knock-out" indices ---------------------------------
335
+ if pileOfLeaf二一 < 首一二(dimensionsTotal):
336
+ if dimensionTail == 4:
337
+ addend = int(bit_flip(0, dimensionTail))
338
+ start: int = domain0corners.index((pileOfLeaf二一 + addend, pileOfLeaf二一零 + addend))
339
+ listIndicesPilesExcluded.extend([*range(start, start + dimensionTail)])
340
+ if dimensionTail == 3:
341
+ addend = int(bit_flip(0, dimensionTail))
342
+ start = domain0corners.index((pileOfLeaf二一 + addend, pileOfLeaf二一零 + addend))
343
+ listIndicesPilesExcluded.extend([*range(start, start + dimensionTail - 1)])
344
+ start = domain0corners.index((pileOfLeaf二一 + addend * 2, pileOfLeaf二一零 + addend * 2))
345
+ listIndicesPilesExcluded.extend([*range(start - 1, start + dimensionTail - 1)])
346
+ if (dimensionTail < 3) and (2 < dimensionNearest首(pileOfLeaf二一)):
347
+ if 5 < dimensionsTotal:
348
+ addend = 四
349
+ start = domain0corners.index((pileOfLeaf二一 + addend, pileOfLeaf二一零 + addend))
350
+ stop: int = start + addend
351
+ step: int = 2
352
+ if (dimensionTail == 1) and (dimensionNearest首(pileOfLeaf二一) == 4):
353
+ start += 2
354
+ stop = start + 1
355
+ if dimensionTail == 2:
356
+ start += 3
357
+ if dimensionNearest首(pileOfLeaf二一) == 4:
358
+ start -= 2
359
+ stop = start + dimensionTail + inclusive
360
+ if howManyDimensionsHaveOddParity(pileOfLeaf二一) == 2:
361
+ stop = start + 1
362
+ listIndicesPilesExcluded.extend([*range(start, stop, step)])
363
+ if (((dimensionNearest首(pileOfLeaf二一) == 3) and (howManyDimensionsHaveOddParity(pileOfLeaf二一) == 1))
364
+ or (dimensionNearest首(pileOfLeaf二一) - raiseIfNone(dimensionSecondNearest首(pileOfLeaf二一)) == 3)):
365
+ addend = pileOfLeaf二一
366
+ start = domain0corners.index((pileOfLeaf二一 + addend, pileOfLeaf二一零 + addend))
367
+ stop = start + 2
368
+ if dimensionTail == 2:
369
+ start += 1
370
+ stop += 1
371
+ if dimensionNearest首(pileOfLeaf二一) == 4:
372
+ start += 3
373
+ stop += 4
374
+ step = 1
375
+ listIndicesPilesExcluded.extend([*range(start, stop, step)])
376
+ if dimensionNearest首(pileOfLeaf二一) == 2:
377
+ addend = 三
378
+ start = domain0corners.index((pileOfLeaf二一 + addend, pileOfLeaf二一零 + addend))
379
+ listIndicesPilesExcluded.extend([*range(start, start + addend, 2)])
380
+
381
+ domainCombined.extend([(pileOfLeaf二一, pileOfLeaf二一零, pileOfLeaf二零, pileOfLeaf二) for pileOfLeaf二零, pileOfLeaf二 in exclude(domain0corners, listIndicesPilesExcluded)])
382
+
383
+ #======== By inclusion of the piles, add non-corners (52 tuples) ====================
384
+ domain一nonCorners: tuple[tuple[int, int], ...] = tuple(set(domain二一零and二一).difference(set(domain一corners)))
385
+ domainCombined.extend([(pileOfLeaf一二, pileOfLeaf二一零, pileOfLeaf二一零 - 1, pileOfLeaf一二 + 1) for pileOfLeaf二一零, pileOfLeaf一二 in domain一nonCorners])
386
+
387
+ return tuple(sorted(filter(all_unique, set(domainCombined))))
388
+
389
+ def getDomainDimension首二(state: EliminationState) -> tuple[tuple[int, int, int, int], ...]:
390
+ """(leaf首二, leaf首零二, leaf首零一二, leaf首一二)."""
391
+ domain首零二and首二: tuple[tuple[int, int], ...] = getDomain首零二and首二(state)
392
+ domain首零一二and首一二: tuple[tuple[int, int], ...] = getDomain首零一二and首一二(state)
393
+ return _getDomainDimension首二(state.dimensionsTotal, domain首零二and首二, domain首零一二and首一二)
394
+ @cache
395
+ def _getDomainDimension首二(dimensionsTotal: int, domain首零二and首二: tuple[tuple[int, int], ...], domain首零一二and首一二: tuple[tuple[int, int], ...]) -> tuple[tuple[int, int, int, int], ...]:
396
+ domain0corners: tuple[tuple[int, int], ...] = tuple(filter(consecutive, domain首零二and首二))
397
+ domain一corners: tuple[tuple[int, int], ...] = tuple(filter(consecutive, domain首零一二and首一二))
398
+ pilesTotal: Leaf = len(domain一corners)
399
+
400
+ domainCombined: list[tuple[int, int, int, int]] = []
401
+
402
+ #======== By exclusion of the indices, add pairs of corners (160 tuples) ====================
403
+ for index, (pileOfLeaf首零二, pileOfLeaf首二) in enumerate(domain0corners):
404
+ listIndicesPilesExcluded: list[int] = []
405
+
406
+ dimensionTail: int = dimensionNearestTail(pileOfLeaf首零二)
407
+
408
+ #-------- `excludeBelow` `index` ---------------------------------
409
+ excludeBelow: int = index - 1
410
+ listIndicesPilesExcluded.extend(range(excludeBelow))
411
+
412
+ #-------- `excludeAbove` `index` ---------------------------------
413
+ excludeAbove: int = pilesTotal
414
+ if dimensionTail == 1:
415
+ excludeAbove = (pilesTotal - (int((pileOfLeaf首二) ^ bit_mask(dimensionsTotal)) // 4 - 1))
416
+
417
+ if howManyDimensionsHaveOddParity(pileOfLeaf首二) == 3 and (dimensionsTotal - dimensionNearest首(pileOfLeaf首二) >= 2):
418
+ excludeAbove += 2
419
+
420
+ if (howManyDimensionsHaveOddParity(pileOfLeaf首二) == 1
421
+ and (dimensionsTotal - dimensionNearest首(pileOfLeaf首二) >= 2)
422
+ and (dimensionNearest首(pileOfLeaf首二) - raiseIfNone(dimensionSecondNearest首(pileOfLeaf首二)) > 3)
423
+ ):
424
+ excludeAbove += 2
425
+
426
+ if (howManyDimensionsHaveOddParity(pileOfLeaf首二) == 1
427
+ and (dimensionNearest首(pileOfLeaf首二) - raiseIfNone(dimensionSecondNearest首(pileOfLeaf首二)) > 4)
428
+ ):
429
+ excludeAbove += 2
430
+
431
+ if ((howManyDimensionsHaveOddParity(pileOfLeaf首二) == dimensionsTotal - dimensionNearest首(pileOfLeaf首二))
432
+ and (dimensionNearest首(pileOfLeaf首二) >= 4)
433
+ and (howManyDimensionsHaveOddParity(pileOfLeaf首二) > 1)
434
+ ):
435
+ excludeAbove -= 1
436
+
437
+ else:
438
+ if 首零二(dimensionsTotal) <= pileOfLeaf首零二:
439
+ excludeAbove = pilesTotal - 1
440
+ if 首零(dimensionsTotal) < pileOfLeaf首零二 < 首零二(dimensionsTotal):
441
+ excludeAbove = pilesTotal - (int(pileOfLeaf首零二 ^ bit_mask(dimensionsTotal)) // 8 - 1)
442
+ if 首一二(dimensionsTotal) < pileOfLeaf首零二 <= 首零(dimensionsTotal):
443
+ excludeAbove = pilesTotal - int(bit_mask(dimensionsTotal - 4))
444
+
445
+ if pileOfLeaf首零二 == 首一二(dimensionsTotal):
446
+ excludeAbove = pilesTotal - int(bit_mask(dimensionsTotal - 4)) - 1
447
+ if pileOfLeaf首零二 < 首一二(dimensionsTotal):
448
+ excludeAbove = pilesTotal - int(bit_mask(dimensionsTotal - 3)) - (dimensionTail == 2)
449
+ listIndicesPilesExcluded.extend(range(excludeAbove, pilesTotal))
450
+
451
+ #-------- Exclude "knock-out" indices ---------------------------------
452
+ if dimensionTail == 1 and (abs(pileOfLeaf首零二 - 首零(dimensionsTotal)) == 2) and is_even(dimensionsTotal):
453
+ listIndicesPilesExcluded.extend([excludeAbove - 2])
454
+ if dimensionTail != 1 and 首一二(dimensionsTotal) <= pileOfLeaf首零二 <= 首零一(dimensionsTotal):
455
+ if (dimensionTail == 2) and (howManyDimensionsHaveOddParity(pileOfLeaf首零二) + 1 != dimensionNearest首(pileOfLeaf首零二) - raiseIfNone(dimensionSecondNearest首(pileOfLeaf首零二))):
456
+ listIndicesPilesExcluded.extend([pilesTotal - (int(pileOfLeaf首零二 ^ bit_mask(dimensionsTotal)) // 8 + 2)])
457
+ if (pileOfLeaf首零二 <= 首零(dimensionsTotal)) and is_even(dimensionsTotal):
458
+ listIndicesPilesExcluded.extend([pilesTotal - (int(pileOfLeaf首零二 ^ bit_mask(dimensionsTotal)) // 4 - 1)])
459
+ if dimensionTail == 3:
460
+ listIndicesPilesExcluded.extend([excludeAbove - 2])
461
+ if 3 < dimensionTail:
462
+ listIndicesPilesExcluded.extend([pilesTotal - (int(pileOfLeaf首零二 ^ bit_mask(dimensionsTotal)) // 4)])
463
+
464
+ domainCombined.extend([(pileOfLeaf首二, pileOfLeaf首零二, pileOfLeaf首零一二, pileOfLeaf首一二) for pileOfLeaf首零一二, pileOfLeaf首一二 in exclude(domain一corners, listIndicesPilesExcluded)])
465
+
466
+ #======== By inclusion of the piles, add non-corners (52 tuples) ====================
467
+ domain0nonCorners: tuple[tuple[int, int], ...] = tuple(set(domain首零二and首二).difference(set(domain0corners)))
468
+ domainCombined.extend([(pileOfLeaf首二, pileOfLeaf首零二, pileOfLeaf首零二 - 1, pileOfLeaf首二 + 1) for pileOfLeaf首零二, pileOfLeaf首二 in domain0nonCorners])
469
+
470
+ return tuple(sorted(filter(all_unique, set(domainCombined))))
471
+
472
+ def getDomain二零and二(state: EliminationState) -> tuple[tuple[int, int], ...]:
473
+ """Combined domain of leaf二零 and leaf二."""
474
+ domain二零: tuple[int, ...] = tuple(getLeafDomain(state, 二+零))
475
+ domain二: tuple[int, ...] = tuple(getLeafDomain(state, 二))
476
+ direction: Callable[[int, int], int] = add
477
+ return _getDomains二Or二一(domain二零, domain二, direction, state.dimensionsTotal, state.sumsOfProductsOfDimensions)
478
+
479
+ def getDomain二一零and二一(state: EliminationState) -> tuple[tuple[int, int], ...]:
480
+ """Combined domain of leaf二一零 and leaf二一."""
481
+ domain二一零: tuple[int, ...] = tuple(getLeafDomain(state, 二+一+零))
482
+ domain二一: tuple[int, ...] = tuple(getLeafDomain(state, 二+一))
483
+ direction: Callable[[int, int], int] = sub
484
+ return _getDomains二Or二一(domain二一零, domain二一, direction, state.dimensionsTotal, state.sumsOfProductsOfDimensions)
485
+
486
+ @cache
487
+ def _getDomains二Or二一(domain零: tuple[int, ...], domain0: tuple[int, ...], direction: Callable[[int, int], int], dimensionsTotal: int, sumsOfProductsOfDimensions: tuple[int, ...]) -> tuple[tuple[int, int], ...]:
488
+ if direction(0, 6009) == 6009:
489
+ ImaDomain二零and二: bool = True
490
+ ImaDomain二一零and二一: bool = False
491
+ else:
492
+ ImaDomain二零and二 = False
493
+ ImaDomain二一零and二一 = True
494
+
495
+ domainCombined: list[tuple[int, int]] = []
496
+
497
+ #======== By exclusion of the indices, add non-consecutive piles (54 pairs) ====================
498
+ pilesTotal: int = len(domain零)
499
+ pilesFewerDomain0: int = pilesTotal - len(domain0)
500
+
501
+ for indexDomain零, pileOfLeaf零 in enumerate(filter(between(pileOrigin, 首零(dimensionsTotal)-零), domain零)):
502
+ indicesDomain0ToExclude: list[int] = []
503
+
504
+ dimensionTail: int = dimensionNearestTail(pileOfLeaf零 - is_odd(pileOfLeaf零))
505
+
506
+ # ******* (Almost) All differences between `_getDomain二零and二` and `_getDomain二一零and二一` *******
507
+ #-------- Two identifiers with different values -------------------
508
+ # One default value from each option is a type of defensive coding, and the type checkers won't complain about possibly unbound values.
509
+ excludeBelowAddend: int = 0
510
+ steppingBasisForUnknownReasons: int = indexDomain零
511
+ if ImaDomain二零and二:
512
+ excludeBelowAddend = 0
513
+ steppingBasisForUnknownReasons = int(bit_mask(dimensionTail - 1).bit_flip(0)) # How the hell did I figure out this bizarre formula?
514
+ elif ImaDomain二一零and二一:
515
+ excludeBelowAddend = int(is_even(indexDomain零) or dimensionTail)
516
+ steppingBasisForUnknownReasons = indexDomain零
517
+
518
+ # - - - - Two special cases that 1) might be inherent, such as the differences in `pilesFewerDomain0`, or 2) might be because the formulas could be better. I'd bet on number 2.
519
+ if ImaDomain二零and二:
520
+ if pileOfLeaf零 == 二:
521
+ indicesDomain0ToExclude.extend([*range(indexDomain零 + 1)])
522
+ if pileOfLeaf零 == (首一(dimensionsTotal) + 首二(dimensionsTotal) + 首三(dimensionsTotal)):
523
+ indexDomain0: int = int(7 * pilesTotal / 8)
524
+ indexDomain0 -= pilesFewerDomain0
525
+ indicesDomain0ToExclude.extend([indexDomain0])
526
+ # ******* end *******
527
+
528
+ #-------- `excludeBelow` `index` ---------------------------------
529
+ excludeBelow: int = indexDomain零 + excludeBelowAddend
530
+ excludeBelow -= pilesFewerDomain0
531
+ indicesDomain0ToExclude.extend(range(excludeBelow))
532
+
533
+ #-------- `excludeAbove` `index` ---------------------------------
534
+ if pileOfLeaf零 <= 首一(dimensionsTotal):
535
+ excludeAbove: int = indexDomain零 + (3 * pilesTotal // 4)
536
+ excludeAbove -= pilesFewerDomain0
537
+ indicesDomain0ToExclude.extend(range(excludeAbove, pilesTotal))
538
+ if 首一(dimensionsTotal) < pileOfLeaf零 < 首零(dimensionsTotal):
539
+ excludeAbove = int(pileOfLeaf零 ^ bit_mask(dimensionsTotal)) // 2
540
+ indicesDomain0ToExclude.extend(range(excludeAbove, pilesTotal))
541
+
542
+ #-------- Exclude by stepping: exclude ((2^dimensionTail - 1) / (2^dimensionTail))-many indices, e.g., 1/2, 3/4, 15/16, after `index` -----------------
543
+ for dimension in range(dimensionTail):
544
+ indicesDomain0ToExclude.extend(range(steppingBasisForUnknownReasons + int(bit_mask(dimension)), pilesTotal, int(bit_flip(0, dimension + 1))))
545
+
546
+ #-------- Exclude "knock-out" indices ---------------------------------
547
+ if dimensionTail == 1:
548
+ if (首二(dimensionsTotal) < pileOfLeaf零 < 首零(dimensionsTotal)-零) and (2 < dimensionNearest首(pileOfLeaf零)):
549
+ if dimensionSecondNearest首(pileOfLeaf零) == 零:
550
+ indexDomain0: int = pilesTotal // 2
551
+ indexDomain0 -= pilesFewerDomain0
552
+ if 4 < domain0[indexDomain0].bit_length():
553
+ indicesDomain0ToExclude.extend([indexDomain0])
554
+ if 首一(dimensionsTotal) < pileOfLeaf零:
555
+ indexDomain0 = -(pilesTotal // 4 - is_odd(pileOfLeaf零))
556
+ indexDomain0 -= -(pilesFewerDomain0)
557
+ indicesDomain0ToExclude.extend([indexDomain0])
558
+ if dimensionSecondNearest首(pileOfLeaf零) == 一:
559
+ indexDomain0 = pilesTotal // 2 + 2
560
+ indexDomain0 -= pilesFewerDomain0
561
+ if domain0[indexDomain0] < 首零(dimensionsTotal):
562
+ indicesDomain0ToExclude.extend([indexDomain0])
563
+ indexDomain0 = -(pilesTotal // 4 - 2)
564
+ indexDomain0 -= -(pilesFewerDomain0)
565
+ if 首一(dimensionsTotal) < pileOfLeaf零:
566
+ indicesDomain0ToExclude.extend([indexDomain0])
567
+
568
+ if dimensionSecondNearest首(pileOfLeaf零) == 一+零:
569
+ indexDomain0 = -(pilesTotal // 4)
570
+ indexDomain0 -= -(pilesFewerDomain0)
571
+ indicesDomain0ToExclude.extend([indexDomain0])
572
+
573
+ indexDomain0 = 3 * pilesTotal // 4
574
+ indexDomain0 -= pilesFewerDomain0
575
+ if pileOfLeaf零 < 首一二(dimensionsTotal):
576
+ # NOTE My thinking: because 首一二(dimensionsTotal)
577
+ dimensionIndexPart首: int = dimensionsTotal
578
+ dimensionIndexPart一: int = dimensionIndex(一)
579
+ dimensionIndexPart二: int = dimensionIndex(二)
580
+
581
+ # Compute the index from the head `首`
582
+ indexSumsOfProductsOfDimensions: int = dimensionIndexPart首 - (dimensionIndexPart一 + dimensionIndexPart二)
583
+
584
+ addend: int = sumsOfProductsOfDimensions[indexSumsOfProductsOfDimensions]
585
+ if ImaDomain二一零and二一:
586
+ addend -= 1 # decreasing?
587
+ pileOfLeaf0: int = addend + 首零(dimensionsTotal)
588
+ indexDomain0 = domain0.index(pileOfLeaf0)
589
+
590
+ indicesDomain0ToExclude.extend([indexDomain0])
591
+
592
+ if dimensionThirdNearest首(pileOfLeaf零) == 零:
593
+ if dimensionSecondNearest首(pileOfLeaf零) == 一+零:
594
+ indicesDomain0ToExclude.extend([indexDomain0 - 2])
595
+ if dimensionNearest首(pileOfLeaf零) == 一+零:
596
+ indicesDomain0ToExclude.extend([indexDomain0 - 2])
597
+
598
+ elif 首一(dimensionsTotal) + 首三(dimensionsTotal) + is_odd(pileOfLeaf零) == pileOfLeaf零:
599
+ indexDomain0 = (3 * pilesTotal // 4) - 1
600
+ indexDomain0 -= pilesFewerDomain0
601
+ indicesDomain0ToExclude.extend([indexDomain0])
602
+
603
+ domainCombined.extend([(pileOfLeaf零, pileOfLeaf0) for pileOfLeaf0 in exclude(domain0, indicesDomain0ToExclude)])
604
+
605
+ #======== By inclusion of the piles, add consecutive piles (22 pairs) ====================
606
+ domainCombined.extend([(pile, direction(pile, 零)) for pile in domain零 if direction(pile, 零) in domain0])
607
+
608
+ return tuple(sorted(set(domainCombined)))
609
+
610
+ def getDomain首零二and首二(state: EliminationState) -> tuple[tuple[int, int], ...]:
611
+ """Combined domain of leaf首零二 and leaf首二."""
612
+ domain首零二: tuple[int, ...] = tuple(getLeafDomain(state, 首零二(state.dimensionsTotal)))
613
+ domain首二: tuple[int, ...] = tuple(getLeafDomain(state, 首二(state.dimensionsTotal)))
614
+ return _getDomain首零二and首二(domain首零二, domain首二, state.dimensionsTotal)
615
+ @cache
616
+ def _getDomain首零二and首二(domain首零二: tuple[int, ...], domain首二: tuple[int, ...], dimensionsTotal: int) -> tuple[tuple[int, int], ...]:
617
+ domainCombined: list[tuple[int, int]] = []
618
+
619
+ domain零: tuple[int, ...] = domain首零二
620
+ domain0: tuple[int, ...] = domain首二
621
+
622
+ #======== By inclusion of the piles, add consecutive piles (22 pairs) ====================
623
+ direction: Callable[[int, int], int] = sub
624
+ domainCombined.extend([(pile, direction(pile, 零)) for pile in domain零 if direction(pile, 零) in domain0])
625
+
626
+ #======== By exclusion of the indices, add non-consecutive piles (54 pairs) ====================
627
+ pilesTotal: int = len(domain零)
628
+ pilesFewerDomain0: int = pilesTotal - len(domain0)
629
+
630
+ for index, pileOfLeaf零 in enumerate(domain零):
631
+ if pileOfLeaf零 < 首零(dimensionsTotal)+零:
632
+ continue
633
+ listIndicesPilesExcluded: list[int] = []
634
+
635
+ dimensionTail: int = dimensionNearestTail(direction(pileOfLeaf零, is_odd(pileOfLeaf零)))
636
+
637
+ #-------- `excludeBelow` `index` ---------------------------------
638
+ if 首零一(dimensionsTotal) < pileOfLeaf零:
639
+ excludeBelow: int = index + 3 - (3 * pilesTotal // 4)
640
+ else:
641
+ excludeBelow = 2 + (首零一(dimensionsTotal) - direction(pileOfLeaf零, is_odd(pileOfLeaf零))) // 2
642
+ excludeBelow -= pilesFewerDomain0
643
+ listIndicesPilesExcluded.extend(range(excludeBelow))
644
+
645
+ #-------- `excludeAbove` `index` ---------------------------------
646
+ excludeAbove: int = index + 2 - int(bit_mask(dimensionTail))
647
+ excludeAbove -= pilesFewerDomain0
648
+ listIndicesPilesExcluded.extend(range(excludeAbove, pilesTotal))
649
+
650
+ #-------- Exclude by stepping: exclude ((2^dimensionTail - 1) / (2^dimensionTail))-many indices, e.g., 1/2, 3/4, 15/16, after `index` -----------------
651
+ countFromTheEnd: int = pilesTotal - 1
652
+ countFromTheEnd -= pilesFewerDomain0
653
+ steppingBasisForUnknownReasons: int = countFromTheEnd - int(bit_mask(dimensionTail - 1).bit_flip(0))
654
+ for dimension in range(dimensionTail):
655
+ listIndicesPilesExcluded.extend(range(steppingBasisForUnknownReasons - int(bit_mask(dimension)), decreasing, decreasing * int(bit_flip(0, dimension + 1))))
656
+
657
+ #-------- Exclude "knock-out" indices ---------------------------------
658
+ if dimensionTail == 1:
659
+ if (dimensionThirdNearest首(pileOfLeaf零) == 一) and (二+零 <= dimensionNearest首(pileOfLeaf零)):
660
+ indexDomain0: int = (pilesTotal // 2) + 1
661
+ indexDomain0 -= pilesFewerDomain0
662
+ listIndicesPilesExcluded.extend([indexDomain0])
663
+ indexDomain0: int = (pilesTotal // 4) + 1
664
+ indexDomain0 -= pilesFewerDomain0
665
+ listIndicesPilesExcluded.extend([indexDomain0])
666
+ if pileOfLeaf零 < 首零一(dimensionsTotal):
667
+ listIndicesPilesExcluded.extend([indexDomain0 - 2])
668
+
669
+ if howManyDimensionsHaveOddParity(pileOfLeaf零) == 一:
670
+ indexDomain0 = (pilesTotal // 4) + 3
671
+ indexDomain0 -= pilesFewerDomain0
672
+ if dimensionSecondNearest首(pileOfLeaf零) == 一:
673
+ listIndicesPilesExcluded.extend([indexDomain0])
674
+ if dimensionSecondNearest首(pileOfLeaf零) == 二:
675
+ listIndicesPilesExcluded.extend([indexDomain0])
676
+ if (((dimensionNearest首(pileOfLeaf零) == dimensionsTotal - 1) and (dimensionSecondNearest首(pileOfLeaf零) == dimensionsTotal - 3))
677
+ or (dimensionSecondNearest首(pileOfLeaf零) == 二)):
678
+ listIndicesPilesExcluded.extend([indexDomain0 - 2])
679
+ indexDomain0 = (pilesTotal // 2) - 1
680
+ indexDomain0 -= pilesFewerDomain0
681
+ listIndicesPilesExcluded.extend([indexDomain0])
682
+
683
+ elif (首零一(dimensionsTotal) - direction(首三(dimensionsTotal), is_odd(pileOfLeaf零))) == pileOfLeaf零:
684
+ indexDomain0 = (pilesTotal // 4) + 2
685
+ indexDomain0 -= pilesFewerDomain0
686
+ listIndicesPilesExcluded.extend([indexDomain0])
687
+
688
+ domainCombined.extend([(pileOfLeaf零, pileOfLeaf0) for pileOfLeaf0 in exclude(domain0, listIndicesPilesExcluded)])
689
+
690
+ return tuple(sorted(set(domainCombined)))
691
+
692
+ def getDomain首零一二and首一二(state: EliminationState) -> tuple[tuple[int, int], ...]:
693
+ """Combined domain of leaf首零一二 and leaf首一二."""
694
+ domain首零一二: tuple[int, ...] = tuple(getLeafDomain(state, 首零一二(state.dimensionsTotal)))
695
+ domain首一二: tuple[int, ...] = tuple(getLeafDomain(state, 首一二(state.dimensionsTotal)))
696
+ direction: Callable[[int, int], int] = add
697
+ return _getDomain首零一二and首一二(domain首零一二, domain首一二, direction, state.dimensionsTotal)
698
+ @cache
699
+ def _getDomain首零一二and首一二(domain零: tuple[int, ...], domain0: tuple[int, ...], direction: Callable[[int, int], int], dimensionsTotal: int) -> tuple[tuple[int, int], ...]:
700
+ domainCombined: list[tuple[int, int]] = []
701
+
702
+ #======== By exclusion of the indices, add non-consecutive piles (54 pairs) ====================
703
+ pilesTotal: int = len(domain零)
704
+ pilesFewerDomain0: int = pilesTotal - len(domain0)
705
+
706
+ for indexDomain零, pileOfLeaf零 in enumerate(domain零):
707
+ if pileOfLeaf零 < 首零(dimensionsTotal):
708
+ continue
709
+ indicesDomain0ToExclude: list[int] = []
710
+
711
+ dimensionTail: int = dimensionNearestTail(direction(pileOfLeaf零, is_odd(pileOfLeaf零)))
712
+
713
+ #-------- `excludeBelow` `index` ---------------------------------
714
+ if 首零一(dimensionsTotal) < pileOfLeaf零:
715
+ excludeBelow: int = indexDomain零 + 1 - (3 * pilesTotal // 4)
716
+ else:
717
+ excludeBelow = (首零一(dimensionsTotal) - direction(pileOfLeaf零, is_odd(pileOfLeaf零))) // 2
718
+ excludeBelow -= pilesFewerDomain0
719
+ indicesDomain0ToExclude.extend(range(excludeBelow))
720
+
721
+ #-------- `excludeAbove` `index` ---------------------------------
722
+ excludeAbove: int = indexDomain零 + 1 - int(bit_mask(dimensionTail))
723
+ excludeAbove -= pilesFewerDomain0
724
+ indicesDomain0ToExclude.extend(range(excludeAbove, pilesTotal))
725
+
726
+ #-------- Exclude by stepping: exclude ((2^dimensionTail - 1) / (2^dimensionTail))-many indices, e.g., 1/2, 3/4, 15/16, after `index` -----------------
727
+ steppingBasisForUnknownReasons: int = indexDomain零
728
+ for dimension in range(dimensionTail):
729
+ indicesDomain0ToExclude.extend(range(steppingBasisForUnknownReasons - int(bit_mask(dimension)), decreasing, decreasing * int(bit_flip(0, dimension + 1))))
730
+
731
+ #-------- Exclude "knock-out" indices ---------------------------------
732
+ if dimensionTail == 1:
733
+ if (dimensionThirdNearest首(pileOfLeaf零) == 一) and (二+零 <= dimensionNearest首(pileOfLeaf零)):
734
+ indexDomain0: int = pilesTotal // 2
735
+ indexDomain0 -= pilesFewerDomain0
736
+ indicesDomain0ToExclude.extend([indexDomain0])
737
+ indexDomain0: int = pilesTotal // 4
738
+ indexDomain0 -= pilesFewerDomain0
739
+ indicesDomain0ToExclude.extend([indexDomain0])
740
+ if pileOfLeaf零 < 首零一(dimensionsTotal):
741
+ indicesDomain0ToExclude.extend([indexDomain0 - 2])
742
+ if dimensionThirdNearest首(pileOfLeaf零) == 一+零:
743
+ indexDomain0 = pilesTotal // 4
744
+ indexDomain0 -= pilesFewerDomain0
745
+ if dimensionFourthNearest首(pileOfLeaf零) == 一:
746
+ indicesDomain0ToExclude.extend([indexDomain0])
747
+ if howManyDimensionsHaveOddParity(pileOfLeaf零) == 一:
748
+ indexDomain0 = (pilesTotal // 4) + 2
749
+ indexDomain0 -= pilesFewerDomain0
750
+ if dimensionSecondNearest首(pileOfLeaf零) == 一:
751
+ indexDomain0 = domain0.index(首零(dimensionsTotal) - 一)
752
+ indicesDomain0ToExclude.extend([indexDomain0])
753
+ if dimensionSecondNearest首(pileOfLeaf零) == 二:
754
+ indicesDomain0ToExclude.extend([indexDomain0])
755
+ if (首零二(dimensionsTotal) < pileOfLeaf零) and (二+零 <= dimensionNearest首(pileOfLeaf零)):
756
+ indicesDomain0ToExclude.extend([indexDomain0 - 2])
757
+ indexDomain0 = (pilesTotal // 2) - 2
758
+ indexDomain0 -= pilesFewerDomain0
759
+ indicesDomain0ToExclude.extend([indexDomain0])
760
+
761
+ elif (首零一(dimensionsTotal) - direction(首三(dimensionsTotal), is_odd(pileOfLeaf零))) == pileOfLeaf零:
762
+ indexDomain0 = (pilesTotal // 4) + 1
763
+ indexDomain0 -= pilesFewerDomain0
764
+ indicesDomain0ToExclude.extend([indexDomain0])
765
+
766
+ domainCombined.extend([(pileOfLeaf零, pileOfLeaf0) for pileOfLeaf0 in exclude(domain0, indicesDomain0ToExclude)])
767
+
768
+ #======== By inclusion of the piles, add consecutive piles (22 pairs) ====================
769
+ domainCombined.extend([(pile, direction(pile, 零)) for pile in domain零 if direction(pile, 零) in domain0])
770
+
771
+ return tuple(sorted(set(domainCombined)))
772
+
773
+ def getLeaf首零Plus零Domain(state: EliminationState, leaf: Leaf | None = None) -> tuple[Pile, ...]:
774
+ """Get the full domain of `leaf首零Plus零` that is valid in all cases, or if `leaf一零` and `leaf首零一` are pinned in `state.permutationSpace`, get a domain of `leaf首零Plus零` customized to `pileOfLeaf一零` and `pileOfLeaf首零一`."""
775
+ if leaf is None:
776
+ leaf = (零)+首零(state.dimensionsTotal)
777
+ domain首零Plus零: tuple[Pile, ...] = tuple(getLeafDomain(state, leaf))
778
+ leaf一零: Leaf = 一+零
779
+ leaf首零一: Leaf = 首零一(state.dimensionsTotal)
780
+ if leafIsPinned(state.permutationSpace, leaf一零) and leafIsPinned(state.permutationSpace, leaf首零一):
781
+ pileOfLeaf一零: Pile = raiseIfNone(reverseLookup(state.permutationSpace, leaf一零))
782
+ pileOfLeaf首零一: Pile = raiseIfNone(reverseLookup(state.permutationSpace, leaf首零一))
783
+ domain首零Plus零 = _getLeaf首零Plus零Domain(domain首零Plus零, pileOfLeaf一零, pileOfLeaf首零一, state.dimensionsTotal, state.leavesTotal)
784
+ return domain首零Plus零
785
+ @cache
786
+ def _getLeaf首零Plus零Domain(domain首零Plus零: tuple[Pile, ...], pileOfLeaf一零: Pile, pileOfLeaf首零一: Pile, dimensionsTotal: int, leavesTotal: int) -> tuple[Pile, ...]:
787
+ pilesTotal: int = 首一(dimensionsTotal)
788
+
789
+ bump: int = 1 - int(pileOfLeaf一零.bit_count() == 1)
790
+ howMany: int = dimensionsTotal - (pileOfLeaf一零.bit_length() + bump)
791
+ onesInBinary: int = int(bit_mask(howMany))
792
+ ImaPattern: int = pilesTotal - onesInBinary
793
+
794
+ listIndicesPilesExcluded: list[int] = []
795
+ if pileOfLeaf一零 == 二:
796
+ listIndicesPilesExcluded.extend([零, 一, 二]) # These symbols make this pattern jump out.
797
+
798
+ if 二 < pileOfLeaf一零 <= 首二(dimensionsTotal):
799
+ stop: int = pilesTotal // 2 - 1
800
+ listIndicesPilesExcluded.extend(range(1, stop))
801
+
802
+ aDimensionPropertyNotFullyUnderstood: int = 5
803
+ for _dimension in loops(dimensionsTotal - aDimensionPropertyNotFullyUnderstood):
804
+ start: int = 1 + stop
805
+ stop += (stop+1) // 2
806
+ listIndicesPilesExcluded.extend([*range(start, stop)])
807
+
808
+ listIndicesPilesExcluded.extend([*range(1 + stop, ImaPattern)])
809
+
810
+ if 首二(dimensionsTotal) < pileOfLeaf一零:
811
+ listIndicesPilesExcluded.extend([*range(1, ImaPattern)])
812
+
813
+ bump = 1 - int((leavesTotal - pileOfLeaf首零一).bit_count() == 1)
814
+ howMany = dimensionsTotal - ((leavesTotal - pileOfLeaf首零一).bit_length() + bump)
815
+ onesInBinary = int(bit_mask(howMany))
816
+ ImaPattern = pilesTotal - onesInBinary
817
+
818
+ aDimensionPropertyNotFullyUnderstood = 5
819
+
820
+ if pileOfLeaf首零一 == leavesTotal-二:
821
+ listIndicesPilesExcluded.extend([-零 -1, -(一) -1])
822
+ if aDimensionPropertyNotFullyUnderstood <= dimensionsTotal:
823
+ listIndicesPilesExcluded.extend([-二 -1])
824
+
825
+ if ((首零一二(dimensionsTotal) < pileOfLeaf首零一 < leavesTotal-二)
826
+ and (首二(dimensionsTotal) < pileOfLeaf一零 <= 首零(dimensionsTotal))):
827
+ listIndicesPilesExcluded.extend([-1])
828
+
829
+ if 首零一二(dimensionsTotal) <= pileOfLeaf首零一 < leavesTotal-二:
830
+ stop: int = pilesTotal // 2 - 1
831
+ listIndicesPilesExcluded.extend(range((1 + inclusive) * decreasing, (stop + inclusive) * decreasing, decreasing))
832
+
833
+ for _dimension in loops(dimensionsTotal - aDimensionPropertyNotFullyUnderstood):
834
+ start: int = 1 + stop
835
+ stop += (stop+1) // 2
836
+ listIndicesPilesExcluded.extend([*range((start + inclusive) * decreasing, (stop + inclusive) * decreasing, decreasing)])
837
+
838
+ listIndicesPilesExcluded.extend([*range((1 + stop + inclusive) * decreasing, (ImaPattern + inclusive) * decreasing, decreasing)])
839
+
840
+ if 二 <= pileOfLeaf一零 <= 首零(dimensionsTotal):
841
+ listIndicesPilesExcluded.extend([零, 一, 二, pilesTotal//2])
842
+
843
+ if ((pileOfLeaf首零一 == 首零一二(dimensionsTotal))
844
+ and (首一(dimensionsTotal) < pileOfLeaf一零 <= 首零(dimensionsTotal))):
845
+ listIndicesPilesExcluded.extend([-1])
846
+
847
+ if 首零一(dimensionsTotal) < pileOfLeaf首零一 < 首零一二(dimensionsTotal):
848
+ if pileOfLeaf一零 in [首一(dimensionsTotal), 首零(dimensionsTotal)]:
849
+ listIndicesPilesExcluded.extend([-1])
850
+ elif 二 < pileOfLeaf一零 < 首二(dimensionsTotal):
851
+ listIndicesPilesExcluded.extend([0])
852
+
853
+ if pileOfLeaf首零一 < 首零一二(dimensionsTotal):
854
+ listIndicesPilesExcluded.extend([*range((1 + inclusive) * decreasing, (ImaPattern + inclusive) * decreasing, decreasing)])
855
+
856
+ pileOfLeaf一零ARCHETYPICAL: int = 首一(dimensionsTotal)
857
+ bump = 1 - int(pileOfLeaf一零ARCHETYPICAL.bit_count() == 1)
858
+ howMany = dimensionsTotal - (pileOfLeaf一零ARCHETYPICAL.bit_length() + bump)
859
+ onesInBinary = int(bit_mask(howMany))
860
+ ImaPattern = pilesTotal - onesInBinary
861
+
862
+ if pileOfLeaf首零一 == leavesTotal-二:
863
+ if pileOfLeaf一零 == 二:
864
+ listIndicesPilesExcluded.extend([零, 一, 二, pilesTotal//2 -1, pilesTotal//2])
865
+ if 二 < pileOfLeaf一零 <= 首零(dimensionsTotal):
866
+ IDK: int = ImaPattern - 1
867
+ listIndicesPilesExcluded.extend([*range(1, 3 * pilesTotal // 4), *range(1 + 3 * pilesTotal // 4, IDK)])
868
+ if 首一(dimensionsTotal) < pileOfLeaf一零 <= 首零(dimensionsTotal):
869
+ listIndicesPilesExcluded.extend([-1])
870
+
871
+ if pileOfLeaf首零一 == 首零一(dimensionsTotal):
872
+ if pileOfLeaf一零 == 首零(dimensionsTotal):
873
+ listIndicesPilesExcluded.extend([-1])
874
+ elif (二 < pileOfLeaf一零 < 首二(dimensionsTotal)) or (首二(dimensionsTotal) < pileOfLeaf一零 < 首一(dimensionsTotal)):
875
+ listIndicesPilesExcluded.extend([0])
876
+
877
+ return tuple(exclude(domain首零Plus零, listIndicesPilesExcluded))
878
+
879
+ def getDictionaryLeafDomains(state: EliminationState) -> dict[int, range]:
880
+ """For each `leaf`, the associated Python `range` defines the mathematical domain:
881
+ 1. every `pile` at which `leaf` may be found in a `folding` and
882
+ 2. in the set of all valid foldings, every `pile` at which `leaf` must be found.
883
+ """ # noqa: D205
884
+ return {leaf: getLeafDomain(state, leaf) for leaf in range(state.leavesTotal)}
885
+
886
+ #======== Specialized tools ===============================
887
+
888
+ def getDataFrameFoldings(state: EliminationState) -> pandas.DataFrame | None:
889
+ pathFilename: Path = Path(f'{packageSettings.pathPackage}/tests/dataSamples/arrayFoldingsP2d{state.dimensionsTotal}.pkl')
890
+ dataframeFoldings: pandas.DataFrame | None = None
891
+ if pathFilename.exists():
892
+ dataframeFoldings = pandas.DataFrame(pandas.read_pickle(pathFilename)) # noqa: S301
893
+ else:
894
+ message: str = f"{ansiColors.YellowOnBlack}I received {state.dimensionsTotal = }, but I could not find the data at:\n\t{pathFilename!r}.{ansiColorReset}"
895
+ sys.stderr.write(message + '\n')
896
+ return dataframeFoldings
897
+
898
+ def makeVerificationDataLeavesDomain(listDimensions: Sequence[int], listLeaves: Sequence[int | Callable[[int], int]], pathFilename: PurePath | None = None, settings: dict[str, dict[str, Any]] | None = None) -> PurePath:
899
+ """Create a Python module containing combined domain data for multiple leaves across multiple mapShapes.
900
+
901
+ This function extracts the actual combined domain (the set of valid pile position tuples) for a group of leaves from pickled
902
+ folding data. The data is used for verification in pytest tests comparing computed domains against empirical data.
903
+
904
+ The combined domain is a set of tuples where each tuple represents the pile positions for the specified leaves in a valid
905
+ folding. For example, if `listLeaves` is `[4, 5, 6, 7]`, each tuple has 4 elements representing the pile where each of those
906
+ leaves appears in a folding.
907
+
908
+ Parameters
909
+ ----------
910
+ listDimensions : Sequence[int]
911
+ The dimension counts to process (e.g., `[4, 5, 6]` for 2^4, 2^5, 2^6 leaf maps).
912
+ listLeaves : Sequence[int | Callable[[int], int]]
913
+ The leaves whose combined domain to extract. Elements can be:
914
+ - Integers for absolute leaf indices (e.g., `4`, `5`, `6`, `7`)
915
+ - Callables that take `dimensionsTotal` and return a leaf index (e.g., `首二`, `首零二`)
916
+ pathFilename : PurePath | None = None
917
+ The output file path. If `None`, defaults to `tests/dataSamples/p2DnDomain{leafNames}.py`.
918
+ settings : dict[str, dict[str, Any]] | None = None
919
+ Settings for `writePython` formatter. If `None`, uses defaults.
920
+
921
+ Returns
922
+ -------
923
+ pathFilename : PurePath
924
+ The path where the module was written.
925
+
926
+ """
927
+ def resolveLeaf(leafSpec: int | Callable[[int], int], dimensionsTotal: int) -> int:
928
+ return leafSpec(dimensionsTotal) if callable(leafSpec) else leafSpec
929
+
930
+ def getLeafName(leafSpec: int | Callable[[int], int]) -> str:
931
+ leafSpecName: str = str(leafSpec)
932
+ if callable(leafSpec):
933
+ leafSpecName = getattr(leafSpec, "__name__", leafSpecName)
934
+ return leafSpecName
935
+
936
+ listLeafNames: list[str] = [getLeafName(leafSpec) for leafSpec in listLeaves]
937
+ filenameLeafPart: str = '_'.join(listLeafNames)
938
+
939
+ if pathFilename is None:
940
+ pathFilename = Path(f"{packageSettings.pathPackage}/tests/dataSamples/p2DnDomain{filenameLeafPart}.py")
941
+ else:
942
+ pathFilename = Path(pathFilename)
943
+
944
+ dictionaryDomainsByDimensions: dict[int, list[tuple[int, ...]]] = {}
945
+
946
+ for dimensionsTotal in listDimensions:
947
+ mapShape: tuple[int, ...] = (2,) * dimensionsTotal
948
+ state: EliminationState = EliminationState(mapShape)
949
+ dataframeFoldings: pandas.DataFrame = raiseIfNone(getDataFrameFoldings(state))
950
+
951
+ listResolvedLeaves: list[int] = [resolveLeaf(leafSpec, dimensionsTotal) for leafSpec in listLeaves]
952
+
953
+ listCombinedTuples: list[tuple[int, ...]] = []
954
+ for indexRow in range(len(dataframeFoldings)):
955
+ rowFolding: pandas.Series = dataframeFoldings.iloc[indexRow]
956
+ tuplePiles: tuple[int, ...] = tuple(int(rowFolding[rowFolding == leaf].index[0]) for leaf in listResolvedLeaves)
957
+ listCombinedTuples.append(tuplePiles)
958
+
959
+ listUniqueTuples: list[tuple[int, ...]] = sorted(set(listCombinedTuples))
960
+ dictionaryDomainsByDimensions[dimensionsTotal] = listUniqueTuples
961
+
962
+ listPythonSource: list[str] = [
963
+ '"""Verification data for combined leaf domains.',
964
+ '',
965
+ 'This module contains empirically extracted combined domain data for leaves',
966
+ f'{listLeafNames} across multiple mapShape configurations.',
967
+ '',
968
+ 'Each list is named `listDomain2D{dimensionsTotal}` where `dimensionsTotal`',
969
+ 'is the exponent in the 2^dimensionsTotal mapShape, and it contains tuples representing',
970
+ 'valid pile positions for the specified leaves. The tuple order follows the original',
971
+ 'leaf argument order.',
972
+ '"""',
973
+ '',
974
+ ]
975
+
976
+ for dimensionsTotal in sorted(dictionaryDomainsByDimensions):
977
+ variableName: str = f"listDomain2D{dimensionsTotal}"
978
+ listPythonSource.append(f'{variableName}: list[tuple[int, ...]] = {dictionaryDomainsByDimensions[dimensionsTotal]!r}')
979
+ listPythonSource.append('')
980
+
981
+ pythonSource: str = '\n'.join(listPythonSource)
982
+ writePython(pythonSource, pathFilename, settings)
983
+
984
+ return pathFilename
985
+
986
+ #======== In development ========================
987
+ # ruff: noqa: SIM102
988
+ # I am developing in this module because of Python's effing namespace and "circular import" issues.
989
+
990
+ # TODO Continue developing getDictionaryConditionalLeafPredecessors
991
+ def getDictionaryConditionalLeafPredecessors(state: EliminationState) -> dict[Leaf, dict[Pile, list[Leaf]]]:
992
+ """leaf: pile: [conditional `leafPredecessor`].
993
+
994
+ Some leaves are always preceded by one or more leaves. Most leaves, however, are preceded by one or more other leaves only if
995
+ the leaf is in a specific pile.
996
+ """
997
+ dictionaryConditionalLeafPredecessors: dict[Leaf, dict[Pile, list[Leaf]]] = {}
998
+ if mapShapeIs2上nDimensions(state.mapShape, youMustBeDimensionsTallToPinThis=6):
999
+ dictionaryConditionalLeafPredecessors = _getDictionaryConditionalLeafPredecessors(state.mapShape)
1000
+ return dictionaryConditionalLeafPredecessors
1001
+ @cache
1002
+ def _getDictionaryConditionalLeafPredecessors(mapShape: tuple[int, ...]) -> dict[Leaf, dict[Pile, list[Leaf]]]:
1003
+ """Prototype."""
1004
+ state = EliminationState(mapShape)
1005
+ dictionaryDomains: dict[Leaf, range] = getDictionaryLeafDomains(state)
1006
+
1007
+ dictionaryPrecedence: dict[Leaf, dict[Pile, list[Leaf]]] = {}
1008
+
1009
+ #======== piles at the beginning of the leaf's domain ================
1010
+ for dimension in range(3, state.dimensionsTotal + inclusive):
1011
+ for countDown in range(dimension - 2 + decreasing, decreasing, decreasing):
1012
+ for leaf in range(state.productsOfDimensions[dimension] - sum(state.productsOfDimensions[countDown:dimension - 2]), state.leavesTotal, state.productsOfDimensions[dimension - 1]):
1013
+ dictionaryPrecedence[leaf] = {aPile: [state.productsOfDimensions[dimensionNearest首(leaf)] + state.productsOfDimensions[dimensionNearestTail(leaf)]]
1014
+ for aPile in list(dictionaryDomains[leaf])[0: getSumsOfProductsOfDimensionsNearest首(state.productsOfDimensions, dimensionFrom首=dimension - 1)[dimension - 2 - countDown] // 2]}
1015
+
1016
+ #-------- The beginning of domain首一Plus零 --------------------------------
1017
+ leaf = (零)+首一(state.dimensionsTotal)
1018
+ dictionaryPrecedence[leaf] = {aPile: [2 * state.productsOfDimensions[dimensionNearest首(leaf)] + state.productsOfDimensions[dimensionNearestTail(leaf)]
1019
+ , 3 * state.productsOfDimensions[dimensionNearest首(leaf)] + state.productsOfDimensions[dimensionNearestTail(leaf)]]
1020
+ for aPile in list(dictionaryDomains[leaf])[1:2]}
1021
+ del leaf
1022
+
1023
+ #======== leaf首零一Plus零: conditional `leafPredecessor` in all piles of its domain ===========
1024
+ leaf: Leaf = (零)+首零一(state.dimensionsTotal)
1025
+ listOfPiles = list(dictionaryDomains[leaf])
1026
+ dictionaryPrecedence[leaf] = {aPile: [] for aPile in list(dictionaryDomains[leaf])}
1027
+ sumsOfProductsOfDimensionsNearest首: tuple[int, ...] = getSumsOfProductsOfDimensionsNearest首(state.productsOfDimensions)
1028
+ sumsOfProductsOfDimensionsNearest首InSubHyperplane: tuple[int, ...] = getSumsOfProductsOfDimensionsNearest首(state.productsOfDimensions, dimensionFrom首=state.dimensionsTotal - 1)
1029
+ pileStepAbsolute = 2
1030
+
1031
+ for aPile in listOfPiles[listOfPiles.index(一+零): listOfPiles.index(neg(零)+首零(state.dimensionsTotal)) + inclusive]:
1032
+ dictionaryPrecedence[leaf][aPile].append((零)+首零(state.dimensionsTotal))
1033
+
1034
+ for indexUniversal in range(state.dimensionsTotal - 2):
1035
+ leafPredecessorTheFirst: int = state.sumsOfProductsOfDimensions[indexUniversal + 2]
1036
+ leavesPredecessorInThisSeries: int = state.productsOfDimensions[howManyDimensionsHaveOddParity(leafPredecessorTheFirst)]
1037
+ for addend in range(leavesPredecessorInThisSeries):
1038
+ leafPredecessor = leafPredecessorTheFirst + (addend * decreasing)
1039
+ pileFirst: int = (
1040
+ sumsOfProductsOfDimensionsNearest首[indexUniversal]
1041
+ + state.sumsOfProductsOfDimensions[2]
1042
+ + state.productsOfDimensions[state.dimensionsTotal - (indexUniversal + 2)]
1043
+ - ((pileStepAbsolute * 2 * (howManyDimensionsHaveOddParity(leafPredecessor) - 1 + is_even(leafPredecessor)))
1044
+ * (1 + (2 == (howManyDimensionsHaveOddParity(leafPredecessor) + is_even(leafPredecessor)) == dimensionNearest首(leafPredecessor)))
1045
+ )
1046
+ )
1047
+ for aPile in listOfPiles[listOfPiles.index(pileFirst): None]:
1048
+ dictionaryPrecedence[leaf][aPile].append(leafPredecessor)
1049
+
1050
+ leafPredecessor首零: int = leafPredecessor + 首零(state.dimensionsTotal)
1051
+ if (leafInSubHyperplane(leafPredecessor) == 0) and is_odd(dimensionNearestTail(leafPredecessor)):
1052
+ dictionaryPrecedence[leaf][pileFirst].append(leafPredecessor首零)
1053
+ if leafPredecessor首零 == leaf:
1054
+ continue
1055
+ pileFirst = listOfPiles[-1] - (
1056
+ pileStepAbsolute * (
1057
+ howManyDimensionsHaveOddParity(leafPredecessor首零)
1058
+ - 1
1059
+ + is_even(leafPredecessor首零)
1060
+ - is_odd(leafPredecessor首零)
1061
+ - int(dimensionNearestTail(leafPredecessor首零) == state.dimensionsTotal - 2)
1062
+ - int(leaf < leafPredecessor首零)
1063
+ ))
1064
+ for aPile in listOfPiles[listOfPiles.index(pileFirst): None]:
1065
+ dictionaryPrecedence[leaf][aPile].append(leafPredecessor首零)
1066
+
1067
+ if indexUniversal < state.dimensionsTotal - 4:
1068
+ if is_odd(dimensionNearestTail(leafPredecessor - is_odd(leafPredecessor))):
1069
+ pileFirst = (
1070
+ sumsOfProductsOfDimensionsNearest首InSubHyperplane[indexUniversal]
1071
+ + state.sumsOfProductsOfDimensions[2 + 1 + indexUniversal]
1072
+ - (pileStepAbsolute
1073
+ * 2
1074
+ * (howManyDimensionsHaveOddParity(leafPredecessor首零) - 1
1075
+ + is_even(leafPredecessor首零) * indexUniversal
1076
+ - is_even(leafPredecessor首零) * (int(not(bool(indexUniversal))))
1077
+ )
1078
+ )
1079
+ + state.productsOfDimensions[state.dimensionsTotal - 1
1080
+ + addend * (int(not(bool(indexUniversal))))
1081
+ - (indexUniversal + 2)]
1082
+ )
1083
+ for aPile in listOfPiles[listOfPiles.index(pileFirst) + indexUniversal: listOfPiles.index(neg(零)+首零(state.dimensionsTotal)) - indexUniversal + inclusive]:
1084
+ dictionaryPrecedence[leaf][aPile].append(leafPredecessor首零)
1085
+
1086
+ del leaf, listOfPiles, sumsOfProductsOfDimensionsNearest首, pileStepAbsolute, sumsOfProductsOfDimensionsNearest首InSubHyperplane
1087
+
1088
+ #======== leaf首零Plus零: Separate logic because the distance between absolute piles is 4, not 2 ==============
1089
+ # leaf has conditional `leafPredecessor` in all but the first pile of its domain
1090
+ # Reminder: has UNconditional `leafPredecessor` in the first pile: leaf零
1091
+ leaf: Leaf = (零)+首零(state.dimensionsTotal)
1092
+ listOfPiles: list[Pile] = list(dictionaryDomains[leaf])[1: None]
1093
+ dictionaryPrecedence[leaf] = {aPile: [] for aPile in listOfPiles}
1094
+ sumsOfProductsOfDimensionsNearest首: tuple[int, ...] = getSumsOfProductsOfDimensionsNearest首(state.productsOfDimensions)
1095
+ pileStepAbsolute = 4
1096
+ for indexUniversal in range(state.dimensionsTotal - 2):
1097
+ leafPredecessorTheFirst: int = state.sumsOfProductsOfDimensions[indexUniversal + 2]
1098
+ leavesPredecessorInThisSeries = state.productsOfDimensions[howManyDimensionsHaveOddParity(leafPredecessorTheFirst)]
1099
+ for addend in range(leavesPredecessorInThisSeries):
1100
+ leafPredecessor: int = leafPredecessorTheFirst + (addend * decreasing)
1101
+ leafPredecessor首零: int = leafPredecessor + 首零(state.dimensionsTotal)
1102
+ pileFirst = sumsOfProductsOfDimensionsNearest首[indexUniversal] + 6 - (pileStepAbsolute * (howManyDimensionsHaveOddParity(leafPredecessor) - 1 + is_even(leafPredecessor)))
1103
+ for aPile in listOfPiles[listOfPiles.index(pileFirst): None]:
1104
+ dictionaryPrecedence[leaf][aPile].append(leafPredecessor)
1105
+ dictionaryPrecedence[leaf][aPile].append(leafPredecessor首零)
1106
+
1107
+ del leaf, listOfPiles, sumsOfProductsOfDimensionsNearest首, pileStepAbsolute
1108
+
1109
+ #======== piles at the end of the leaf's domain ================
1110
+ #-------- Example of special case: has conditional `leafPredecessor` two steps before the end of the domain --------------------------
1111
+ if state.dimensionsTotal == 6:
1112
+ leaf = 22
1113
+ sliceOfPiles = slice(0, None)
1114
+ listOfPiles = list(dictionaryDomains[leaf])[sliceOfPiles]
1115
+ leafPredecessorPileFirstPileLast = [(15, 43, 43)]
1116
+ for leafPredecessor, pileFirst, pileLast in leafPredecessorPileFirstPileLast:
1117
+ for pile in listOfPiles[listOfPiles.index(pileFirst): listOfPiles.index(pileLast) + inclusive]:
1118
+ dictionaryPrecedence[leaf].setdefault(pile, []).append(leafPredecessor)
1119
+
1120
+ # NOTE Some leaves, such as 16,48, have `leafPredecessor`, such as leaves 40 and 56, with a larger step size.
1121
+ # NOTE There may be "knock-out" leaves, such as within the domain functions, above. Or I might have to find complex formulas, such
1122
+ # as in `pinPile二Crease`. Or, more likely, "knock-out" leaves might be complex formulas that I have not yet discovered.
1123
+
1124
+ return dictionaryPrecedence
1125
+
1126
+ # TODO Implement and use getDictionaryConditionalLeafSuccessors
1127
+ def getDictionaryConditionalLeafSuccessors(state: EliminationState) -> dict[Leaf, dict[Pile, list[Leaf]]]:
1128
+ """leaf: pile: [conditional `leafSuccessor`]."""
1129
+ return _getDictionaryConditionalLeafSuccessors(state.mapShape)
1130
+ @cache
1131
+ def _getDictionaryConditionalLeafSuccessors(mapShape: tuple[int, ...]) -> dict[Leaf, dict[Pile, list[Leaf]]]:
1132
+ state = EliminationState(mapShape)
1133
+ dictionaryDomains: dict[Leaf, range] = getDictionaryLeafDomains(state)
1134
+
1135
+ dictionarySuccessor: dict[Leaf, dict[Pile, list[Leaf]]] = {}
1136
+
1137
+ dictionaryPrecedence: dict[Leaf, dict[Pile, list[Leaf]]] = getDictionaryConditionalLeafPredecessors(state)
1138
+
1139
+ for leafLater, dictionaryPiles in dictionaryPrecedence.items():
1140
+ tupleDomainLater: tuple[Pile, ...] = tuple(dictionaryDomains[leafLater])
1141
+ dictionaryPilesByPredecessor: defaultdict[Leaf, set[Pile]] = defaultdict(set)
1142
+ for pileLater, listLeafPredecessors in dictionaryPiles.items():
1143
+ for leafEarlier in listLeafPredecessors:
1144
+ dictionaryPilesByPredecessor[leafEarlier].add(pileLater)
1145
+
1146
+ for leafEarlier, setPilesRequiring in dictionaryPilesByPredecessor.items():
1147
+ tupleDomainEarlier: tuple[Pile, ...] = tuple(dictionaryDomains[leafEarlier])
1148
+ listOptionalPiles: list[Pile] = sorted(pile for pile in tupleDomainLater if pile not in setPilesRequiring)
1149
+ for pileEarlier in tupleDomainEarlier:
1150
+ optionalLessEqualCount: int = bisect_right(listOptionalPiles, pileEarlier)
1151
+ if optionalLessEqualCount == 0:
1152
+ listSuccessors: list[Leaf] = dictionarySuccessor.setdefault(leafEarlier, {}).setdefault(pileEarlier, [])
1153
+ if leafLater not in listSuccessors:
1154
+ listSuccessors.append(leafLater)
1155
+
1156
+ return dictionarySuccessor
1157
+
1158
+ # TODO Creation of `permutationSpace2上nDomainDefaults` could possibly be a function. To future proof the performance, I probably want to cache `permutationSpace2上nDomainDefaults`.
1159
+ def addPileRangesOfLeaves(state: EliminationState) -> EliminationState:
1160
+ permutationSpace2上nDomainDefaults: PermutationSpace = {pile: raiseIfNone(JeanValjean(getPileRangeOfLeaves(state.leavesTotal, pileRangeOfLeaves)))
1161
+ for pile, pileRangeOfLeaves in getDictionaryPileRanges(state).items()}
1162
+ state.permutationSpace = merge(permutationSpace2上nDomainDefaults, state.permutationSpace)
1163
+ return state
1164
+