pystatistics 2.0.1__tar.gz → 2.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (544) hide show
  1. {pystatistics-2.0.1 → pystatistics-2.1.0}/CHANGELOG.md +213 -0
  2. {pystatistics-2.0.1 → pystatistics-2.1.0}/PKG-INFO +103 -1
  3. {pystatistics-2.0.1 → pystatistics-2.1.0}/README.md +102 -0
  4. pystatistics-2.1.0/benchmarks/mvnmle_bench.py +194 -0
  5. {pystatistics-2.0.1 → pystatistics-2.1.0}/pyproject.toml +1 -1
  6. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/__init__.py +1 -1
  7. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/__init__.py +14 -1
  8. pystatistics-2.1.0/pystatistics/mvnmle/_monotone.py +230 -0
  9. pystatistics-2.1.0/pystatistics/mvnmle/backends/_em_batched.py +795 -0
  10. pystatistics-2.1.0/pystatistics/mvnmle/backends/_squarem.py +235 -0
  11. pystatistics-2.1.0/pystatistics/mvnmle/backends/em.py +469 -0
  12. pystatistics-2.1.0/pystatistics/mvnmle/mcar_test.py +654 -0
  13. pystatistics-2.1.0/pystatistics/mvnmle/solvers.py +338 -0
  14. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/test_gpu.py +55 -0
  15. pystatistics-2.1.0/tests/mvnmle/test_mcar.py +123 -0
  16. pystatistics-2.1.0/tests/mvnmle/test_mom_mcar.py +169 -0
  17. pystatistics-2.1.0/tests/mvnmle/test_monotone.py +241 -0
  18. pystatistics-2.1.0/tests/mvnmle/test_no_silent_fallback.py +96 -0
  19. pystatistics-2.1.0/tests/mvnmle/test_squarem.py +120 -0
  20. pystatistics-2.0.1/pystatistics/mvnmle/backends/em.py +0 -330
  21. pystatistics-2.0.1/pystatistics/mvnmle/mcar_test.py +0 -228
  22. pystatistics-2.0.1/pystatistics/mvnmle/solvers.py +0 -195
  23. pystatistics-2.0.1/tests/mvnmle/test_no_silent_fallback.py +0 -55
  24. {pystatistics-2.0.1 → pystatistics-2.1.0}/.github/workflows/publish.yml +0 -0
  25. {pystatistics-2.0.1 → pystatistics-2.1.0}/.github/workflows/trigger-docs-rebuild.yml +0 -0
  26. {pystatistics-2.0.1 → pystatistics-2.1.0}/.gitignore +0 -0
  27. {pystatistics-2.0.1 → pystatistics-2.1.0}/.release/CHECKLIST.md +0 -0
  28. {pystatistics-2.0.1 → pystatistics-2.1.0}/.release/UNRELEASED.md +0 -0
  29. {pystatistics-2.0.1 → pystatistics-2.1.0}/.release/release.py +0 -0
  30. {pystatistics-2.0.1 → pystatistics-2.1.0}/CLAUDE.md +0 -0
  31. {pystatistics-2.0.1 → pystatistics-2.1.0}/LICENSE +0 -0
  32. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/DESIGN.md +0 -0
  33. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/Forge.md +0 -0
  34. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/GPU_BACKEND_NOTES.md +0 -0
  35. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/Makefile +0 -0
  36. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/PYSTATSBIO_CONTEXT.md +0 -0
  37. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/ROADMAP.md +0 -0
  38. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/_static/custom.css +0 -0
  39. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/anova.rst +0 -0
  40. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/conf.py +0 -0
  41. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/core.rst +0 -0
  42. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/descriptive.rst +0 -0
  43. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/hypothesis.rst +0 -0
  44. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/index.rst +0 -0
  45. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/mixed.rst +0 -0
  46. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/montecarlo.rst +0 -0
  47. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/mvnmle.rst +0 -0
  48. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/regression.rst +0 -0
  49. {pystatistics-2.0.1 → pystatistics-2.1.0}/docs/survival.rst +0 -0
  50. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/GPU_BACKEND_CONVENTION.md +0 -0
  51. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/__init__.py +0 -0
  52. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/_common.py +0 -0
  53. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/_contrasts.py +0 -0
  54. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/_levene.py +0 -0
  55. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/_posthoc.py +0 -0
  56. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/_repeated.py +0 -0
  57. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/_ss.py +0 -0
  58. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/design.py +0 -0
  59. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/solution.py +0 -0
  60. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/anova/solvers.py +0 -0
  61. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/__init__.py +0 -0
  62. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/capabilities.py +0 -0
  63. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/__init__.py +0 -0
  64. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/device.py +0 -0
  65. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/linalg/__init__.py +0 -0
  66. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/linalg/batched.py +0 -0
  67. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/linalg/cholesky.py +0 -0
  68. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/linalg/determinant.py +0 -0
  69. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/linalg/qr.py +0 -0
  70. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/linalg/solve.py +0 -0
  71. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/linalg/svd.py +0 -0
  72. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/optimization/__init__.py +0 -0
  73. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/optimization/convergence.py +0 -0
  74. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/precision.py +0 -0
  75. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/timing.py +0 -0
  76. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/compute/tolerances.py +0 -0
  77. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/datasource.py +0 -0
  78. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/exceptions.py +0 -0
  79. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/protocols.py +0 -0
  80. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/result.py +0 -0
  81. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/core/validation.py +0 -0
  82. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/__init__.py +0 -0
  83. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/_missing.py +0 -0
  84. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/_quantile_types.py +0 -0
  85. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/backends/__init__.py +0 -0
  86. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/backends/cpu.py +0 -0
  87. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/backends/gpu.py +0 -0
  88. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/design.py +0 -0
  89. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/solution.py +0 -0
  90. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/descriptive/solvers.py +0 -0
  91. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/__init__.py +0 -0
  92. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/_basis.py +0 -0
  93. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/_common.py +0 -0
  94. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/_fit.py +0 -0
  95. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/_gam.py +0 -0
  96. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/_gcv.py +0 -0
  97. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/_smooth.py +0 -0
  98. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/backends/__init__.py +0 -0
  99. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/backends/_gpu_family.py +0 -0
  100. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/backends/gpu_pirls.py +0 -0
  101. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/gam/solution.py +0 -0
  102. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/__init__.py +0 -0
  103. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/_common.py +0 -0
  104. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/_design_factories.py +0 -0
  105. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/_p_adjust.py +0 -0
  106. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/__init__.py +0 -0
  107. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/_chisq_test.py +0 -0
  108. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/_fisher_test.py +0 -0
  109. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/_ks_test.py +0 -0
  110. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/_prop_test.py +0 -0
  111. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/_t_test.py +0 -0
  112. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/_var_test.py +0 -0
  113. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/_wilcox_test.py +0 -0
  114. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/cpu.py +0 -0
  115. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/backends/gpu.py +0 -0
  116. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/design.py +0 -0
  117. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/solution.py +0 -0
  118. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/hypothesis/solvers.py +0 -0
  119. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/__init__.py +0 -0
  120. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/_common.py +0 -0
  121. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/_deviance.py +0 -0
  122. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/_pirls.py +0 -0
  123. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/_pls.py +0 -0
  124. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/_random_effects.py +0 -0
  125. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/_satterthwaite.py +0 -0
  126. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/design.py +0 -0
  127. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/solution.py +0 -0
  128. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mixed/solvers.py +0 -0
  129. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/__init__.py +0 -0
  130. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/_ci.py +0 -0
  131. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/_common.py +0 -0
  132. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/_influence.py +0 -0
  133. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/backends/__init__.py +0 -0
  134. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/backends/cpu.py +0 -0
  135. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/backends/gpu.py +0 -0
  136. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/design.py +0 -0
  137. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/solution.py +0 -0
  138. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/montecarlo/solvers.py +0 -0
  139. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multinomial/__init__.py +0 -0
  140. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multinomial/_common.py +0 -0
  141. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multinomial/_likelihood.py +0 -0
  142. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multinomial/_solver.py +0 -0
  143. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multinomial/backends/__init__.py +0 -0
  144. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multinomial/backends/gpu_likelihood.py +0 -0
  145. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multinomial/solution.py +0 -0
  146. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multivariate/__init__.py +0 -0
  147. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multivariate/_common.py +0 -0
  148. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multivariate/_factor.py +0 -0
  149. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multivariate/_pca.py +0 -0
  150. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multivariate/_rotation.py +0 -0
  151. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multivariate/backends/__init__.py +0 -0
  152. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/multivariate/backends/gpu_pca.py +0 -0
  153. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/_objectives/__init__.py +0 -0
  154. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/_objectives/base.py +0 -0
  155. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/_objectives/cpu.py +0 -0
  156. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/_objectives/gpu_fp32.py +0 -0
  157. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/_objectives/gpu_fp64.py +0 -0
  158. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/_objectives/parameterizations.py +0 -0
  159. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/_utils.py +0 -0
  160. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/backends/__init__.py +0 -0
  161. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/backends/cpu.py +0 -0
  162. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/backends/gpu.py +0 -0
  163. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/datasets.py +0 -0
  164. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/design.py +0 -0
  165. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/patterns.py +0 -0
  166. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/mvnmle/solution.py +0 -0
  167. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/ordinal/__init__.py +0 -0
  168. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/ordinal/_common.py +0 -0
  169. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/ordinal/_likelihood.py +0 -0
  170. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/ordinal/_solver.py +0 -0
  171. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/ordinal/backends/__init__.py +0 -0
  172. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/ordinal/backends/gpu_likelihood.py +0 -0
  173. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/ordinal/solution.py +0 -0
  174. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/py.typed +0 -0
  175. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/__init__.py +0 -0
  176. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/_formatting.py +0 -0
  177. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/_glm.py +0 -0
  178. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/_linear.py +0 -0
  179. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/_nb_theta.py +0 -0
  180. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/backends/__init__.py +0 -0
  181. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/backends/cpu.py +0 -0
  182. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/backends/cpu_glm.py +0 -0
  183. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/backends/gpu.py +0 -0
  184. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/backends/gpu_glm.py +0 -0
  185. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/design.py +0 -0
  186. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/families.py +0 -0
  187. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/solution.py +0 -0
  188. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/regression/solvers.py +0 -0
  189. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/__init__.py +0 -0
  190. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/_common.py +0 -0
  191. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/_cox.py +0 -0
  192. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/_discrete.py +0 -0
  193. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/_km.py +0 -0
  194. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/_logrank.py +0 -0
  195. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/backends/__init__.py +0 -0
  196. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/backends/cpu.py +0 -0
  197. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/backends/gpu.py +0 -0
  198. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/design.py +0 -0
  199. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/solution.py +0 -0
  200. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/survival/solvers.py +0 -0
  201. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/__init__.py +0 -0
  202. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_acf.py +0 -0
  203. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_arima_batch.py +0 -0
  204. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_arima_factored.py +0 -0
  205. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_arima_fit.py +0 -0
  206. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_arima_forecast.py +0 -0
  207. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_arima_kalman.py +0 -0
  208. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_arima_likelihood.py +0 -0
  209. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_arima_order.py +0 -0
  210. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_common.py +0 -0
  211. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_decomposition.py +0 -0
  212. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_differencing.py +0 -0
  213. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_ets_fit.py +0 -0
  214. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_ets_forecast.py +0 -0
  215. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_ets_models.py +0 -0
  216. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_stationarity.py +0 -0
  217. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/_whittle.py +0 -0
  218. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/backends/__init__.py +0 -0
  219. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/backends/whittle_batch_gpu.py +0 -0
  220. {pystatistics-2.0.1 → pystatistics-2.1.0}/pystatistics/timeseries/backends/whittle_gpu.py +0 -0
  221. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/__init__.py +0 -0
  222. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/conftest.py +0 -0
  223. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/test_contrasts.py +0 -0
  224. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/test_design.py +0 -0
  225. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/test_factorial.py +0 -0
  226. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/test_levene.py +0 -0
  227. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/test_oneway.py +0 -0
  228. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/test_posthoc.py +0 -0
  229. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/test_r_validation.py +0 -0
  230. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/anova/test_repeated_measures.py +0 -0
  231. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/benchmark_gpu.py +0 -0
  232. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/conftest.py +0 -0
  233. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/core/test_datasource.py +0 -0
  234. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/core/test_exceptions.py +0 -0
  235. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/core/test_result.py +0 -0
  236. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/core/test_validation.py +0 -0
  237. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/__init__.py +0 -0
  238. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/conftest.py +0 -0
  239. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/test_cor.py +0 -0
  240. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/test_cov.py +0 -0
  241. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/test_describe.py +0 -0
  242. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/test_gpu.py +0 -0
  243. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/test_missing.py +0 -0
  244. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/test_moments.py +0 -0
  245. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/test_quantile.py +0 -0
  246. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/descriptive/test_r_validation.py +0 -0
  247. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_ancova_meta.json +0 -0
  248. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_ancova_r_results.json +0 -0
  249. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_bonferroni_meta.json +0 -0
  250. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_bonferroni_r_results.json +0 -0
  251. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_eta_meta.json +0 -0
  252. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_eta_r_results.json +0 -0
  253. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_levene_meta.json +0 -0
  254. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_levene_r_results.json +0 -0
  255. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_oneway_balanced_meta.json +0 -0
  256. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_oneway_balanced_r_results.json +0 -0
  257. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_oneway_unbalanced_meta.json +0 -0
  258. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_oneway_unbalanced_r_results.json +0 -0
  259. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_rm_mixed_meta.json +0 -0
  260. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_rm_mixed_r_results.json +0 -0
  261. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_rm_within_meta.json +0 -0
  262. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_rm_within_r_results.json +0 -0
  263. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_tukey_meta.json +0 -0
  264. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_tukey_r_results.json +0 -0
  265. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_twoway_balanced_meta.json +0 -0
  266. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_twoway_balanced_r_results.json +0 -0
  267. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_twoway_unbalanced_meta.json +0 -0
  268. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/anova_twoway_unbalanced_r_results.json +0 -0
  269. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/basic_100x3.csv +0 -0
  270. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/basic_100x3_meta.json +0 -0
  271. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/basic_100x3_r_results.json +0 -0
  272. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/collinear_almost.csv +0 -0
  273. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/collinear_almost_meta.json +0 -0
  274. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/collinear_almost_r_results.json +0 -0
  275. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_basic_100x5.csv +0 -0
  276. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_basic_100x5_meta.json +0 -0
  277. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_basic_100x5_r_results.json +0 -0
  278. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_constant_column.csv +0 -0
  279. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_constant_column_meta.json +0 -0
  280. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_constant_column_r_results.json +0 -0
  281. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_extreme_values.csv +0 -0
  282. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_extreme_values_meta.json +0 -0
  283. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_extreme_values_r_results.json +0 -0
  284. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_large_1000x10.csv +0 -0
  285. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_large_1000x10_meta.json +0 -0
  286. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_large_1000x10_r_results.json +0 -0
  287. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_nan_columnwise.csv +0 -0
  288. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_nan_columnwise_meta.json +0 -0
  289. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_nan_columnwise_r_results.json +0 -0
  290. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_nan_scattered.csv +0 -0
  291. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_nan_scattered_meta.json +0 -0
  292. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_nan_scattered_r_results.json +0 -0
  293. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_negative_correlation.csv +0 -0
  294. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_negative_correlation_meta.json +0 -0
  295. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_negative_correlation_r_results.json +0 -0
  296. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_perfect_correlation.csv +0 -0
  297. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_perfect_correlation_meta.json +0 -0
  298. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_perfect_correlation_r_results.json +0 -0
  299. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_single_column.csv +0 -0
  300. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_single_column_meta.json +0 -0
  301. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_single_column_r_results.json +0 -0
  302. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_ties.csv +0 -0
  303. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_ties_meta.json +0 -0
  304. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/desc_ties_r_results.json +0 -0
  305. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/different_scales.csv +0 -0
  306. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/different_scales_meta.json +0 -0
  307. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/different_scales_r_results.json +0 -0
  308. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/generate_anova_fixtures.py +0 -0
  309. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/generate_descriptive_fixtures.py +0 -0
  310. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/generate_fixtures.py +0 -0
  311. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/generate_glm_fixtures.py +0 -0
  312. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/generate_hypothesis_fixtures.py +0 -0
  313. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/generate_mixed_fixtures.py +0 -0
  314. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/generate_montecarlo_fixtures.py +0 -0
  315. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/generate_survival_fixtures.py +0 -0
  316. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_balanced.csv +0 -0
  317. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_balanced_meta.json +0 -0
  318. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_balanced_r_results.json +0 -0
  319. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_basic.csv +0 -0
  320. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_basic_meta.json +0 -0
  321. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_basic_r_results.json +0 -0
  322. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_large.csv +0 -0
  323. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_large_meta.json +0 -0
  324. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_large_r_results.json +0 -0
  325. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_separated.csv +0 -0
  326. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_separated_meta.json +0 -0
  327. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_binomial_separated_r_results.json +0 -0
  328. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_gaussian_basic.csv +0 -0
  329. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_gaussian_basic_meta.json +0 -0
  330. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_gaussian_basic_r_results.json +0 -0
  331. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_gaussian_large.csv +0 -0
  332. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_gaussian_large_meta.json +0 -0
  333. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_gaussian_large_r_results.json +0 -0
  334. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_basic.csv +0 -0
  335. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_basic_meta.json +0 -0
  336. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_basic_r_results.json +0 -0
  337. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_large_counts.csv +0 -0
  338. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_large_counts_meta.json +0 -0
  339. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_large_counts_r_results.json +0 -0
  340. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_zeros.csv +0 -0
  341. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_zeros_meta.json +0 -0
  342. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/glm_poisson_zeros_r_results.json +0 -0
  343. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/high_noise.csv +0 -0
  344. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/high_noise_meta.json +0 -0
  345. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/high_noise_r_results.json +0 -0
  346. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_chisq_2x2_yates_meta.json +0 -0
  347. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_chisq_2x2_yates_r_results.json +0 -0
  348. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_chisq_3x3_meta.json +0 -0
  349. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_chisq_3x3_r_results.json +0 -0
  350. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_chisq_gof_meta.json +0 -0
  351. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_chisq_gof_r_results.json +0 -0
  352. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_chisq_gof_unequal_meta.json +0 -0
  353. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_chisq_gof_unequal_r_results.json +0 -0
  354. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_fisher_2x2_less_meta.json +0 -0
  355. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_fisher_2x2_less_r_results.json +0 -0
  356. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_fisher_2x2_meta.json +0 -0
  357. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_fisher_2x2_r_results.json +0 -0
  358. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_fisher_3x3_meta.json +0 -0
  359. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_fisher_3x3_r_results.json +0 -0
  360. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_ks_onesample_norm_meta.json +0 -0
  361. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_ks_onesample_norm_r_results.json +0 -0
  362. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_ks_twosample_meta.json +0 -0
  363. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_ks_twosample_r_results.json +0 -0
  364. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_prop_onesample_meta.json +0 -0
  365. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_prop_onesample_r_results.json +0 -0
  366. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_prop_twosample_meta.json +0 -0
  367. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_prop_twosample_r_results.json +0 -0
  368. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_t_onesample_meta.json +0 -0
  369. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_t_onesample_r_results.json +0 -0
  370. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_t_paired_meta.json +0 -0
  371. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_t_paired_r_results.json +0 -0
  372. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_t_pooled_meta.json +0 -0
  373. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_t_pooled_r_results.json +0 -0
  374. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_t_welch_meta.json +0 -0
  375. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_t_welch_r_results.json +0 -0
  376. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_var_basic_meta.json +0 -0
  377. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_var_basic_r_results.json +0 -0
  378. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_wilcox_ranksum_meta.json +0 -0
  379. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_wilcox_ranksum_r_results.json +0 -0
  380. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_wilcox_signed_meta.json +0 -0
  381. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/htest_wilcox_signed_r_results.json +0 -0
  382. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/ill_conditioned.csv +0 -0
  383. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/ill_conditioned_meta.json +0 -0
  384. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/ill_conditioned_r_results.json +0 -0
  385. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/large_coeffs.csv +0 -0
  386. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/large_coeffs_meta.json +0 -0
  387. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/large_coeffs_r_results.json +0 -0
  388. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_ci_90_meta.json +0 -0
  389. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_ci_90_r_results.json +0 -0
  390. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_ci_normal_meta.json +0 -0
  391. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_ci_normal_r_results.json +0 -0
  392. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_ci_skewed_meta.json +0 -0
  393. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_ci_skewed_r_results.json +0 -0
  394. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_mean_balanced_meta.json +0 -0
  395. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_mean_balanced_r_results.json +0 -0
  396. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_mean_ordinary_meta.json +0 -0
  397. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_mean_ordinary_r_results.json +0 -0
  398. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_median_meta.json +0 -0
  399. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_median_r_results.json +0 -0
  400. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_variance_meta.json +0 -0
  401. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_boot_variance_r_results.json +0 -0
  402. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_perm_greater_meta.json +0 -0
  403. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_perm_greater_r_results.json +0 -0
  404. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_perm_not_significant_meta.json +0 -0
  405. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_perm_not_significant_r_results.json +0 -0
  406. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_perm_significant_meta.json +0 -0
  407. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mc_perm_significant_r_results.json +0 -0
  408. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/glmm_binomial.csv +0 -0
  409. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/glmm_poisson.csv +0 -0
  410. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/lmm_crossed.csv +0 -0
  411. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/lmm_intercept.csv +0 -0
  412. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/lmm_ml.csv +0 -0
  413. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/lmm_no_effect.csv +0 -0
  414. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/lmm_slope.csv +0 -0
  415. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/mixed_meta.json +0 -0
  416. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/mixed/mixed_r_results.json +0 -0
  417. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/near_square.csv +0 -0
  418. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/near_square_meta.json +0 -0
  419. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/near_square_r_results.json +0 -0
  420. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/no_intercept.csv +0 -0
  421. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/no_intercept_meta.json +0 -0
  422. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/no_intercept_r_results.json +0 -0
  423. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_r_anova_validation.R +0 -0
  424. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_r_descriptive_validation.R +0 -0
  425. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_r_glm_validation.R +0 -0
  426. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_r_hypothesis_validation.R +0 -0
  427. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_r_mixed_validation.R +0 -0
  428. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_r_montecarlo_validation.R +0 -0
  429. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_r_survival_validation.R +0 -0
  430. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_r_validation.R +0 -0
  431. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/run_validation.sh +0 -0
  432. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/small_noise.csv +0 -0
  433. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/small_noise_meta.json +0 -0
  434. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/small_noise_r_results.json +0 -0
  435. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_cox_breslow_meta.json +0 -0
  436. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_cox_breslow_r_results.json +0 -0
  437. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_cox_single_meta.json +0 -0
  438. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_cox_single_r_results.json +0 -0
  439. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_cox_ties_meta.json +0 -0
  440. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_cox_ties_r_results.json +0 -0
  441. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_cox_two_cov_meta.json +0 -0
  442. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_cox_two_cov_r_results.json +0 -0
  443. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_basic_meta.json +0 -0
  444. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_basic_r_results.json +0 -0
  445. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_heavy_cens_meta.json +0 -0
  446. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_heavy_cens_r_results.json +0 -0
  447. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_loglog_ci_meta.json +0 -0
  448. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_loglog_ci_r_results.json +0 -0
  449. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_no_cens_meta.json +0 -0
  450. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_no_cens_r_results.json +0 -0
  451. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_plain_ci_meta.json +0 -0
  452. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_plain_ci_r_results.json +0 -0
  453. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_ties_meta.json +0 -0
  454. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_km_ties_r_results.json +0 -0
  455. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_lr_peto_meta.json +0 -0
  456. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_lr_peto_r_results.json +0 -0
  457. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_lr_three_group_meta.json +0 -0
  458. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_lr_three_group_r_results.json +0 -0
  459. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_lr_two_group_meta.json +0 -0
  460. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/surv_lr_two_group_r_results.json +0 -0
  461. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/tall_skinny.csv +0 -0
  462. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/tall_skinny_meta.json +0 -0
  463. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/tall_skinny_r_results.json +0 -0
  464. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/fixtures/validate_against_r.py +0 -0
  465. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/gam/__init__.py +0 -0
  466. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/gam/test_gam.py +0 -0
  467. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/__init__.py +0 -0
  468. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/conftest.py +0 -0
  469. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_chisq_test.py +0 -0
  470. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_design_split.py +0 -0
  471. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_fisher_test.py +0 -0
  472. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_gpu.py +0 -0
  473. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_ks_test.py +0 -0
  474. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_p_adjust.py +0 -0
  475. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_prop_test.py +0 -0
  476. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_r_validation.py +0 -0
  477. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_t_test.py +0 -0
  478. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_var_test.py +0 -0
  479. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/hypothesis/test_wilcox_test.py +0 -0
  480. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/__init__.py +0 -0
  481. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/conftest.py +0 -0
  482. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_glmm.py +0 -0
  483. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_lmm_crossed.py +0 -0
  484. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_lmm_intercept.py +0 -0
  485. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_lmm_nested.py +0 -0
  486. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_lmm_slope.py +0 -0
  487. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_pls.py +0 -0
  488. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_r_validation.py +0 -0
  489. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_random_effects.py +0 -0
  490. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mixed/test_satterthwaite.py +0 -0
  491. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/__init__.py +0 -0
  492. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/conftest.py +0 -0
  493. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/test_batched_solver.py +0 -0
  494. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/test_boot_ci.py +0 -0
  495. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/test_bootstrap.py +0 -0
  496. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/test_gpu.py +0 -0
  497. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/test_influence.py +0 -0
  498. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/test_permutation.py +0 -0
  499. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/montecarlo/test_r_validation.py +0 -0
  500. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/multinomial/__init__.py +0 -0
  501. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/multinomial/test_multinom.py +0 -0
  502. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/multivariate/__init__.py +0 -0
  503. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/multivariate/test_multivariate.py +0 -0
  504. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/apple_em_reference.json +0 -0
  505. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/apple_reference.json +0 -0
  506. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/generate_em_fixtures.R +0 -0
  507. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/little_mcar_apple.json +0 -0
  508. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/little_mcar_complete.json +0 -0
  509. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/little_mcar_extreme.json +0 -0
  510. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/little_mcar_missvals.json +0 -0
  511. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/little_mcar_simple_mcar.json +0 -0
  512. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/little_mcar_summary.json +0 -0
  513. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/missvals_em_reference.json +0 -0
  514. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/missvals_reference.json +0 -0
  515. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/references/small_test_reference.json +0 -0
  516. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/test_em.py +0 -0
  517. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/mvnmle/test_mlest.py +0 -0
  518. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/ordinal/__init__.py +0 -0
  519. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/ordinal/test_ordinal.py +0 -0
  520. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/benchmark.py +0 -0
  521. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/benchmark.r +0 -0
  522. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/conftest.py +0 -0
  523. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/test_fit.py +0 -0
  524. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/test_gamma_nb.py +0 -0
  525. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/test_glm.py +0 -0
  526. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/test_glm_gpu.py +0 -0
  527. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/test_glm_r_validation.py +0 -0
  528. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/test_module_split.py +0 -0
  529. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/test_r_validation.py +0 -0
  530. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/regression/test_stress_gpu.py +0 -0
  531. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/survival/__init__.py +0 -0
  532. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/survival/conftest.py +0 -0
  533. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/survival/test_coxph.py +0 -0
  534. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/survival/test_discrete_time.py +0 -0
  535. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/survival/test_gpu.py +0 -0
  536. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/survival/test_kaplan_meier.py +0 -0
  537. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/survival/test_logrank.py +0 -0
  538. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/survival/test_r_validation.py +0 -0
  539. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/test_code_quality.py +0 -0
  540. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/timeseries/__init__.py +0 -0
  541. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/timeseries/test_acf_stationarity.py +0 -0
  542. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/timeseries/test_arima.py +0 -0
  543. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/timeseries/test_decomposition.py +0 -0
  544. {pystatistics-2.0.1 → pystatistics-2.1.0}/tests/timeseries/test_ets.py +0 -0
@@ -1,5 +1,218 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.1.0
4
+
5
+ - **`mom_mcar_test`: new method-of-moments MCAR test**
6
+ (``pystatistics/mvnmle/mcar_test.py``). A separate function — not
7
+ a new mode on ``little_mcar_test`` — because the method-of-moments
8
+ variant **is not Little's test**. Little (1988) specifically calls
9
+ for MLE plug-in estimators; swapping in pairwise-deletion sample
10
+ moments gives a statistic of the same shape with different
11
+ asymptotic properties, and calling it Little's test would be a
12
+ polite but concrete lie. The separate function preserves the
13
+ ``little_mcar_test`` contract exactly (matches R ``mvnmle`` bit-
14
+ for-bit as before) while giving users a documented fast alternative.
15
+
16
+ End-to-end timings at 15 % MCAR:
17
+
18
+ | dataset | shape | little_mcar_test | mom_mcar_test |
19
+ |----------------|-----------|------------------|---------------|
20
+ | iris | 150 × 4 | 2.9 ms | 0.31 ms |
21
+ | wine | 178 × 13 | 60.9 ms | 2.17 ms |
22
+ | breast_cancer | 569 × 30 | 1491 ms | 28.7 ms |
23
+
24
+ For repeated-diagnostic workflows (e.g. an MCAR sweep over 3410
25
+ datasets), this is **1.6 minutes vs ~50 minutes** end-to-end. The
26
+ statistical trade-off is asymptotic efficiency: MoM is consistent
27
+ under the MCAR null but not asymptotically efficient, and the
28
+ finite-sample distribution deviates more from chi-square than
29
+ Little's does. The docstring spells out when to use which:
30
+ diagnostic screens → MoM; regulated submissions or anywhere the
31
+ exact asymptotic distribution matters → Little's.
32
+
33
+ Implementation details:
34
+ - ``_pairwise_deletion_moments``: O(n v^2) pairwise mean and
35
+ covariance via a single matmul. No per-column loop.
36
+ - ``chi_square_mcar_batched_np`` / ``_torch``: fully batched
37
+ chi-square assembly (batched SVD for conditioning,
38
+ well-conditioned patterns through batched solve, ill-conditioned
39
+ patterns through batched pinv as separate groups — no
40
+ per-pattern Python loop).
41
+ - ``backend`` parameter with same size-heuristic + visible-warning
42
+ discipline as the EM path. GPU is supported but does not
43
+ out-perform CPU on any tested shape — MoM's compute is small
44
+ enough that transfer + launch overhead loses to CPU numpy.
45
+ Auto-dispatch warns when this is the case.
46
+ - Honesty: ``MCARTestResult`` gained a ``method`` field so
47
+ downstream code knows which test produced a given result.
48
+ ``little_mcar_test`` reports ``"Little (MLE plug-in)"``;
49
+ ``mom_mcar_test`` reports ``"Method-of-moments
50
+ (pairwise-deletion plug-in)"``.
51
+
52
+ New tests (``tests/mvnmle/test_mom_mcar.py``, 10 tests):
53
+ name-honesty, MLE-vs-MoM agreement on MCAR data, correct rejection
54
+ on non-MCAR data, all-missing-row handling, speed guard of
55
+ ≥ 10× over MLE on breast_cancer.
56
+
57
+ - **Fully-batched device-resident EM on GPU** (``_em_batched.py``
58
+ / ``_run_em_loop_gpu``). Pre-2.1.0 the "GPU EM" path set up a
59
+ torch device in the constructor but none of the per-iteration
60
+ work actually ran on-device — the numpy E-step ran for every
61
+ backend, which is why pre-2.1.0 benchmarks showed identical CPU
62
+ and GPU timings. This release implements the real thing: one
63
+ batched Cholesky + one batched solve over patterns for the
64
+ regression betas, one batched gather + bmm over all N
65
+ observations for the filled data, two dense gemms for the
66
+ sufficient-statistic accumulators, all on-device. SQUAREM also
67
+ runs fully on-device.
68
+
69
+ EM-only timings (without the MCAR-assembly wrapper):
70
+
71
+ | dataset | shape | CPU EM | GPU EM | speedup |
72
+ |----------------|-----------|----------|----------|---------|
73
+ | wine | 178 × 13 | 38 ms | 24 ms | 1.6× |
74
+ | breast_cancer | 569 × 30 | 2142 ms | 147 ms | 14.6× |
75
+
76
+ Small-data cases (apple, iris, missvals) lose on GPU because
77
+ transfer + launch overhead exceeds the per-iteration work.
78
+ Empirically calibrated heuristic: GPU is worth it when
79
+ ``n_obs * n_vars > 1500``.
80
+
81
+ - **Size-heuristic dispatch with Rule-1 visibility** for both EM and
82
+ MoM backends. When ``backend='auto'`` makes a non-obvious choice
83
+ (e.g. picking CPU despite GPU availability because the data are
84
+ too small), a ``UserWarning`` explains the decision and tells
85
+ users how to override. When ``backend='gpu'`` is explicitly
86
+ requested on small data, the request is honored (user knows best)
87
+ but a warning notes that CPU would likely be faster. No silent
88
+ fallbacks anywhere. New tests pin these behaviours.
89
+
90
+ - **Monotone-missingness closed-form MLE** (Anderson 1957; new
91
+ ``pystatistics.mvnmle._monotone``). When the missingness pattern
92
+ is monotone — when variables can be ordered such that each
93
+ observation's missing entries form a contiguous suffix — the MVN
94
+ MLE has a closed form via a chain of OLS regressions, with no
95
+ iteration. Common on longitudinal data with attrition, panel
96
+ surveys with dropout, and most sequentially-administered
97
+ instruments. New public helpers:
98
+
99
+ - ``pystatistics.mvnmle.is_monotone(data) -> bool``
100
+ - ``pystatistics.mvnmle.monotone_permutation(data) -> ndarray | None``
101
+ - ``pystatistics.mvnmle.mlest_monotone_closed_form(data) -> (mu, sigma, n)``
102
+ - ``mlest(data, algorithm='monotone')`` routes through the
103
+ closed-form; raises ``ValidationError`` if the data are not
104
+ monotone (Rule 1: no silent dispatch). Users who want
105
+ "use the closed form when applicable, fall back otherwise"
106
+ should call ``is_monotone`` first and branch explicitly.
107
+
108
+ The closed-form is the exact MLE (no tolerance-bounded
109
+ approximation), matches R ``mvnmle`` reference output on both
110
+ ``apple`` and ``missvals`` to machine precision, and is
111
+ dramatically faster than iterative algorithms at larger v
112
+ (a 1500 × 20 monotone dataset completes in ~2 ms vs EM's
113
+ ~40 ms). For non-monotone random MCAR data (the common case
114
+ in MCAR diagnostic use), detection is cheap (~O(v² n)) and
115
+ correctly returns False so iterative algorithms run.
116
+
117
+ New tests (``tests/mvnmle/test_monotone.py``, 12 tests):
118
+ detection true-positive / true-negative on several canonical
119
+ shapes; closed-form vs EM agreement; permutation invariance;
120
+ non-monotone data raises; performance guard at v=20.
121
+
122
+ - **EM MLE: substantial real-data speedup via batched per-pattern
123
+ linear algebra + SQUAREM acceleration** (Project Lacuna-driven).
124
+
125
+ End-to-end ``little_mcar_test`` wall-clock at 15 % MCAR, seed 0:
126
+
127
+ | dataset | shape | 2.0.1 | 2.1.0 | speedup |
128
+ |----------------|-----------|----------|----------|---------|
129
+ | apple | 18 × 2 | 1.9 ms | 2.0 ms | flat |
130
+ | missvals | 13 × 5 | 19.9 ms | 9.5 ms | 2.1× |
131
+ | iris | 150 × 4 | 2.8 ms | 2.8 ms | flat |
132
+ | wine | 178 × 13 | 79.4 ms | 41.5 ms | 1.9× |
133
+ | breast_cancer | 569 × 30 | 3278 ms | 2089 ms | 1.6× |
134
+
135
+ For workloads that run MCAR repeatedly over many datasets
136
+ (e.g. a 3410-entry MCAR sweep), this is roughly a 1-hour reduction
137
+ per full pass at Lacuna's current scale.
138
+
139
+ Three changes stack:
140
+
141
+ 1. **Batched per-pattern conditional parameters** (new
142
+ ``pystatistics.mvnmle.backends._em_batched``). The E-step used
143
+ to loop in Python over missingness patterns, issuing a scalar
144
+ Cholesky + triangular solve per pattern. It now stacks all P
145
+ pattern-sigma submatrices into a single
146
+ ``(P, v_max, v_max)`` tensor (identity-padded in the unused
147
+ slots so the Cholesky stays well-defined) and runs one batched
148
+ Cholesky + one batched solve for the whole iteration. The
149
+ accumulator loop over patterns remains in Python because
150
+ ``n_k`` varies and full observation-level padding hurt more
151
+ than it helped on the representative shapes we benchmarked.
152
+
153
+ 2. **SQUAREM acceleration** (Varadhan & Roland 2008; new
154
+ ``pystatistics.mvnmle.backends._squarem``). EM's linear
155
+ convergence is sped up by a Steffensen-style extrapolation of
156
+ three consecutive EM iterates, safeguarded by a monotonicity
157
+ check on the observed-data log-likelihood. Typical effect on
158
+ well-behaved EM problems: 2–4× reduction in underlying
159
+ EM-step-equivalents. Preserves the MLE — the convergence
160
+ point is unchanged, only the path is shorter. On by default
161
+ via a new ``accelerate=True`` kwarg on ``EMBackend.solve``;
162
+ pass ``accelerate=False`` for the plain-EM reference path.
163
+
164
+ 3. **Fully batched observed-data log-likelihood**
165
+ (``compute_loglik_batched_np``). The SQUAREM monotonicity
166
+ safeguard calls the log-likelihood often, so that path
167
+ needed to be cheap. The implementation now does one batched
168
+ Cholesky over all patterns for log-determinants and one
169
+ batched solve across all N observations for the quadratic-
170
+ form contribution — no per-pattern Python loop.
171
+
172
+ - **Benchmark harness** (``benchmarks/mvnmle_bench.py``). Runs the
173
+ five reference shapes (apple, missvals, iris, wine,
174
+ breast_cancer) across the (algorithm, backend) matrix and
175
+ prints wall-clock / iteration counts per case. Use
176
+ ``--quick`` to skip the BFGS cases that don't converge on
177
+ high-$v$ data; ``--tag`` labels a run for diff against prior
178
+ baselines.
179
+
180
+ - **Documented why direct-BFGS is not always the right default.**
181
+ Internal notes and the 2.0.0 / 2.0.1 release narrative already
182
+ covered why ``algorithm='em'`` became the ``little_mcar_test``
183
+ default; this release adds the story of why batching helps EM
184
+ significantly but does *not* rescue direct-BFGS on realistic
185
+ high-$v$ data (layer-3 Hessian conditioning is parameterization-
186
+ invariant; batching only addresses layer-1 launch overhead).
187
+ See ``GPU_BACKEND_CONVENTION.md`` Section 0 for the "when to
188
+ add a GPU backend and when not" rule that drove the 2.0.1
189
+ cleanup; this release extends that logic with
190
+ "accelerating the algorithm by reducing iteration count
191
+ (SQUAREM) is cheaper than accelerating each iteration."
192
+
193
+ - **Finding: the "GPU EM" backend was never actually running on
194
+ GPU.** The ``device='cuda'`` / ``'mps'`` constructor flag set
195
+ up ``self._torch`` but none of ``_e_step`` / ``_m_step`` /
196
+ ``_compute_loglik`` used it — the numpy path ran for every
197
+ backend. That's why pre-2.1.0 benchmarks showed identical
198
+ CPU and GPU EM timings. We attempted to implement a real
199
+ device-resident EM loop and found it was slower than CPU for
200
+ all the shapes we care about (per-pattern kernel-launch
201
+ overhead dominates the small per-pattern matrix work). The
202
+ honest answer for now is that GPU EM stays CPU-equivalent
203
+ by design; a future release may revisit with fully N-parallel
204
+ observation-level batching if a workload appears where the
205
+ GPU can actually win. This behaviour is unchanged from prior
206
+ releases — we're just documenting what was already true.
207
+
208
+ - **SQUAREM test coverage** (new ``tests/mvnmle/test_squarem.py``).
209
+ Four tests pinning the invariants: same MLE as plain EM on
210
+ apple; substantially fewer EM-equivalent steps on missvals;
211
+ monotonicity of log-likelihood preserved across iteration
212
+ caps; same MLE as plain EM on a realistic shape (sklearn
213
+ wine with 15 % MCAR).
214
+
215
+
3
216
  ## 2.0.1
4
217
 
5
218
  - **GPU Backend Convention: codified when NOT to add a GPU backend**
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pystatistics
3
- Version: 2.0.1
3
+ Version: 2.1.0
4
4
  Summary: GPU-accelerated statistical computing for Python
5
5
  Project-URL: Homepage, https://sgcx.org/technology/pystatistics/
6
6
  Project-URL: Documentation, https://sgcx.org/docs/pystatistics/
@@ -51,6 +51,108 @@ GPU-accelerated statistical computing for Python.
51
51
 
52
52
  ## What's New
53
53
 
54
+ ### 2.1.0 — Real-data EM speedup + monotone closed-form MLE
55
+
56
+ Dogfooding via Project Lacuna surfaced that ``little_mcar_test`` on
57
+ realistic tabular data (sklearn's iris / wine / breast_cancer with
58
+ random MCAR injection) was bottlenecked by EM: the E-step was a
59
+ Python loop over missingness patterns, and each SQUAREM-style
60
+ safeguard pass re-ran a per-pattern log-likelihood. This release
61
+ batches both and adds Varadhan & Roland's SQUAREM acceleration.
62
+
63
+ End-to-end ``little_mcar_test`` wall-clock at 15 % MCAR, seed 0:
64
+
65
+ | dataset | shape | 2.0.1 | 2.1.0 | speedup |
66
+ |----------------|-----------|----------|----------|---------|
67
+ | missvals | 13 × 5 | 19.9 ms | 9.5 ms | 2.1× |
68
+ | wine | 178 × 13 | 79.4 ms | 41.5 ms | 1.9× |
69
+ | breast_cancer | 569 × 30 | 3278 ms | 2089 ms | 1.6× |
70
+
71
+ For repeated-diagnostic workflows (e.g. an MCAR sweep over several
72
+ thousand datasets), this turns a 3-hour run into a 2-hour run.
73
+
74
+ Three stacked improvements, all preserving bit-equivalence on the R
75
+ mvnmle reference cases (apple, missvals):
76
+
77
+ - **Batched per-pattern conditional parameters.** The E-step's
78
+ per-pattern Cholesky + triangular solve now runs as a single
79
+ batched kernel pair across all missingness patterns. The
80
+ unused padding slots are identity-filled so the Cholesky stays
81
+ well-defined.
82
+ - **SQUAREM acceleration on top of EM.** Three EM steps + one
83
+ Steffensen-style extrapolation, safeguarded by a monotonicity
84
+ check on the observed-data log-likelihood. Typical effect:
85
+ 2–4× fewer EM-step equivalents to convergence. Convergence
86
+ point is the same MLE — only the path is shorter. On by
87
+ default; ``EMBackend.solve(..., accelerate=False)`` recovers
88
+ the plain-EM reference.
89
+ - **Fully batched log-likelihood.** The SQUAREM monotonicity
90
+ check calls ``loglik`` often, so it was batched too — one
91
+ Cholesky over all patterns, one solve across all N
92
+ observations, no per-pattern Python loop.
93
+
94
+ **`mom_mcar_test`: fast method-of-moments MCAR test.** A new *separate
95
+ function* (not a mode on ``little_mcar_test``, because the MoM variant
96
+ is not Little's test) that uses pairwise-deletion sample moments
97
+ instead of MLE plug-in. The test is consistent under MCAR but not
98
+ asymptotically efficient, trading a small amount of statistical
99
+ efficiency for dramatic speed. At 15 % MCAR on sklearn demos:
100
+
101
+ | dataset | shape | little_mcar_test | mom_mcar_test |
102
+ |----------------|-----------|------------------|---------------|
103
+ | iris | 150 × 4 | 2.9 ms | 0.31 ms |
104
+ | wine | 178 × 13 | 60.9 ms | 2.17 ms |
105
+ | breast_cancer | 569 × 30 | 1491 ms | 28.7 ms |
106
+
107
+ For a 3410-dataset MCAR sweep: **~50 minutes → ~1.6 minutes**. Use
108
+ ``little_mcar_test`` when you need Little 1988's asymptotic
109
+ distribution exactly (regulated submissions, citing R reference);
110
+ use ``mom_mcar_test`` for high-throughput diagnostic screens. The
111
+ ``MCARTestResult.method`` field records which test produced a given
112
+ result so downstream code can disambiguate without tracking the
113
+ calling function.
114
+
115
+ **Fully-batched device-resident EM on GPU.** Pre-2.1.0 the
116
+ ``device='cuda'`` EM path set up a torch device but never used it —
117
+ numpy ran for every backend. This release implements a real
118
+ device-resident loop with fully batched E-step / M-step / log-
119
+ likelihood, SQUAREM acceleration on top, all on device. On breast-
120
+ cancer-scale (569 × 30) EM drops from 2142 ms CPU to 147 ms GPU
121
+ (14.6×). Small data remains CPU-faster; an empirical size heuristic
122
+ (``n * v >= 1500``) with visible dispatch warnings keeps this
123
+ correct in user-facing behaviour.
124
+
125
+ **Monotone-missingness closed-form MLE** (Anderson 1957). Longitudinal
126
+ cohorts with attrition, panel surveys with dropout, and most
127
+ sequentially-administered instruments produce *monotone* missingness
128
+ — the variables can be ordered such that each observation's missing
129
+ entries form a contiguous suffix. When the pattern is monotone, the
130
+ MVN MLE has a closed form via a chain of OLS regressions, with no
131
+ iteration. New helpers: ``mvnmle.is_monotone(data)``,
132
+ ``mvnmle.monotone_permutation(data)``, and
133
+ ``mlest(data, algorithm='monotone')``. The closed-form matches R
134
+ ``mvnmle`` bit-for-bit on canonical datasets and is orders of
135
+ magnitude faster than EM on larger-v longitudinal data. Per Rule 1
136
+ the algorithm raises on non-monotone input rather than silently
137
+ falling back — call ``is_monotone`` first if you want conditional
138
+ dispatch.
139
+
140
+ Also in this release:
141
+
142
+ - **Benchmark harness** under ``benchmarks/mvnmle_bench.py`` for
143
+ tracking wall-clock and iteration counts across the reference
144
+ shapes; use the ``--tag`` flag to label a baseline for diff
145
+ against future changes.
146
+ - **Documented finding**: the ``device='cuda'`` EM path was never
147
+ actually running on the GPU prior to this release — it stored
148
+ a torch device but never used it. We tried to wire up a real
149
+ device-resident loop and found GPU is slower than CPU for all
150
+ shapes we tested (per-pattern launch overhead still dominates
151
+ the tiny per-pattern matrix work). GPU EM therefore remains
152
+ CPU-equivalent by design; a future release will revisit if a
153
+ workload appears where full observation-level batching makes
154
+ GPU actually win.
155
+
54
156
  ### 2.0.1 — GPU-backend exposure gaps and a convention rule
55
157
 
56
158
  Two public functions had GPU-capable inner calls but no `backend=`
@@ -4,6 +4,108 @@ GPU-accelerated statistical computing for Python.
4
4
 
5
5
  ## What's New
6
6
 
7
+ ### 2.1.0 — Real-data EM speedup + monotone closed-form MLE
8
+
9
+ Dogfooding via Project Lacuna surfaced that ``little_mcar_test`` on
10
+ realistic tabular data (sklearn's iris / wine / breast_cancer with
11
+ random MCAR injection) was bottlenecked by EM: the E-step was a
12
+ Python loop over missingness patterns, and each SQUAREM-style
13
+ safeguard pass re-ran a per-pattern log-likelihood. This release
14
+ batches both and adds Varadhan & Roland's SQUAREM acceleration.
15
+
16
+ End-to-end ``little_mcar_test`` wall-clock at 15 % MCAR, seed 0:
17
+
18
+ | dataset | shape | 2.0.1 | 2.1.0 | speedup |
19
+ |----------------|-----------|----------|----------|---------|
20
+ | missvals | 13 × 5 | 19.9 ms | 9.5 ms | 2.1× |
21
+ | wine | 178 × 13 | 79.4 ms | 41.5 ms | 1.9× |
22
+ | breast_cancer | 569 × 30 | 3278 ms | 2089 ms | 1.6× |
23
+
24
+ For repeated-diagnostic workflows (e.g. an MCAR sweep over several
25
+ thousand datasets), this turns a 3-hour run into a 2-hour run.
26
+
27
+ Three stacked improvements, all preserving bit-equivalence on the R
28
+ mvnmle reference cases (apple, missvals):
29
+
30
+ - **Batched per-pattern conditional parameters.** The E-step's
31
+ per-pattern Cholesky + triangular solve now runs as a single
32
+ batched kernel pair across all missingness patterns. The
33
+ unused padding slots are identity-filled so the Cholesky stays
34
+ well-defined.
35
+ - **SQUAREM acceleration on top of EM.** Three EM steps + one
36
+ Steffensen-style extrapolation, safeguarded by a monotonicity
37
+ check on the observed-data log-likelihood. Typical effect:
38
+ 2–4× fewer EM-step equivalents to convergence. Convergence
39
+ point is the same MLE — only the path is shorter. On by
40
+ default; ``EMBackend.solve(..., accelerate=False)`` recovers
41
+ the plain-EM reference.
42
+ - **Fully batched log-likelihood.** The SQUAREM monotonicity
43
+ check calls ``loglik`` often, so it was batched too — one
44
+ Cholesky over all patterns, one solve across all N
45
+ observations, no per-pattern Python loop.
46
+
47
+ **`mom_mcar_test`: fast method-of-moments MCAR test.** A new *separate
48
+ function* (not a mode on ``little_mcar_test``, because the MoM variant
49
+ is not Little's test) that uses pairwise-deletion sample moments
50
+ instead of MLE plug-in. The test is consistent under MCAR but not
51
+ asymptotically efficient, trading a small amount of statistical
52
+ efficiency for dramatic speed. At 15 % MCAR on sklearn demos:
53
+
54
+ | dataset | shape | little_mcar_test | mom_mcar_test |
55
+ |----------------|-----------|------------------|---------------|
56
+ | iris | 150 × 4 | 2.9 ms | 0.31 ms |
57
+ | wine | 178 × 13 | 60.9 ms | 2.17 ms |
58
+ | breast_cancer | 569 × 30 | 1491 ms | 28.7 ms |
59
+
60
+ For a 3410-dataset MCAR sweep: **~50 minutes → ~1.6 minutes**. Use
61
+ ``little_mcar_test`` when you need Little 1988's asymptotic
62
+ distribution exactly (regulated submissions, citing R reference);
63
+ use ``mom_mcar_test`` for high-throughput diagnostic screens. The
64
+ ``MCARTestResult.method`` field records which test produced a given
65
+ result so downstream code can disambiguate without tracking the
66
+ calling function.
67
+
68
+ **Fully-batched device-resident EM on GPU.** Pre-2.1.0 the
69
+ ``device='cuda'`` EM path set up a torch device but never used it —
70
+ numpy ran for every backend. This release implements a real
71
+ device-resident loop with fully batched E-step / M-step / log-
72
+ likelihood, SQUAREM acceleration on top, all on device. On breast-
73
+ cancer-scale (569 × 30) EM drops from 2142 ms CPU to 147 ms GPU
74
+ (14.6×). Small data remains CPU-faster; an empirical size heuristic
75
+ (``n * v >= 1500``) with visible dispatch warnings keeps this
76
+ correct in user-facing behaviour.
77
+
78
+ **Monotone-missingness closed-form MLE** (Anderson 1957). Longitudinal
79
+ cohorts with attrition, panel surveys with dropout, and most
80
+ sequentially-administered instruments produce *monotone* missingness
81
+ — the variables can be ordered such that each observation's missing
82
+ entries form a contiguous suffix. When the pattern is monotone, the
83
+ MVN MLE has a closed form via a chain of OLS regressions, with no
84
+ iteration. New helpers: ``mvnmle.is_monotone(data)``,
85
+ ``mvnmle.monotone_permutation(data)``, and
86
+ ``mlest(data, algorithm='monotone')``. The closed-form matches R
87
+ ``mvnmle`` bit-for-bit on canonical datasets and is orders of
88
+ magnitude faster than EM on larger-v longitudinal data. Per Rule 1
89
+ the algorithm raises on non-monotone input rather than silently
90
+ falling back — call ``is_monotone`` first if you want conditional
91
+ dispatch.
92
+
93
+ Also in this release:
94
+
95
+ - **Benchmark harness** under ``benchmarks/mvnmle_bench.py`` for
96
+ tracking wall-clock and iteration counts across the reference
97
+ shapes; use the ``--tag`` flag to label a baseline for diff
98
+ against future changes.
99
+ - **Documented finding**: the ``device='cuda'`` EM path was never
100
+ actually running on the GPU prior to this release — it stored
101
+ a torch device but never used it. We tried to wire up a real
102
+ device-resident loop and found GPU is slower than CPU for all
103
+ shapes we tested (per-pattern launch overhead still dominates
104
+ the tiny per-pattern matrix work). GPU EM therefore remains
105
+ CPU-equivalent by design; a future release will revisit if a
106
+ workload appears where full observation-level batching makes
107
+ GPU actually win.
108
+
7
109
  ### 2.0.1 — GPU-backend exposure gaps and a convention rule
8
110
 
9
111
  Two public functions had GPU-capable inner calls but no `backend=`
@@ -0,0 +1,194 @@
1
+ """Benchmark harness for pystatistics.mvnmle.
2
+
3
+ Measures wall-clock + iteration count across a representative
4
+ spectrum of shapes, for every (algorithm, backend) combination.
5
+
6
+ Shapes:
7
+ apple 2-var, 18 obs — R-mvnmle reference case
8
+ missvals 5-var, 13 obs — R-mvnmle reference case
9
+ iris 4-var, 150 obs, synthetic MCAR — sklearn demo
10
+ wine 13-var, 178 obs, synthetic MCAR — sklearn demo
11
+ (the Project Lacuna canary: 100+ patterns)
12
+ breast 30-var, 569 obs, synthetic MCAR — sklearn demo
13
+ (Lacuna's real per-entry workload)
14
+
15
+ Run:
16
+ python benchmarks/mvnmle_bench.py # full sweep
17
+ python benchmarks/mvnmle_bench.py --quick # skip slow BFGS cases
18
+ python benchmarks/mvnmle_bench.py --tag baseline > baseline.txt
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import argparse
23
+ import sys
24
+ import time
25
+ from dataclasses import dataclass
26
+
27
+ import numpy as np
28
+
29
+
30
+ SEED = 0
31
+ MISSING_RATE = 0.15
32
+
33
+
34
+ @dataclass
35
+ class Case:
36
+ name: str
37
+ data_fn: object
38
+ shape_hint: str
39
+ slow_bfgs: bool
40
+
41
+
42
+ def _load_apple():
43
+ from pystatistics.mvnmle.datasets import apple
44
+ return apple.copy()
45
+
46
+
47
+ def _load_missvals():
48
+ from pystatistics.mvnmle.datasets import missvals
49
+ return missvals.copy()
50
+
51
+
52
+ def _load_sklearn(loader_name):
53
+ from sklearn import datasets as sk
54
+ X = getattr(sk, f"load_{loader_name}")().data.astype(float).copy()
55
+ rng = np.random.default_rng(SEED)
56
+ X[rng.random(X.shape) < MISSING_RATE] = np.nan
57
+ X = X[~np.all(np.isnan(X), axis=1)]
58
+ return X
59
+
60
+
61
+ CASES = [
62
+ Case("apple", _load_apple, "18 x 2", False),
63
+ Case("missvals", _load_missvals, "13 x 5", False),
64
+ Case("iris", lambda: _load_sklearn("iris"), "150 x 4", False),
65
+ Case("wine", lambda: _load_sklearn("wine"), "178 x 13", True),
66
+ Case("breast", lambda: _load_sklearn("breast_cancer"),"569 x 30", True),
67
+ ]
68
+
69
+
70
+ def _gpu_available():
71
+ try:
72
+ import torch
73
+ return torch.cuda.is_available()
74
+ except ImportError:
75
+ return False
76
+
77
+
78
+ def bench_one(data, algorithm, backend, max_iter, repeat=1):
79
+ """Return dict with time_ms, n_iter, converged, loglik, err.
80
+
81
+ Never raises — any exception becomes err=type-name.
82
+ """
83
+ from pystatistics.mvnmle import mlest
84
+
85
+ # Warmup
86
+ try:
87
+ _ = mlest(data, algorithm=algorithm, backend=backend,
88
+ max_iter=max_iter, verbose=False)
89
+ except Exception as e:
90
+ return {"time_ms": None, "n_iter": None, "converged": False,
91
+ "loglik": None, "err": type(e).__name__}
92
+
93
+ times = []
94
+ n_iter = None
95
+ converged = None
96
+ loglik = None
97
+ for _ in range(repeat):
98
+ t = time.perf_counter()
99
+ try:
100
+ r = mlest(data, algorithm=algorithm, backend=backend,
101
+ max_iter=max_iter, verbose=False)
102
+ times.append(time.perf_counter() - t)
103
+ n_iter = r.n_iter
104
+ converged = r.converged
105
+ loglik = r.loglik
106
+ except Exception as e:
107
+ return {"time_ms": None, "n_iter": None, "converged": False,
108
+ "loglik": None, "err": type(e).__name__}
109
+ median_ms = 1000 * float(np.median(times))
110
+ return {"time_ms": median_ms, "n_iter": n_iter, "converged": converged,
111
+ "loglik": loglik, "err": None}
112
+
113
+
114
+ def bench_mcar_one(data, backend, repeat=1):
115
+ """Benchmark little_mcar_test end-to-end (what Lacuna actually calls)."""
116
+ from pystatistics.mvnmle import little_mcar_test
117
+ import warnings
118
+
119
+ try:
120
+ with warnings.catch_warnings():
121
+ warnings.simplefilter("ignore")
122
+ _ = little_mcar_test(data, backend=backend)
123
+ except Exception as e:
124
+ return {"time_ms": None, "err": type(e).__name__, "stat": None}
125
+
126
+ times = []
127
+ stat = None
128
+ for _ in range(repeat):
129
+ t = time.perf_counter()
130
+ try:
131
+ with warnings.catch_warnings():
132
+ warnings.simplefilter("ignore")
133
+ r = little_mcar_test(data, backend=backend)
134
+ times.append(time.perf_counter() - t)
135
+ stat = r.statistic
136
+ except Exception as e:
137
+ return {"time_ms": None, "err": type(e).__name__, "stat": None}
138
+ return {"time_ms": 1000 * float(np.median(times)),
139
+ "err": None, "stat": stat}
140
+
141
+
142
+ def main():
143
+ ap = argparse.ArgumentParser()
144
+ ap.add_argument("--quick", action="store_true",
145
+ help="skip BFGS on known-slow cases")
146
+ ap.add_argument("--tag", default="",
147
+ help="label printed with each row (e.g. 'baseline')")
148
+ ap.add_argument("--repeat", type=int, default=1,
149
+ help="repetitions per case; reports median")
150
+ ap.add_argument("--max-iter", type=int, default=500)
151
+ args = ap.parse_args()
152
+
153
+ gpu = _gpu_available()
154
+ backends = ["cpu"] + (["gpu"] if gpu else [])
155
+ print(f"# GPU available: {gpu}")
156
+ print(f"# Missing rate: {MISSING_RATE}, seed: {SEED}")
157
+ print(f"# Tag: {args.tag!r}")
158
+ print()
159
+
160
+ header = f"{'case':<10} {'shape':<10} {'algo':<7} {'backend':<4} {'time_ms':>10} {'n_iter':>7} {'conv':>5} {'err':<15}"
161
+ print(header)
162
+ print("-" * len(header))
163
+
164
+ for case in CASES:
165
+ data = case.data_fn()
166
+ for algorithm in ("em", "direct"):
167
+ for backend in backends:
168
+ if args.quick and algorithm == "direct" and case.slow_bfgs:
169
+ continue
170
+ r = bench_one(data, algorithm, backend,
171
+ max_iter=args.max_iter, repeat=args.repeat)
172
+ t = f"{r['time_ms']:.1f}" if r["time_ms"] is not None else "--"
173
+ ni = r["n_iter"] if r["n_iter"] is not None else "--"
174
+ cv = "y" if r["converged"] else ("--" if r["converged"] is None else "n")
175
+ err = r["err"] or ""
176
+ print(f"{case.name:<10} {case.shape_hint:<10} {algorithm:<7} "
177
+ f"{backend:<4} {t:>10} {ni:>7} {cv:>5} {err:<15}")
178
+
179
+ print()
180
+ print("# little_mcar_test end-to-end timings:")
181
+ print(f"{'case':<10} {'shape':<10} {'backend':<4} {'time_ms':>10}")
182
+ print("-" * 40)
183
+ for case in CASES:
184
+ data = case.data_fn()
185
+ for backend in backends:
186
+ r = bench_mcar_one(data, backend, repeat=args.repeat)
187
+ t = f"{r['time_ms']:.1f}" if r["time_ms"] is not None else "--"
188
+ err = r["err"] or ""
189
+ print(f"{case.name:<10} {case.shape_hint:<10} {backend:<4} "
190
+ f"{t:>10} {err}")
191
+
192
+
193
+ if __name__ == "__main__":
194
+ main()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pystatistics"
7
- version = "2.0.1"
7
+ version = "2.1.0"
8
8
  description = "GPU-accelerated statistical computing for Python"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -16,7 +16,7 @@ Usage:
16
16
  result = fit(design)
17
17
  """
18
18
 
19
- __version__ = "2.0.1"
19
+ __version__ = "2.1.0"
20
20
  __author__ = "Hai-Shuo"
21
21
  __email__ = "contact@sgcx.org"
22
22