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,551 @@
1
+ # ruff: noqa: ERA001
2
+ from collections import Counter, deque
3
+ from cytoolz.dicttoolz import get_in, keyfilter, valfilter
4
+ from cytoolz.functoolz import complement, curry as syntacticCurry
5
+ from functools import cache
6
+ from gmpy2 import bit_flip, bit_test as isBit1吗
7
+ from hunterMakesPy import raiseIfNone
8
+ from itertools import chain, combinations, product as CartesianProduct
9
+ from mapFolding import inclusive
10
+ from mapFolding._e import (
11
+ bifurcatePermutationSpace, DimensionIndex, dimensionNearestTail, dimensionNearest首, DOTitems, DOTkeys, DOTvalues,
12
+ getAntiPileRangeOfLeaves, getDictionaryConditionalLeafPredecessors, getIteratorOfLeaves, getLeafDomain,
13
+ getLeavesCreaseAnte, getLeavesCreasePost, JeanValjean, Leaf, LeafOrPileRangeOfLeaves, mapShapeIs2上nDimensions,
14
+ PermutationSpace, Pile, PileRangeOfLeaves, pileRangeOfLeavesAND, PinnedLeaves, reverseLookup, 一, 零, 首一, 首零一)
15
+ from mapFolding._e.algorithms.iff import thisIsAViolation
16
+ from mapFolding._e.dataBaskets import EliminationState
17
+ from mapFolding._e.filters import (
18
+ between, extractPilesWithPileRangeOfLeaves, extractPinnedLeaves, leafIsInPileRange, leafIsPinned, mappingHasKey,
19
+ notLeafOriginOrLeaf零, notPileLast, thisHasThat, thisIsALeaf, thisIsAPileRangeOfLeaves)
20
+ from mapFolding._e.pinIt import atPilePinLeaf, disqualifyAppendingLeafAtPile
21
+ from more_itertools import (
22
+ filter_map, ilen as lenIterator, one, pairwise, partition as more_itertools_partition, split_at, triplewise)
23
+ from typing import TYPE_CHECKING
24
+
25
+ if TYPE_CHECKING:
26
+ from collections.abc import Iterable, Iterator
27
+
28
+ #======== Boolean filters ======================================
29
+
30
+ @syntacticCurry
31
+ def leafIsOddInDimension(leaf: Leaf, dimension: int) -> bool:
32
+ return isBit1吗(leaf, dimension)
33
+
34
+ #======== Reducing `PileRangeOfLeaves` =======
35
+
36
+ # TODO implement - The signs of the magnitudes alternate: if the difference between two leaves is 2, for example, then before there can be another difference of 2, there must be a difference of -2.
37
+ # TODO implement - Because `state.leavesTotal // 2` always has one more than `- state.leavesTotal // 2`, the first and last differences with magnitude `state.leavesTotal // 2` are positive.
38
+ # TODO implement The running total of the differences does not repeat in a Folding.
39
+ def reduceAllPermutationSpaceInEliminationState(state: EliminationState) -> EliminationState:
40
+ """Flow control to apply per-`PermutationSpace` functions to all of `state.listPermutationSpace`."""
41
+ listPermutationSpace: list[PermutationSpace] = state.listPermutationSpace
42
+ state.listPermutationSpace = []
43
+ state.listPermutationSpace.extend(filter_map(_reducePermutationSpace_byCrease(state), listPermutationSpace))
44
+
45
+ listPermutationSpace: list[PermutationSpace] = state.listPermutationSpace
46
+ state.listPermutationSpace = []
47
+ state.listPermutationSpace.extend(filter_map(_reducePermutationSpace_LeafIsPinned(state), listPermutationSpace))
48
+
49
+ listPermutationSpace: list[PermutationSpace] = state.listPermutationSpace
50
+ state.listPermutationSpace = []
51
+ state.listPermutationSpace.extend(filter_map(_reducePermutationSpace_HeadsBeforeTails(state), listPermutationSpace))
52
+
53
+ listPermutationSpace: list[PermutationSpace] = state.listPermutationSpace
54
+ state.listPermutationSpace = []
55
+ state.listPermutationSpace.extend(filter_map(_reducePermutationSpace_ConditionalPredecessors(state), listPermutationSpace))
56
+
57
+ listPermutationSpace: list[PermutationSpace] = state.listPermutationSpace
58
+ state.listPermutationSpace = []
59
+ state.listPermutationSpace.extend(filter_map(_reducePermutationSpace_CrossedCreases(state), listPermutationSpace))
60
+
61
+ listPermutationSpace: list[PermutationSpace] = state.listPermutationSpace
62
+ state.listPermutationSpace = []
63
+ state.listPermutationSpace.extend(filter_map(_reducePermutationSpace_noConsecutiveDimensions(state), listPermutationSpace))
64
+
65
+ listPermutationSpace: list[PermutationSpace] = state.listPermutationSpace
66
+ state.listPermutationSpace = []
67
+ state.listPermutationSpace.extend(filter_map(_reducePermutationSpace_leafDomainIs1(state), listPermutationSpace))
68
+
69
+ return state
70
+
71
+ #-------- Shared logic -----------------------------------------
72
+ def _reducePileRangesOfLeaves(state: EliminationState, permutationSpace: PermutationSpace, pilesToUpdate: deque[tuple[Pile, PileRangeOfLeaves]], antiPileRangeOfLeaves: PileRangeOfLeaves) -> PermutationSpace:
73
+ """You can use this function to reduce `PileRangeOfLeaves` values in `permutationSpace` and propagate newly pinned `Leaf`.
74
+
75
+ (AI generated docstring)
76
+
77
+ This function updates each `pile: pileRangeOfLeaves` pair from `pilesToUpdate` by intersecting
78
+ `pileRangeOfLeaves` with `antiPileRangeOfLeaves` using `pileRangeOfLeavesAND`.
79
+
80
+ This function converts an updated `PileRangeOfLeaves` to a `Leaf` using `JeanValjean` when the
81
+ intersection contains exactly one `leaf`. If the intersection is empty, `JeanValjean` returns `None`,
82
+ and this function returns `{}` to signal that `permutationSpace` is invalid.
83
+
84
+ When a new `Leaf` becomes pinned, this function applies the "beans without cornbread" rule by
85
+ pinning the complementary adjacent `Leaf` via a local subroutine. This function then calls
86
+ `_reducePermutationSpace_LeafIsPinned` to propagate the new `Leaf` to all other piles.
87
+
88
+ Parameters
89
+ ----------
90
+ state : EliminationState
91
+ A data basket that provides `state.mapShape` for constructing follow-on `EliminationState` values.
92
+ permutationSpace : PermutationSpace
93
+ A dictionary of `pile: leaf` and/or `pile: pileRangeOfLeaves`.
94
+ pilesToUpdate : deque[tuple[Pile, PileRangeOfLeaves]]
95
+ A LIFO work list of `pile` and `pileRangeOfLeaves` pairs that must be reduced.
96
+ antiPileRangeOfLeaves : PileRangeOfLeaves
97
+ A `PileRangeOfLeaves` mask applied to each `pileRangeOfLeaves` using `pileRangeOfLeavesAND`.
98
+
99
+ Returns
100
+ -------
101
+ updatedPermutationSpace : PermutationSpace
102
+ An updated `permutationSpace` when reduction succeeds.
103
+ An empty dictionary `{}` when reduction invalidates `permutationSpace`.
104
+
105
+ References
106
+ ----------
107
+ [1] mapFolding._e.pileRangeOfLeavesAND
108
+ Internal package reference.
109
+ [2] mapFolding._e.JeanValjean
110
+ Internal package reference.
111
+ [3] mapFolding._e.filters.thisIsALeaf
112
+ Internal package reference.
113
+ [4] mapFolding._e.pin2上nDimensionsAnnex._reducePermutationSpace_LeafIsPinned
114
+ Internal package reference.
115
+
116
+ """
117
+ def pinLeafCornbread(state: EliminationState) -> EliminationState:
118
+ leafBeans: Leaf | None = None
119
+ for beans, cornbread in ((一+零, 一), (首一(state.dimensionsTotal), 首零一(state.dimensionsTotal))):
120
+ beansPinned: bool = leafIsPinned(state.permutationSpace, beans)
121
+ cornbreadPinned: bool = leafIsPinned(state.permutationSpace, cornbread)
122
+ if beansPinned ^ cornbreadPinned:
123
+ leafBeans = beans if beansPinned else cornbread
124
+ break
125
+
126
+ if leafBeans is None:
127
+ return state
128
+
129
+ state.pile = raiseIfNone(reverseLookup(state.permutationSpace, leafBeans))
130
+ if leafBeans in [一+零, 首一(state.dimensionsTotal)]:
131
+ state.pile += 1
132
+ leafCornbread = one(getLeavesCreasePost(state, leafBeans))
133
+ else:
134
+ state.pile -= 1
135
+ leafCornbread = one(getLeavesCreaseAnte(state, leafBeans))
136
+
137
+ if disqualifyAppendingLeafAtPile(state, leafCornbread):
138
+ state.permutationSpace = {}
139
+ else:
140
+ state.permutationSpace = atPilePinLeaf(state.permutationSpace, state.pile, leafCornbread)
141
+
142
+ return state
143
+
144
+ permutationSpaceHasNewLeaf: bool = False
145
+ while pilesToUpdate and not permutationSpaceHasNewLeaf:
146
+ pile, pileRangeOfLeaves = pilesToUpdate.pop()
147
+ if (ImaLeafOrPileRangeOfLeavesNotAWalrusSubscript := JeanValjean(pileRangeOfLeavesAND(antiPileRangeOfLeaves, pileRangeOfLeaves))) is None:
148
+ return {}
149
+ # TODO These statements are syntactically necessary because I'm using subscripts AND walrus operators. Does that suggest there is
150
+ # a "better" flow paradigm, or is this merely a limitation of Python syntax?
151
+ permutationSpace[pile] = ImaLeafOrPileRangeOfLeavesNotAWalrusSubscript
152
+ if thisIsALeaf(permutationSpace[pile]):
153
+ stateCornbread = EliminationState(state.mapShape, pile=pile, permutationSpace=permutationSpace)
154
+ if not (permutationSpace := pinLeafCornbread(stateCornbread).permutationSpace):
155
+ return {}
156
+ permutationSpaceHasNewLeaf = True
157
+ if permutationSpaceHasNewLeaf:
158
+ sherpa: PermutationSpace | None = _reducePermutationSpace_LeafIsPinned(state, permutationSpace)
159
+ if not sherpa:
160
+ return {}
161
+ else:
162
+ permutationSpace = sherpa
163
+ return permutationSpace
164
+
165
+ @syntacticCurry
166
+ def _reducePermutationSpace_byCrease(state: EliminationState, permutationSpace: PermutationSpace) -> PermutationSpace | None:
167
+ permutationSpaceHasNewLeaf = True
168
+ while permutationSpaceHasNewLeaf:
169
+ permutationSpaceHasNewLeaf = False
170
+
171
+ dequePileLeafOrPileRangeOfLeavesPileLeafOrPileRangeOfLeaves: deque[tuple[tuple[Pile, LeafOrPileRangeOfLeaves], tuple[Pile, LeafOrPileRangeOfLeaves]]] = deque(pairwise(sorted(permutationSpace.items())))
172
+ while dequePileLeafOrPileRangeOfLeavesPileLeafOrPileRangeOfLeaves and not permutationSpaceHasNewLeaf:
173
+ (pile_k, leafOrPileRangeOfLeaves_k), (pile_r, leafOrPileRangeOfLeaves_r) = dequePileLeafOrPileRangeOfLeavesPileLeafOrPileRangeOfLeaves.pop()
174
+
175
+ antiPileRangeOfLeaves: PileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, frozenset())
176
+ leavesCrease: Iterator[Leaf] = iter(())
177
+ pilesToUpdate: deque[tuple[Pile, PileRangeOfLeaves]] = deque()
178
+
179
+ if thisIsALeaf(leafOrPileRangeOfLeaves_k) and thisIsAPileRangeOfLeaves(leafOrPileRangeOfLeaves_r):
180
+ pilesToUpdate = deque([(pile_r, leafOrPileRangeOfLeaves_r)])
181
+ leavesCrease = getLeavesCreasePost(state, leafOrPileRangeOfLeaves_k)
182
+ elif thisIsAPileRangeOfLeaves(leafOrPileRangeOfLeaves_k) and thisIsALeaf(leafOrPileRangeOfLeaves_r):
183
+ pilesToUpdate = deque([(pile_k, leafOrPileRangeOfLeaves_k)])
184
+ leavesCrease = getLeavesCreaseAnte(state, leafOrPileRangeOfLeaves_r)
185
+ else:
186
+ continue
187
+
188
+ antiPileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, set(range(state.leavesTotal)).difference(leavesCrease))
189
+
190
+ sumChecksForNewLeaves: int = sum(map(dimensionNearest首, permutationSpace.values()))
191
+ if not (permutationSpace := _reducePileRangesOfLeaves(state, permutationSpace, pilesToUpdate, antiPileRangeOfLeaves)):
192
+ return None
193
+ if sum(map(dimensionNearest首, permutationSpace.values())) < sumChecksForNewLeaves:
194
+ permutationSpaceHasNewLeaf = True
195
+
196
+ return permutationSpace
197
+
198
+ @syntacticCurry
199
+ def _reducePermutationSpace_ConditionalPredecessors(state: EliminationState, permutationSpace: PermutationSpace) -> PermutationSpace | None:
200
+ if not mapShapeIs2上nDimensions(state.mapShape, youMustBeDimensionsTallToPinThis=6):
201
+ return permutationSpace
202
+
203
+ dictionaryConditionalLeafPredecessors: dict[Leaf, dict[Pile, list[Leaf]]] = getDictionaryConditionalLeafPredecessors(state)
204
+
205
+ permutationSpaceHasNewLeaf: bool = True
206
+ while permutationSpaceHasNewLeaf:
207
+ permutationSpaceHasNewLeaf = False
208
+
209
+ dequePileLeaf: deque[tuple[Pile, Leaf]] = deque(sorted(DOTitems(valfilter(mappingHasKey(dictionaryConditionalLeafPredecessors),
210
+ keyfilter(notPileLast(state.pileLast), valfilter(notLeafOriginOrLeaf零, extractPinnedLeaves(permutationSpace)))))))
211
+
212
+ while dequePileLeaf and not permutationSpaceHasNewLeaf:
213
+ pile, leaf = dequePileLeaf.pop()
214
+
215
+ if mappingHasKey(dictionaryConditionalLeafPredecessors[leaf], pile):
216
+ # For this `pile:leaf` in `permutationSpace`, `dictionaryConditionalLeafPredecessors` has a `list` of at least one
217
+ # `leaf` that must precede this `pile:leaf`, so the `list` cannot follow this `pile:leaf`, so remove the `list`
218
+ # from the `PileRangeOfLeaves` at piles after `pile`.
219
+ antiPileRangeOfLeaves: PileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, dictionaryConditionalLeafPredecessors[leaf][pile])
220
+
221
+ pilesToUpdate: deque[tuple[Pile, PileRangeOfLeaves]] = deque(DOTitems(extractPilesWithPileRangeOfLeaves(keyfilter(between(pile + inclusive, state.pileLast), permutationSpace))))
222
+
223
+ sumChecksForNewLeaves: int = sum(map(dimensionNearest首, permutationSpace.values()))
224
+ if not (permutationSpace := _reducePileRangesOfLeaves(state, permutationSpace, pilesToUpdate, antiPileRangeOfLeaves)):
225
+ return None
226
+ if sum(map(dimensionNearest首, permutationSpace.values())) < sumChecksForNewLeaves:
227
+ permutationSpaceHasNewLeaf = True
228
+
229
+ return permutationSpace
230
+
231
+ @syntacticCurry
232
+ def _reducePermutationSpace_CrossedCreases(state: EliminationState, permutationSpace: PermutationSpace) -> PermutationSpace | None:
233
+ permutationSpaceHasNewLeaf = True
234
+ while permutationSpaceHasNewLeaf:
235
+ permutationSpaceHasNewLeaf = False
236
+ for dimension in range(state.dimensionsTotal):
237
+
238
+ dictionaryLeafToPile: dict[Leaf, Pile] = {leafValue: pileKey for pileKey, leafValue in extractPinnedLeaves(permutationSpace).items()}
239
+
240
+ # For efficiency, I wish I could create the two dictionaries with one operation and without the intermediate `leavesPinned`.
241
+ leavesPinned: PinnedLeaves = extractPinnedLeaves(permutationSpace)
242
+ leavesPinnedEvenInDimension: PinnedLeaves = valfilter(complement(leafIsOddInDimension(dimension=dimension)), leavesPinned)
243
+ leavesPinnedOddInDimension: PinnedLeaves = valfilter(leafIsOddInDimension(dimension=dimension), leavesPinned)
244
+
245
+ dequePileLeafPileLeaf: deque[tuple[PinnedLeaves, tuple[tuple[Pile, Leaf], tuple[Pile, Leaf]]]] = deque(
246
+ CartesianProduct((leavesPinnedOddInDimension,), combinations(leavesPinnedEvenInDimension.items(), 2)))
247
+ dequePileLeafPileLeaf.extend(deque(CartesianProduct((leavesPinnedEvenInDimension,), combinations(leavesPinnedOddInDimension.items(), 2))))
248
+
249
+ while dequePileLeafPileLeaf and not permutationSpaceHasNewLeaf:
250
+ leavesPinnedParityOpposite, ((pileOf_k, leaf_k), (pileOf_r, leaf_r)) = dequePileLeafPileLeaf.pop()
251
+ leaf_kCrease: Leaf = int(bit_flip(leaf_k, dimension))
252
+ leaf_rCrease: Leaf = int(bit_flip(leaf_r, dimension))
253
+ pileOf_kCrease: Pile = 31212012
254
+ pileOf_rCrease: Pile = 31212012
255
+
256
+ if (leaf_kCreaseIsPinned := leafIsPinned(leavesPinnedParityOpposite, leaf_kCrease)):
257
+ pileOf_kCrease = dictionaryLeafToPile[leaf_kCrease]
258
+ if (leaf_rCreaseIsPinned := leafIsPinned(leavesPinnedParityOpposite, leaf_rCrease)):
259
+ pileOf_rCrease = dictionaryLeafToPile[leaf_rCrease]
260
+
261
+ pilesForbidden: Iterable[Pile] = []
262
+ antiPileRangeOfLeaves: PileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, frozenset())
263
+
264
+ if leaf_kCreaseIsPinned and not leaf_rCreaseIsPinned:
265
+ antiPileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, (leaf_rCrease,))
266
+
267
+ if pileOf_k < pileOf_r < pileOf_kCrease:
268
+ pilesForbidden = frozenset([*range(pileOf_k), *range(pileOf_kCrease + 1, state.pileLast + inclusive)])
269
+ elif pileOf_kCrease < pileOf_r < pileOf_k:
270
+ pilesForbidden = frozenset([*range(pileOf_kCrease), *range(pileOf_k + 1, state.pileLast + inclusive)])
271
+ elif (pileOf_r < pileOf_kCrease < pileOf_k) or (pileOf_kCrease < pileOf_k < pileOf_r):
272
+ pilesForbidden = frozenset(range(pileOf_kCrease + 1, pileOf_k))
273
+ elif (pileOf_r < pileOf_k < pileOf_kCrease) or (pileOf_k < pileOf_kCrease < pileOf_r):
274
+ pilesForbidden = frozenset(range(pileOf_k + 1, pileOf_kCrease))
275
+
276
+ elif not leaf_kCreaseIsPinned and leaf_rCreaseIsPinned:
277
+ antiPileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, (leaf_kCrease,))
278
+
279
+ if pileOf_rCrease < pileOf_k < pileOf_r:
280
+ pilesForbidden = frozenset([*range(pileOf_rCrease), *range(pileOf_r + 1, state.pileLast + inclusive)])
281
+ elif pileOf_r < pileOf_k < pileOf_rCrease:
282
+ pilesForbidden = frozenset([*range(pileOf_r), *range(pileOf_rCrease + 1, state.pileLast + inclusive)])
283
+ elif (pileOf_k < pileOf_r < pileOf_rCrease) or (pileOf_r < pileOf_rCrease < pileOf_k):
284
+ pilesForbidden = frozenset(range(pileOf_r + 1, pileOf_rCrease))
285
+ elif (pileOf_k < pileOf_rCrease < pileOf_r) or (pileOf_rCrease < pileOf_r < pileOf_k):
286
+ pilesForbidden = frozenset(range(pileOf_rCrease + 1, pileOf_r))
287
+
288
+ elif leaf_kCreaseIsPinned and leaf_rCreaseIsPinned:
289
+ if thisIsAViolation(pileOf_k, pileOf_r, pileOf_kCrease, pileOf_rCrease):
290
+ return None
291
+
292
+ elif not leaf_kCreaseIsPinned and not leaf_rCreaseIsPinned:
293
+ # case leaves: leaf_k, leaf_r
294
+ # I don't think I have enough information to do anything.
295
+ pass
296
+
297
+ pilesToUpdate: deque[tuple[Pile, PileRangeOfLeaves]] = deque(DOTitems(keyfilter(thisHasThat(pilesForbidden), extractPilesWithPileRangeOfLeaves(permutationSpace))))
298
+
299
+ sumChecksForNewLeaves: int = sum(map(dimensionNearest首, permutationSpace.values()))
300
+ if not (permutationSpace := _reducePileRangesOfLeaves(state, permutationSpace, pilesToUpdate, antiPileRangeOfLeaves)):
301
+ return None
302
+ if sum(map(dimensionNearest首, permutationSpace.values())) < sumChecksForNewLeaves:
303
+ permutationSpaceHasNewLeaf = True
304
+
305
+ return permutationSpace
306
+
307
+ @syntacticCurry
308
+ def _reducePermutationSpace_HeadsBeforeTails(state: EliminationState, permutationSpace: PermutationSpace) -> PermutationSpace | None:
309
+ permutationSpaceHasNewLeaf: bool = True
310
+ while permutationSpaceHasNewLeaf:
311
+ permutationSpaceHasNewLeaf = False
312
+ dequePileLeaf: deque[tuple[Pile, Leaf]] = deque(sorted(DOTitems(keyfilter(notPileLast(state.pileLast), valfilter(notLeafOriginOrLeaf零, extractPinnedLeaves(permutationSpace))))))
313
+ while dequePileLeaf and not permutationSpaceHasNewLeaf:
314
+ pile, leaf = dequePileLeaf.pop()
315
+ dimensionTail: int = dimensionNearestTail(leaf)
316
+ dimensionHead: int = dimensionNearest首(leaf)
317
+ if 0 < dimensionHead:
318
+ leavesForbidden = range(state.productsOfDimensions[dimensionHead], state.leavesTotal, state.productsOfDimensions[dimensionHead])
319
+ floor: Pile = 2
320
+ ceiling: Pile = pile - inclusive
321
+
322
+ antiPileRangeOfLeaves: PileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, leavesForbidden)
323
+ pilesToUpdate: deque[tuple[Pile, PileRangeOfLeaves]] = deque(extractPilesWithPileRangeOfLeaves(keyfilter(between(floor, ceiling), permutationSpace)).items())
324
+
325
+ sumChecksForNewLeaves: int = sum(map(dimensionNearest首, permutationSpace.values()))
326
+ if not (permutationSpace := _reducePileRangesOfLeaves(state, permutationSpace, pilesToUpdate, antiPileRangeOfLeaves)):
327
+ return None
328
+ if sum(map(dimensionNearest首, permutationSpace.values())) < sumChecksForNewLeaves:
329
+ permutationSpaceHasNewLeaf = True
330
+
331
+ if 0 < dimensionTail:
332
+ leavesForbidden = range(0, state.sumsOfProductsOfDimensions[dimensionTail], 1)
333
+ floor: Pile = pile + inclusive
334
+ ceiling: Pile = state.pileLast
335
+
336
+ antiPileRangeOfLeaves: PileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, leavesForbidden)
337
+ pilesToUpdate: deque[tuple[Pile, PileRangeOfLeaves]] = deque(extractPilesWithPileRangeOfLeaves(keyfilter(between(floor, ceiling), permutationSpace)).items())
338
+
339
+ sumChecksForNewLeaves = sum(map(dimensionNearest首, permutationSpace.values()))
340
+ if not (permutationSpace := _reducePileRangesOfLeaves(state, permutationSpace, pilesToUpdate, antiPileRangeOfLeaves)):
341
+ return None
342
+ if sum(map(dimensionNearest首, permutationSpace.values())) < sumChecksForNewLeaves:
343
+ permutationSpaceHasNewLeaf = True
344
+
345
+ return permutationSpace
346
+
347
+ @syntacticCurry
348
+ def _reducePermutationSpace_leafDomainIs1(state: EliminationState, permutationSpace: PermutationSpace) -> PermutationSpace | None:
349
+ permutationSpaceHasNewLeaf: bool = True
350
+ while permutationSpaceHasNewLeaf:
351
+ permutationSpaceHasNewLeaf = False
352
+
353
+ leavesPinned, pilesWithPileRangeOfLeaves = bifurcatePermutationSpace(permutationSpace)
354
+
355
+ leafAndItsDomainSize: Counter[Leaf] = Counter(chain(
356
+ chain.from_iterable(map(getIteratorOfLeaves, DOTvalues(pilesWithPileRangeOfLeaves))),
357
+ DOTvalues(leavesPinned)
358
+ ))
359
+
360
+ if set(range(state.leavesTotal)).difference(leafAndItsDomainSize.keys()):
361
+ return None
362
+
363
+ leavesWithDomainOf1: set[Leaf] = set(DOTkeys(valfilter((1).__eq__, leafAndItsDomainSize))).difference(leavesPinned.values()).difference([state.leavesTotal])
364
+ if leavesWithDomainOf1:
365
+ permutationSpaceHasNewLeaf = True
366
+ leaf: Leaf = leavesWithDomainOf1.pop()
367
+ pile: Pile = one(DOTkeys(valfilter(leafIsInPileRange(leaf), pilesWithPileRangeOfLeaves)))
368
+ sherpa: PermutationSpace | None = _reducePermutationSpace_LeafIsPinned(state, atPilePinLeaf(permutationSpace, pile, leaf))
369
+ if (sherpa is None) or (not sherpa):
370
+ return None
371
+ else:
372
+ permutationSpace = sherpa
373
+ return permutationSpace
374
+
375
+ @syntacticCurry
376
+ def _reducePermutationSpace_LeafIsPinned(state: EliminationState, permutationSpace: PermutationSpace) -> PermutationSpace | None:
377
+ """Update or invalidate `permutationSpace`: for every `leaf` pinned at a `pile`, remove `leaf` from `PileRangeOfLeaves` from every other `pile`; or return `None` if the updated `permutationSpace` is invalid.
378
+
379
+ If the `PileRangeOfLeaves` for a `pile` is reduced to one `leaf`, then convert from `pile: pileRangeOfLeaves` to `pile: leaf`.
380
+ If that results in "beans without cornbread", then pin the complementary "cornbread" `leaf` at the appropriate adjacent
381
+ `pile`.
382
+
383
+ Parameters
384
+ ----------
385
+ state : EliminationState
386
+ A data basket to facilitate computations and actions.
387
+ permutationSpace : PermutationSpace
388
+ A dictionary of `pile: leaf` and/or `pile: pileRangeOfLeaves`.
389
+
390
+ Returns
391
+ -------
392
+ updatedPermutationSpace : PermutationSpace | None
393
+ An updated `permutationSpace` if valid; otherwise `None`.
394
+
395
+ """
396
+ permutationSpaceHasNewLeaf: bool = True
397
+
398
+ while permutationSpaceHasNewLeaf:
399
+ permutationSpaceHasNewLeaf = False
400
+
401
+ leavesPinned, pilesWithPileRangeOfLeaves = bifurcatePermutationSpace(permutationSpace)
402
+
403
+ antiPileRangeOfLeaves: PileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, DOTvalues(leavesPinned))
404
+
405
+ pilesToUpdate: deque[tuple[Pile, PileRangeOfLeaves]] = deque(pilesWithPileRangeOfLeaves.items())
406
+
407
+ sumChecksForNewLeaves: int = sum(map(dimensionNearest首, permutationSpace.values()))
408
+ if not (permutationSpace := _reducePileRangesOfLeaves(state, permutationSpace, pilesToUpdate, antiPileRangeOfLeaves)):
409
+ return None
410
+ if sum(map(dimensionNearest首, permutationSpace.values())) < sumChecksForNewLeaves:
411
+ permutationSpaceHasNewLeaf = True
412
+
413
+ return permutationSpace
414
+
415
+ @syntacticCurry
416
+ def _reducePermutationSpace_noConsecutiveDimensions(state: EliminationState, permutationSpace: PermutationSpace) -> PermutationSpace | None:
417
+ # TODO Figure out a way to measure how often this function (or the other functions) actually reduces `permutationSpace`.
418
+ permutationSpaceHasNewLeaf = True
419
+ while permutationSpaceHasNewLeaf:
420
+ permutationSpaceHasNewLeaf = False
421
+
422
+ Z0Z_triple = deque(triplewise(sorted(permutationSpace.items())))
423
+ while Z0Z_triple and not permutationSpaceHasNewLeaf:
424
+ (pile_k, leafOrPileRangeOfLeaves_k), (pile_r, leafOrPileRangeOfLeaves_r), (pile_z, leafOrPileRangeOfLeaves_z) = Z0Z_triple.pop()
425
+
426
+ antiPileRangeOfLeaves: PileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, frozenset())
427
+ leafForbidden: Leaf = 0
428
+ pilesToUpdate: deque[tuple[Pile, PileRangeOfLeaves]] = deque()
429
+
430
+ if thisIsALeaf(leafOrPileRangeOfLeaves_k) and thisIsALeaf(leafOrPileRangeOfLeaves_r) and thisIsAPileRangeOfLeaves(leafOrPileRangeOfLeaves_z):
431
+ pilesToUpdate = deque([(pile_z, leafOrPileRangeOfLeaves_z)])
432
+ differenceOfLeaves: int = leafOrPileRangeOfLeaves_k - leafOrPileRangeOfLeaves_r
433
+ leafForbidden = leafOrPileRangeOfLeaves_r + differenceOfLeaves
434
+ elif thisIsALeaf(leafOrPileRangeOfLeaves_k) and thisIsAPileRangeOfLeaves(leafOrPileRangeOfLeaves_r) and thisIsALeaf(leafOrPileRangeOfLeaves_z):
435
+ pilesToUpdate = deque([(pile_r, leafOrPileRangeOfLeaves_r)])
436
+ leafForbidden = (leafOrPileRangeOfLeaves_k + leafOrPileRangeOfLeaves_z) // 2
437
+ elif thisIsAPileRangeOfLeaves(leafOrPileRangeOfLeaves_k) and thisIsALeaf(leafOrPileRangeOfLeaves_r) and thisIsALeaf(leafOrPileRangeOfLeaves_z):
438
+ pilesToUpdate = deque([(pile_k, leafOrPileRangeOfLeaves_k)])
439
+ differenceOfLeaves: int = leafOrPileRangeOfLeaves_r - leafOrPileRangeOfLeaves_z
440
+ leafForbidden = leafOrPileRangeOfLeaves_r - differenceOfLeaves
441
+ else:
442
+ continue
443
+
444
+ antiPileRangeOfLeaves = getAntiPileRangeOfLeaves(state.leavesTotal, [leafForbidden])
445
+
446
+ sumChecksForNewLeaves: int = sum(map(dimensionNearest首, permutationSpace.values()))
447
+ if not (permutationSpace := _reducePileRangesOfLeaves(state, permutationSpace, pilesToUpdate, antiPileRangeOfLeaves)):
448
+ return None
449
+ if sum(map(dimensionNearest首, permutationSpace.values())) < sumChecksForNewLeaves:
450
+ permutationSpaceHasNewLeaf = True
451
+
452
+ return permutationSpace
453
+
454
+ @syntacticCurry
455
+ # TODO Implement `sudoku` reduction: borrow ideas from `notEnoughOpenPiles`.
456
+ def sudoku(state: EliminationState, permutationSpace: PermutationSpace) -> PermutationSpace | None: # noqa: ARG001
457
+ """My implementation broke `eliminationCrease` and possibly other things.
458
+
459
+ Sudoku trick:
460
+ in a restricted space (square, row, or column), if two numbers have the same domain of two cells, then all other numbers are excluded from those two cells.
461
+ ^^^ generalizes to if n numbers have the same domain of n cells, all other numbers are excluded from that domain of n cells.
462
+ """
463
+ return permutationSpace
464
+ def notEnoughOpenPiles(state: EliminationState) -> bool:
465
+ """Decommissioned: implement with the sudoku trick.
466
+
467
+ Check `state.permutationSpace` for enough open piles for required leaves.
468
+
469
+ Some leaves must be before or after other leaves, such as the dimension origin leaves. For each pinned leaf, get all of the
470
+ required leaves for before and after, and check if there are enough open piles for all of them. If the set of open piles does
471
+ not intersect with the domain of a required leaf, return True. If a required leaf can only be pinned in one pile of the open
472
+ piles, pin it at that pile in stateOfOpenPiles. Use the real pinning functions with the disposable stateOfOpenPiles. With the required
473
+ leaves that are not pinned, check if there are enough open piles for them.
474
+ """
475
+ stateWorkbench = EliminationState(state.mapShape, pile=state.pile, permutationSpace=state.permutationSpace.copy())
476
+
477
+ dictionaryConditionalLeafPredecessors: dict[Leaf, dict[Pile, list[Leaf]]] = getDictionaryConditionalLeafPredecessors(state)
478
+
479
+ # DEVELOPMENT Reminder: I designed this function before `updateListPermutationSpace` AND BEFORE `PileRangeOfLeaves`. I'm not using
480
+ # `PileRangeOfLeaves` anywhere in this function, which seems odd. I should rethink the entire function. Actually, I should
481
+ # translate the broader concept--allocating limited piles to the leaves that must have them--into a subroutine of
482
+ # `updateListPermutationSpace`. And then eliminate this function.
483
+
484
+ # This general concept is the sudoku trick, right?
485
+
486
+ # DEVELOPMENT Flow control
487
+ permutationSpaceHasNewLeaf: bool = True
488
+ while permutationSpaceHasNewLeaf:
489
+ permutationSpaceHasNewLeaf = False
490
+
491
+ # DEVELOPMENT Too many intermediate variables. And/or the wrong variables. And/or the wrong functions.
492
+ leavesPinned, _pilesWithPileRangeOfLeaves = bifurcatePermutationSpace(stateWorkbench.permutationSpace)
493
+ leavesFixed: tuple[Leaf, ...] = tuple(DOTvalues(leavesPinned))
494
+ leavesNotPinned: frozenset[Leaf] = frozenset(range(stateWorkbench.leavesTotal)).difference(leavesFixed)
495
+ pilesOpen: frozenset[Pile] = frozenset(range(stateWorkbench.pileLast + inclusive)).difference(leavesPinned.keys())
496
+
497
+ dequePileLeaf: deque[tuple[Pile, Leaf]] = deque(sorted(DOTitems(keyfilter(notPileLast(state.pileLast), valfilter(notLeafOriginOrLeaf零, leavesPinned)))))
498
+
499
+ while dequePileLeaf and not permutationSpaceHasNewLeaf:
500
+ # DEVELOPMENT Iteration data
501
+ pile, leaf = dequePileLeaf.pop()
502
+ leavesFixedBeforePile, leavesFixedAfterPile = split_at(leavesFixed, leaf.__eq__, maxsplit=1)
503
+ pilesOpenAfterLeaf, pilesOpenBeforeLeaf = more_itertools_partition(pile.__lt__, pilesOpen)
504
+
505
+ @cache
506
+ def leaf_kMustPrecede_leaf吗(leaf_k: Leaf, leaf: Leaf = leaf, pile: Pile = pile) -> bool:
507
+ if dimensionNearest首(leaf_k) <= dimensionNearestTail(leaf):
508
+ return True
509
+ return leaf_k in get_in([leaf, pile], dictionaryConditionalLeafPredecessors, default=list[Leaf]())
510
+
511
+ dimensionHead: DimensionIndex = dimensionNearest首(leaf)
512
+ @cache
513
+ def leafMustPrecede_leaf_r吗(leaf_r: Leaf, dimensionHead: DimensionIndex = dimensionHead) -> bool:
514
+ return dimensionHead <= dimensionNearestTail(leaf_r)
515
+
516
+ if any(map(leaf_kMustPrecede_leaf吗, leavesFixedAfterPile)) or any(map(leafMustPrecede_leaf_r吗, leavesFixedBeforePile)):
517
+ return True
518
+
519
+ leavesMustPrecede_leaf: deque[Leaf] = deque(filter(leaf_kMustPrecede_leaf吗, leavesNotPinned))
520
+ leafMustPrecedeLeaves: deque[Leaf] = deque(filter(leafMustPrecede_leaf_r吗, leavesNotPinned))
521
+
522
+ if (lenIterator(pilesOpenBeforeLeaf) < lenIterator(leavesMustPrecede_leaf)) or (lenIterator(pilesOpenAfterLeaf) < lenIterator(leafMustPrecedeLeaves)):
523
+ return True
524
+
525
+ while leavesMustPrecede_leaf and not permutationSpaceHasNewLeaf:
526
+ # DEVELOPMENT Iteration data, nested
527
+ leaf_k: Leaf = leavesMustPrecede_leaf.pop()
528
+
529
+ domain_k = getLeafDomain(stateWorkbench, leaf_k)
530
+ pilesOpenFor_k: set[Pile] = set(pilesOpenBeforeLeaf).intersection(domain_k)
531
+
532
+ if len(pilesOpenFor_k) == 0:
533
+ return True
534
+ if len(pilesOpenFor_k) == 1:
535
+ stateWorkbench.permutationSpace = atPilePinLeaf(stateWorkbench.permutationSpace, pilesOpenFor_k.pop(), leaf_k)
536
+ permutationSpaceHasNewLeaf = True
537
+
538
+ while leafMustPrecedeLeaves and not permutationSpaceHasNewLeaf:
539
+ # DEVELOPMENT Iteration data, nested
540
+ leaf_r: Leaf = leafMustPrecedeLeaves.pop()
541
+
542
+ domain_r = getLeafDomain(stateWorkbench, leaf_r)
543
+ pilesOpenFor_r: set[int] = set(pilesOpenAfterLeaf).intersection(domain_r)
544
+
545
+ if len(pilesOpenFor_r) == 0:
546
+ return True
547
+ if len(pilesOpenFor_r) == 1:
548
+ stateWorkbench.permutationSpace = atPilePinLeaf(stateWorkbench.permutationSpace, pilesOpenFor_r.pop(), leaf_r)
549
+ permutationSpaceHasNewLeaf = True
550
+
551
+ return False