easyscience 2.4.0__tar.gz → 2.5.1__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 (219) hide show
  1. {easyscience-2.4.0 → easyscience-2.5.1}/PKG-INFO +2 -2
  2. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/tutorials/fitting-bayesian.ipynb +230 -31
  3. {easyscience-2.4.0 → easyscience-2.5.1}/pixi.lock +4719 -4346
  4. {easyscience-2.4.0 → easyscience-2.5.1}/pyproject.toml +7 -7
  5. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/__init__.py +2 -2
  6. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/__init__.py +0 -2
  7. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/minimizer_bumps.py +161 -13
  8. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/multi_fitter.py +0 -2
  9. easyscience-2.5.1/src/easyscience/fitting/sampler.py +810 -0
  10. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/parameter.py +3 -0
  11. {easyscience-2.4.0 → easyscience-2.5.1}/tests/integration/fitting/test_fitter.py +79 -0
  12. {easyscience-2.4.0 → easyscience-2.5.1}/tests/integration/fitting/test_multi_fitter.py +6 -218
  13. easyscience-2.5.1/tests/integration/fitting/test_sampler.py +407 -0
  14. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/minimizers/test_minimizer_bumps.py +274 -2
  15. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/test_fitter.py +0 -153
  16. easyscience-2.5.1/tests/unit/fitting/test_sampler.py +583 -0
  17. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/global_object/test_undo_redo.py +1 -1
  18. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/test_parameter.py +58 -0
  19. {easyscience-2.4.0 → easyscience-2.5.1}/.badgery.yaml +0 -0
  20. {easyscience-2.4.0 → easyscience-2.5.1}/.codecov.yml +0 -0
  21. {easyscience-2.4.0 → easyscience-2.5.1}/.copier-answers.yml +0 -0
  22. {easyscience-2.4.0 → easyscience-2.5.1}/.coveragerc +0 -0
  23. {easyscience-2.4.0 → easyscience-2.5.1}/.github/actions/download-artifact/action.yml +0 -0
  24. {easyscience-2.4.0 → easyscience-2.5.1}/.github/actions/github-script/action.yml +0 -0
  25. {easyscience-2.4.0 → easyscience-2.5.1}/.github/actions/setup-easyscience-bot/action.yml +0 -0
  26. {easyscience-2.4.0 → easyscience-2.5.1}/.github/actions/setup-pixi/action.yml +0 -0
  27. {easyscience-2.4.0 → easyscience-2.5.1}/.github/actions/upload-artifact/action.yml +0 -0
  28. {easyscience-2.4.0 → easyscience-2.5.1}/.github/actions/upload-codecov/action.yml +0 -0
  29. {easyscience-2.4.0 → easyscience-2.5.1}/.github/configs/pages-deployment.json +0 -0
  30. {easyscience-2.4.0 → easyscience-2.5.1}/.github/configs/rulesets-develop.json +0 -0
  31. {easyscience-2.4.0 → easyscience-2.5.1}/.github/configs/rulesets-gh-pages.json +0 -0
  32. {easyscience-2.4.0 → easyscience-2.5.1}/.github/configs/rulesets-master.json +0 -0
  33. {easyscience-2.4.0 → easyscience-2.5.1}/.github/scripts/backmerge-conflict-issue.js +0 -0
  34. {easyscience-2.4.0 → easyscience-2.5.1}/.github/scripts/publish-dashboard.sh +0 -0
  35. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/backmerge.yml +0 -0
  36. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/cleanup.yml +0 -0
  37. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/coverage.yml +0 -0
  38. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/dashboard.yml +0 -0
  39. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/docs.yml +0 -0
  40. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/issues-labels.yml +0 -0
  41. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/lint-format.yml +0 -0
  42. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/pr-labels.yml +0 -0
  43. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/pypi-publish.yml +0 -0
  44. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/pypi-test.yml +0 -0
  45. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/release-notes.yml +0 -0
  46. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/release-pr.yml +0 -0
  47. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/security.yml +0 -0
  48. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/test-trigger.yml +0 -0
  49. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/test.yml +0 -0
  50. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/tutorial-tests-trigger.yml +0 -0
  51. {easyscience-2.4.0 → easyscience-2.5.1}/.github/workflows/tutorial-tests.yml +0 -0
  52. {easyscience-2.4.0 → easyscience-2.5.1}/.gitignore +0 -0
  53. {easyscience-2.4.0 → easyscience-2.5.1}/.pre-commit-config.yaml +0 -0
  54. {easyscience-2.4.0 → easyscience-2.5.1}/.prettierignore +0 -0
  55. {easyscience-2.4.0 → easyscience-2.5.1}/CONTRIBUTING.md +0 -0
  56. {easyscience-2.4.0 → easyscience-2.5.1}/LICENSE +0 -0
  57. {easyscience-2.4.0 → easyscience-2.5.1}/README.md +0 -0
  58. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/base_classes.md +0 -0
  59. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/fitting.md +0 -0
  60. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/global_object.md +0 -0
  61. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/index.md +0 -0
  62. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/io.md +0 -0
  63. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/job.md +0 -0
  64. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/models.md +0 -0
  65. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/utils.md +0 -0
  66. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/api-reference/variable.md +0 -0
  67. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/assets/images/favicon.png +0 -0
  68. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/assets/images/logo_dark.svg +0 -0
  69. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/assets/images/logo_light.svg +0 -0
  70. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/assets/javascripts/extra.js +0 -0
  71. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/assets/javascripts/mathjax.js +0 -0
  72. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/assets/stylesheets/extra.css +0 -0
  73. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/index.md +0 -0
  74. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/installation-and-setup/index.md +0 -0
  75. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/introduction/index.md +0 -0
  76. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/tutorials/fitting-qens.ipynb +0 -0
  77. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/tutorials/fitting-sans.ipynb +0 -0
  78. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/tutorials/index.md +0 -0
  79. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/tutorials/progress-callback.ipynb +0 -0
  80. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/user-guide/controlling-log-output.md +0 -0
  81. {easyscience-2.4.0 → easyscience-2.5.1}/docs/docs/user-guide/index.md +0 -0
  82. {easyscience-2.4.0 → easyscience-2.5.1}/docs/includes/abbreviations.md +0 -0
  83. {easyscience-2.4.0 → easyscience-2.5.1}/docs/mkdocs.yml +0 -0
  84. {easyscience-2.4.0 → easyscience-2.5.1}/docs/overrides/.icons/app.svg +0 -0
  85. {easyscience-2.4.0 → easyscience-2.5.1}/docs/overrides/.icons/easyscience.svg +0 -0
  86. {easyscience-2.4.0 → easyscience-2.5.1}/docs/overrides/.icons/google-colab.svg +0 -0
  87. {easyscience-2.4.0 → easyscience-2.5.1}/docs/overrides/main.html +0 -0
  88. {easyscience-2.4.0 → easyscience-2.5.1}/docs/overrides/partials/logo.html +0 -0
  89. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/Examples/README.rst +0 -0
  90. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/Examples/base/README.rst +0 -0
  91. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/Examples/base/plot_baseclass1.py +0 -0
  92. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/Examples/fitting/README.rst +0 -0
  93. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/PARAMETER_DEPENDENCY_SERIALIZATION.md +0 -0
  94. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/dataset_examples.ipynb +0 -0
  95. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/dimer_example.ipynb +0 -0
  96. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example1.py +0 -0
  97. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example1_dream.py +0 -0
  98. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example2.py +0 -0
  99. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example3.py +0 -0
  100. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example4.py +0 -0
  101. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example5_broken.py +0 -0
  102. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example6_broken.py +0 -0
  103. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example_dataset.py +0 -0
  104. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example_dataset2.py +0 -0
  105. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example_dataset2pt2.py +0 -0
  106. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example_dataset2pt2_broken.py +0 -0
  107. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example_dataset3.py +0 -0
  108. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example_dataset3pt2.py +0 -0
  109. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example_dataset4.py +0 -0
  110. {easyscience-2.4.0 → easyscience-2.5.1}/legacy/examples_old/example_dataset4_2.py +0 -0
  111. {easyscience-2.4.0 → easyscience-2.5.1}/pixi.toml +0 -0
  112. {easyscience-2.4.0 → easyscience-2.5.1}/prettierrc.toml +0 -0
  113. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/__init__.py +0 -0
  114. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/base_classes/__init__.py +0 -0
  115. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/base_classes/based_base.py +0 -0
  116. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/base_classes/collection_base.py +0 -0
  117. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/base_classes/easy_list.py +0 -0
  118. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/base_classes/model_base.py +0 -0
  119. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/base_classes/new_base.py +0 -0
  120. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/base_classes/obj_base.py +0 -0
  121. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/available_minimizers.py +0 -0
  122. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/calculators/__init__.py +0 -0
  123. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/calculators/interface_factory.py +0 -0
  124. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/fitter.py +0 -0
  125. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/bumps_utils/__init__.py +0 -0
  126. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/bumps_utils/eval_counter.py +0 -0
  127. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/bumps_utils/progress_monitor.py +0 -0
  128. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/factory.py +0 -0
  129. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/minimizer_base.py +0 -0
  130. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/minimizer_dfo.py +0 -0
  131. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/minimizer_lmfit.py +0 -0
  132. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/fitting/minimizers/utils.py +0 -0
  133. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/global_object/__init__.py +0 -0
  134. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/global_object/global_object.py +0 -0
  135. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/global_object/hugger/__init__.py +0 -0
  136. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/global_object/hugger/hugger.py +0 -0
  137. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/global_object/hugger/property.py +0 -0
  138. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/global_object/logger.py +0 -0
  139. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/global_object/map.py +0 -0
  140. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/global_object/undo_redo.py +0 -0
  141. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/io/__init__.py +0 -0
  142. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/io/serializer_base.py +0 -0
  143. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/io/serializer_component.py +0 -0
  144. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/io/serializer_dict.py +0 -0
  145. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/job/__init__.py +0 -0
  146. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/job/analysis.py +0 -0
  147. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/job/experiment.py +0 -0
  148. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/job/job.py +0 -0
  149. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/job/theoreticalmodel.py +0 -0
  150. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/legacy/__init__.py +0 -0
  151. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/legacy/collection_base.py +0 -0
  152. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/legacy/dict.py +0 -0
  153. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/legacy/json.py +0 -0
  154. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/legacy/legacy_core.py +0 -0
  155. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/legacy/obj_base.py +0 -0
  156. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/legacy/xml.py +0 -0
  157. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/models/__init__.py +0 -0
  158. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/models/polynomial.py +0 -0
  159. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/utils/__init__.py +0 -0
  160. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/utils/classTools.py +0 -0
  161. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/utils/classUtils.py +0 -0
  162. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/utils/decorators.py +0 -0
  163. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/utils/string.py +0 -0
  164. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/__init__.py +0 -0
  165. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/descriptor_any_type.py +0 -0
  166. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/descriptor_array.py +0 -0
  167. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/descriptor_base.py +0 -0
  168. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/descriptor_bool.py +0 -0
  169. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/descriptor_number.py +0 -0
  170. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/descriptor_str.py +0 -0
  171. {easyscience-2.4.0 → easyscience-2.5.1}/src/easyscience/variable/parameter_dependency_resolver.py +0 -0
  172. {easyscience-2.4.0 → easyscience-2.5.1}/tests/conftest.py +0 -0
  173. {easyscience-2.4.0 → easyscience-2.5.1}/tests/functional/test_smoke.py +0 -0
  174. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/base_classes/__init__.py +0 -0
  175. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/base_classes/test_collection_base.py +0 -0
  176. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/base_classes/test_deprecated_wrappers.py +0 -0
  177. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/base_classes/test_easy_list.py +0 -0
  178. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/base_classes/test_model_base.py +0 -0
  179. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/base_classes/test_new_base.py +0 -0
  180. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/base_classes/test_obj_base.py +0 -0
  181. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/__init__.py +0 -0
  182. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/calculators/__init__.py +0 -0
  183. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/calculators/test_interface_factory.py +0 -0
  184. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/minimizers/__init__.py +0 -0
  185. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/minimizers/test_factory.py +0 -0
  186. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/minimizers/test_minimizer_base.py +0 -0
  187. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/minimizers/test_minimizer_dfo.py +0 -0
  188. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/minimizers/test_minimizer_lmfit.py +0 -0
  189. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/minimizers/test_utils.py +0 -0
  190. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/fitting/test_multi_fitter.py +0 -0
  191. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/global_object/__init__.py +0 -0
  192. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/global_object/test_entry_list_comprehensive.py +0 -0
  193. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/global_object/test_global_object.py +0 -0
  194. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/global_object/test_integration_comprehensive.py +0 -0
  195. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/global_object/test_logger.py +0 -0
  196. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/global_object/test_map.py +0 -0
  197. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/global_object/test_undo_redo_comprehensive.py +0 -0
  198. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/io/test_serializer_base.py +0 -0
  199. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/io/test_serializer_component.py +0 -0
  200. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/io/test_serializer_dict.py +0 -0
  201. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/legacy/__init__.py +0 -0
  202. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/legacy/test_collection_base.py +0 -0
  203. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/legacy/test_dict.py +0 -0
  204. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/legacy/test_json.py +0 -0
  205. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/legacy/test_obj_base.py +0 -0
  206. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/legacy/test_xml.py +0 -0
  207. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/models/__init__.py +0 -0
  208. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/models/test_polynomial.py +0 -0
  209. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/__init__.py +0 -0
  210. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/test_descriptor_any_type.py +0 -0
  211. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/test_descriptor_array.py +0 -0
  212. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/test_descriptor_base.py +0 -0
  213. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/test_descriptor_bool.py +0 -0
  214. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/test_descriptor_number.py +0 -0
  215. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/test_descriptor_str.py +0 -0
  216. {easyscience-2.4.0 → easyscience-2.5.1}/tests/unit/variable/test_parameter_dependency_serialization.py +0 -0
  217. {easyscience-2.4.0 → easyscience-2.5.1}/tools/license_headers.py +0 -0
  218. {easyscience-2.4.0 → easyscience-2.5.1}/tools/update_docs_assets.py +0 -0
  219. {easyscience-2.4.0 → easyscience-2.5.1}/tools/update_github_labels.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easyscience
3
- Version: 2.4.0
3
+ Version: 2.5.1
4
4
  Summary: Core building blocks for EasyScience
5
5
  Project-URL: Documentation, https://easyscience.github.io/core
6
6
  Project-URL: Release Notes, https://github.com/easyscience/core/releases
@@ -21,7 +21,7 @@ Classifier: Programming Language :: Python :: 3.14
21
21
  Classifier: Topic :: Scientific/Engineering
22
22
  Requires-Python: >=3.11
23
23
  Requires-Dist: asteval
24
- Requires-Dist: bumps
24
+ Requires-Dist: bumps>=1.0.4
25
25
  Requires-Dist: dfo-ls
26
26
  Requires-Dist: lmfit
27
27
  Requires-Dist: numpy
@@ -7,7 +7,7 @@
7
7
  "metadata": {},
8
8
  "outputs": [],
9
9
  "source": [
10
- "%matplotlib widget"
10
+ "%matplotlib inline"
11
11
  ]
12
12
  },
13
13
  {
@@ -28,7 +28,7 @@
28
28
  "\n",
29
29
  "where $\\theta$ are the model parameters, $d$ is the observed data, $p(d \\mid \\theta)$ is the likelihood, and $p(\\theta)$ is the prior. In `easyscience`, the `min`/`max` bounds of a `Parameter` are interpreted as a **uniform prior**, and a Gaussian likelihood is constructed from the data and supplied weights.\n",
30
30
  "\n",
31
- "`easyscience` exposes a Bayesian Markov-chain Monte Carlo (MCMC) sampler through the `Fitter.mcmc_sample` method. Under the hood this uses BUMPS' DREAM sampler, so the underlying minimizer must be switched to BUMPS.\n",
31
+ "`easyscience` exposes a Bayesian Markov-chain Monte Carlo (MCMC) sampler through the `Sampler` class. Under the hood this uses BUMPS' DREAM sampler, so the underlying minimizer must be switched to BUMPS.\n",
32
32
  "\n",
33
33
  "```{note}\n",
34
34
  "This tutorial focuses on Bayesian analysis with a simple QENS model for illustration. For dedicated QENS fitting with more sophisticated models, consider using [`EasyDynamics`](https://github.com/easyscience/easydynamics).\n",
@@ -45,7 +45,7 @@
45
45
  "\n",
46
46
  "The trade-off is computational cost: MCMC requires thousands of model evaluations, whereas an MLE fit may converge in dozens. For the simple 4-parameter model used here the difference is negligible, but for expensive models it is worth starting with MLE and only switching to MCMC when you need the richer output.\n",
47
47
  "\n",
48
- "In this tutorial we re-use the QENS dataset and the Lorentzian-with-resolution model from the [Fitting QENS](fitting-qens.ipynb) tutorial, but instead of returning a single best-fit value with a symmetric error bar we will draw thousands of samples from the posterior.\n"
48
+ "In this tutorial we re-use the QENS dataset and the Lorentzian-with-resolution model from the [Fitting QENS](fitting-qens.ipynb) tutorial, but instead of returning a single best-fit value with a symmetric error bar we will draw thousands of samples from the posterior."
49
49
  ]
50
50
  },
51
51
  {
@@ -215,9 +215,20 @@
215
215
  "id": "11",
216
216
  "metadata": {},
217
217
  "source": [
218
- "## Maximum-likelihood fit (for reference)\n",
218
+ "## Maximum-likelihood fit (optional, but recommended)\n",
219
219
  "\n",
220
- "Before running MCMC, perform a quick maximum-likelihood fit. The result will give us a good starting point and lets us compare the central tendency of the posterior with the classical best-fit values.\n"
220
+ "Perform a quick maximum-likelihood fit. This is **not** a prerequisite for sampling: `Sampler`\n",
221
+ "needs a *configured* `Fitter`, not a *fitted* one, and you can sample straight from the initial\n",
222
+ "parameter values.\n",
223
+ "\n",
224
+ "It is worth doing anyway, for two reasons:\n",
225
+ "\n",
226
+ "1. It lets us compare the central tendency of the posterior against the classical best-fit values.\n",
227
+ "2. It gives the chain a much better starting point. DREAM seeds its entire starting population\n",
228
+ " inside a tiny ball around whatever the parameter values happen to be at the time (BUMPS' default\n",
229
+ " `init='eps'`), so sampling from fitted values begins in the right region of parameter space and\n",
230
+ " needs less burn-in to reach the typical set. Starting from a poor initial guess is not wrong, but\n",
231
+ " expect to burn for longer."
221
232
  ]
222
233
  },
223
234
  {
@@ -250,20 +261,20 @@
250
261
  "\n",
251
262
  "We now draw samples from the posterior distribution $p(\\theta \\mid d)$ using the BUMPS DREAM (DiffeRential Evolution Adaptive Metropolis) algorithm. DREAM is an ensemble MCMC method that runs multiple chains in parallel and automatically tunes the proposal distribution.\n",
252
263
  "\n",
253
- "DREAM only works with the BUMPS minimizer. We reuse the ``mle_fitter`` created above, switch it to BUMPS, and call `Fitter.mcmc_sample`, which returns a dictionary with the following keys:\n",
264
+ "DREAM only works with the BUMPS minimizer. We reuse the ``mle_fitter`` created above — any configured `Fitter` would do, and it does not have to have been fitted — switch it to BUMPS, and create a `Sampler` instance bound to the fitter and data. Calling `sampler.sample()` returns a `SamplingResults` object with the following attributes:\n",
254
265
  "\n",
255
- "- `draws`: a `(n_samples, n_parameters)` array of posterior samples: each **row** is one complete draw from the joint posterior (one value for every parameter simultaneously), and each **column** holds all sampled values for a single parameter;\n",
266
+ "- `draws`: a `(n_samples, n_parameters)` array of posterior samples: each **row** is one complete draw from the joint posterior (one value for every parameter simultaneously), and each **column** holds all sampled values for a single parameter. Note this is a *trimmed* view of the chain rather than the raw buffer, so `n_samples` is smaller than `samples / thin` — see the note under [Extend the chain](#extend-the-chain-and-check-convergence);\n",
256
267
  "- `param_names`: the unique names of the parameters, in the same column order as `draws`;\n",
257
- "- `internal_bumps_object`: the underlying BUMPS `MCMCDraw` object, useful for advanced diagnostics;\n",
268
+ "- `state`: the underlying BUMPS `MCMCDraw` object, useful for advanced diagnostics;\n",
258
269
  "- `logp`: the log-posterior of each retained sample.\n",
259
270
  "\n",
260
271
  "The key sampling parameters are:\n",
261
272
  "\n",
262
- "- `samples` (4000): the total number of posterior draws to generate across all chains;\n",
263
- "- `burn` (500): the number of initial *burn-in* iterations to discard — the sampler needs time to find the typical set of the posterior, and early samples are not representative;\n",
264
- "- `thin` (2): the *thinning* interval — only every second sample is kept, which reduces autocorrelation between consecutive draws;\n",
273
+ "- `samples` (10000): the number of raw samples to draw across all chains, *before* thinning. This is a guaranteed minimum rather than an exact count: DREAM advances in blocks of 10 generations (one generation = one draw per chain) and stops at the first block boundary at or past `samples`;\n",
274
+ "- `burn` (500): the number of initial *burn-in* generations to discard — the sampler needs time to find the typical set of the posterior, and early samples are not representative. Note this counts generations, not raw samples, so `burn=500` discards `500 × n_chains` raw samples;\n",
275
+ "- `thin` (2): the *thinning* interval — only every second generation is kept, which reduces autocorrelation between consecutive draws;\n",
265
276
  "\n",
266
- "First, we switch to the BUMPS minimizer:\n"
277
+ "First, we switch to the BUMPS minimizer:"
267
278
  ]
268
279
  },
269
280
  {
@@ -285,17 +296,13 @@
285
296
  "metadata": {},
286
297
  "outputs": [],
287
298
  "source": [
288
- "result = mle_fitter.mcmc_sample(\n",
289
- " x=omega,\n",
290
- " y=intensity_obs,\n",
291
- " weights=1 / intensity_error,\n",
292
- " samples=10000,\n",
293
- " burn=500,\n",
294
- " thin=2,\n",
295
- ")\n",
299
+ "from easyscience.fitting import Sampler\n",
296
300
  "\n",
297
- "print(f'Drew {result[\"draws\"].shape[0]} samples for {result[\"draws\"].shape[1]} parameters.')\n",
298
- "print('parameters:', result['param_names'])"
301
+ "sampler = Sampler(mle_fitter, omega, intensity_obs, weights=1 / intensity_error)\n",
302
+ "results = sampler.sample(samples=10000, burn=500, thin=2)\n",
303
+ "\n",
304
+ "print(f'Drew {results.draws.shape[0]} samples for {results.draws.shape[1]} parameters.')\n",
305
+ "print('parameters:', results.param_names)"
299
306
  ]
300
307
  },
301
308
  {
@@ -320,12 +327,9 @@
320
327
  "metadata": {},
321
328
  "outputs": [],
322
329
  "source": [
323
- "draws = result['draws']\n",
324
- "logp = result['logp']\n",
325
- "if callable(logp):\n",
326
- " _, logp = logp()\n",
327
- " logp = logp.flatten()\n",
328
- "name_to_col = {name: idx for idx, name in enumerate(result['param_names'])}\n",
330
+ "draws = results.draws\n",
331
+ "logp = results.logp\n",
332
+ "name_to_col = {name: idx for idx, name in enumerate(results.param_names)}\n",
329
333
  "\n",
330
334
  "\n",
331
335
  "def column_for(parameter):\n",
@@ -367,7 +371,7 @@
367
371
  "The MLE finds the single point that maximises the likelihood, while the Bayesian median is the central value of the *posterior* — which also accounts for the prior $p(\\theta)$. If a parameter's posterior is skewed (asymmetric), the median and the mode (which approximates the MLE) will not coincide. The table below shows both so you can spot any such differences.\n",
368
372
  "\n",
369
373
  "\n",
370
- "Note that the columns of `result['draws']` are ordered by `result['param_names']` (which use the parameters' `unique_name`), so it is worth building a small helper to look up a column by friendly name.\n"
374
+ "Note that the columns of `results.draws` are ordered by `results.param_names` (which use the parameters' `unique_name`), so it is worth building a small helper to look up a column by friendly name."
371
375
  ]
372
376
  },
373
377
  {
@@ -492,11 +496,206 @@
492
496
  "ax.legend()\n",
493
497
  "plt.show()"
494
498
  ]
499
+ },
500
+ {
501
+ "cell_type": "markdown",
502
+ "id": "03339658",
503
+ "metadata": {},
504
+ "source": [
505
+ "## Extend the chain and check convergence\n",
506
+ "\n",
507
+ "The original run asked for ``samples=10000`` with ``thin=2``. Here we **extend the\n",
508
+ "chain by 5000 more raw samples** using ``sampler.extend()`` — DREAM continues from\n",
509
+ "the previous in-memory state instead of starting from scratch.\n",
510
+ "\n",
511
+ "``sampler.extend(additional_samples=5000)`` does the ring-buffer arithmetic for you\n",
512
+ "automatically: it reads the number of stored generations from the saved state and\n",
513
+ "sizes the new buffer to ``old_generations + additional_samples``, so no existing\n",
514
+ "draws are dropped from the buffer.\n",
515
+ "\n",
516
+ "```{note}\n",
517
+ "`results.draws` grows by less than `additional_samples / thin`, for two unrelated\n",
518
+ "reasons.\n",
519
+ "\n",
520
+ "First, BUMPS post-processes the chain before returning it: with the default\n",
521
+ "`trim=True` it re-runs a burn-point detector over the whole extended chain and\n",
522
+ "returns only the part after the detected burn point, minus any chains flagged as\n",
523
+ "outliers. The detector runs anew on every `sample()` and `extend()` call, so the\n",
524
+ "retained count is not deterministic and can even shrink. This is unrelated to\n",
525
+ "`burn=500`: `extend()` resumes with `burn=0`.\n",
526
+ "\n",
527
+ "Second, `samples` is a minimum, not an exact count. DREAM advances in blocks of\n",
528
+ "10 generations (one generation = one draw per chain - this model has 4 parameters\n",
529
+ "and the default population scale of 10, hence 40 chains) and only checks its\n",
530
+ "stopping condition between blocks, so the chain grows by `additional_samples`\n",
531
+ "rounded up to a multiple of `10 × n_chains` raw draws. Here that is\n",
532
+ "5000 -> 13 blocks of 400 -> 5200 raw draws, i.e. 2600 retained rows at `thin=2`.\n",
533
+ "\n",
534
+ "The full chain is always available via\n",
535
+ "`results.state.draw(portion=1.0, outliers=True)`; pass\n",
536
+ "`sampler_kwargs={'trim': False}` to disable the trimming altogether.\n",
537
+ "```\n",
538
+ "\n",
539
+ "After the extension we compare the posterior summaries and check convergence with\n",
540
+ "Gelman-Rubin R-hat."
541
+ ]
542
+ },
543
+ {
544
+ "cell_type": "code",
545
+ "execution_count": null,
546
+ "id": "293b140b",
547
+ "metadata": {},
548
+ "outputs": [],
549
+ "source": [
550
+ "# Extend the existing chain by 5000 more raw samples.\n",
551
+ "# extend() handles the ring-buffer arithmetic automatically.\n",
552
+ "extended_results = sampler.extend(additional_samples=5000, thin=2)\n",
553
+ "\n",
554
+ "\n",
555
+ "def n_full_chain(res):\n",
556
+ " \"\"\"Rows in the whole chain, before BUMPS' automatic trimming.\"\"\"\n",
557
+ " return res.state.draw(portion=1.0, outliers=True).points.shape[0]\n",
558
+ "\n",
559
+ "\n",
560
+ "print(f'{\"chain\":<10s} {\"trimmed\":>9s} {\"full\":>9s}')\n",
561
+ "print('-' * 30)\n",
562
+ "print(f'{\"original\":<10s} {results.draws.shape[0]:9d} {n_full_chain(results):9d}')\n",
563
+ "print(\n",
564
+ " f'{\"extended\":<10s} {extended_results.draws.shape[0]:9d} {n_full_chain(extended_results):9d}'\n",
565
+ ")\n",
566
+ "\n",
567
+ "grew_by = n_full_chain(extended_results) - n_full_chain(results)\n",
568
+ "print(f'\\nThe full chain grew by {grew_by} draws: the {5000 // 2} we asked for')\n",
569
+ "print('(additional_samples / thin), rounded up to whole DREAM blocks of 10 generations.')\n",
570
+ "print('The \"trimmed\" column is what results.draws exposes: a view, not the chain.')"
571
+ ]
572
+ },
573
+ {
574
+ "cell_type": "code",
575
+ "execution_count": null,
576
+ "id": "9ec4302c",
577
+ "metadata": {},
578
+ "outputs": [],
579
+ "source": [
580
+ "# Build helpers to look up parameter columns.\n",
581
+ "name_to_col_ext = {name: idx for idx, name in enumerate(extended_results.param_names)}\n",
582
+ "name_to_col_orig = {name: idx for idx, name in enumerate(results.param_names)}\n",
583
+ "\n",
584
+ "\n",
585
+ "def col_orig(par):\n",
586
+ " return results.draws[:, name_to_col_orig[par.unique_name]]\n",
587
+ "\n",
588
+ "\n",
589
+ "def col_ext(par):\n",
590
+ " return extended_results.draws[:, name_to_col_ext[par.unique_name]]\n",
591
+ "\n",
592
+ "\n",
593
+ "# Side-by-side posterior summary: the original chain vs the full extended set.\n",
594
+ "lbl_orig = f'original ({results.draws.shape[0]})'\n",
595
+ "lbl_ext = f'extended ({extended_results.draws.shape[0]})'\n",
596
+ "print(f'{\"param\":<10s} {\"metric\":>8s} {lbl_orig:>18s} {lbl_ext:>18s} diff')\n",
597
+ "print('-' * 70)\n",
598
+ "for label, par in (('area', area), ('gamma', gamma), ('omega_0', omega_0), ('sigma', sigma)):\n",
599
+ " c_first = col_orig(par)\n",
600
+ " c_full = col_ext(par)\n",
601
+ " for metric, fn in [\n",
602
+ " ('mean', np.mean),\n",
603
+ " ('std', np.std),\n",
604
+ " ('q2.5%', lambda c: np.percentile(c, 2.5)),\n",
605
+ " ('q50%', lambda c: np.percentile(c, 50)),\n",
606
+ " ('q97.5%', lambda c: np.percentile(c, 97.5)),\n",
607
+ " ]:\n",
608
+ " vf = fn(c_first)\n",
609
+ " vx = fn(c_full)\n",
610
+ " diff = vx - vf\n",
611
+ " print(f'{label:<10s} {metric:>8s} {vf:18.4g} {vx:18.4g} {diff:+.2e}')"
612
+ ]
613
+ },
614
+ {
615
+ "cell_type": "code",
616
+ "execution_count": null,
617
+ "id": "b0f30be6",
618
+ "metadata": {},
619
+ "outputs": [],
620
+ "source": [
621
+ "# Visual comparison: overlay the original chain with the extended set.\n",
622
+ "fig, axes = plt.subplots(1, 4, figsize=(14, 3))\n",
623
+ "for ax, label, par in zip(\n",
624
+ " axes, ('area', 'gamma', 'omega_0', 'sigma'), (area, gamma, omega_0, sigma)\n",
625
+ "):\n",
626
+ " c_first = col_orig(par)\n",
627
+ " c_full = col_ext(par)\n",
628
+ " ax.hist(\n",
629
+ " c_first, bins=40, density=True, alpha=0.5, color='C0', label=f'original ({len(c_first)})'\n",
630
+ " )\n",
631
+ " ax.hist(\n",
632
+ " c_full, bins=40, density=True, alpha=0.5, color='C3', label=f'extended ({len(c_full)})'\n",
633
+ " )\n",
634
+ " ax.set_title(label)\n",
635
+ " ax.set_yticks([])\n",
636
+ "axes[0].legend(fontsize=9)\n",
637
+ "fig.suptitle('Marginal posterior: original chain vs extended chain')\n",
638
+ "plt.tight_layout()\n",
639
+ "plt.show()"
640
+ ]
641
+ },
642
+ {
643
+ "cell_type": "markdown",
644
+ "id": "50b7213a",
645
+ "metadata": {},
646
+ "source": [
647
+ "### What is Gelman-Rubin R-hat?\n",
648
+ "\n",
649
+ "DREAM runs many chains in parallel, each started from a different point. The\n",
650
+ "Gelman-Rubin statistic $\\hat{R}$ compares two variance estimates: $W$, the average\n",
651
+ "variance *within* each chain, and $B$, the variance of the per-chain *means*.\n",
652
+ "\n",
653
+ "$$\n",
654
+ "\\hat{R} \\approx \\sqrt{\\frac{W + B}{W}}\n",
655
+ "$$\n",
656
+ "\n",
657
+ "If all chains sample the same distribution, each chain mean estimates the same\n",
658
+ "posterior mean with standard error $\\sqrt{W/n}$ (for $n$ draws per chain), so\n",
659
+ "$B \\approx W/n$ — negligible next to $W$ — and $\\hat{R} \\to 1$ as the chains grow.\n",
660
+ "If the chains are still drifting toward the posterior, or have settled in different\n",
661
+ "regions of it, their means genuinely disagree, $B$ stays comparable to $W$ or\n",
662
+ "larger, and $\\hat{R}$ sits visibly above 1. (The exact statistic — Gelman & Rubin\n",
663
+ "1992, which is what ``state.gelman()`` computes — adds finite-sample corrections\n",
664
+ "to this; the rule-of-thumb thresholds below are unchanged.)\n",
665
+ "\n",
666
+ "The usual rule of thumb is $\\hat{R} < 1.05$ for **every** parameter; above $\\approx 1.1$\n",
667
+ "the chain should be run for longer. Note that $\\hat{R} \\approx 1$ is *necessary but not\n",
668
+ "sufficient* for convergence: chains can agree with each other and still have all\n",
669
+ "missed the same region of the posterior, so read it alongside the trace plots.\n",
670
+ "\n",
671
+ "Extending a chain should improve convergence, so we print $\\hat{R}$ for the original and\n",
672
+ "the extended chain side by side."
673
+ ]
674
+ },
675
+ {
676
+ "cell_type": "code",
677
+ "execution_count": null,
678
+ "id": "3449e0a7",
679
+ "metadata": {},
680
+ "outputs": [],
681
+ "source": [
682
+ "# Convergence diagnostic: Gelman-Rubin R-hat before and after the extension.\n",
683
+ "# extend() leaves the original chain state untouched, so both can be compared.\n",
684
+ "rhat_short = results.state.gelman()\n",
685
+ "rhat_extended = extended_results.state.gelman()\n",
686
+ "\n",
687
+ "print('Gelman-Rubin R-hat — values < 1.05 indicate convergence:')\n",
688
+ "print(f'{\"parameter\":<22s} {\"short\":>10s} {\"extended\":>10s}')\n",
689
+ "print('-' * 46)\n",
690
+ "for name, r_short, r_ext in zip(extended_results.param_names, rhat_short, rhat_extended):\n",
691
+ " status = '✓' if r_ext < 1.05 else '?' if r_ext < 1.1 else '✗'\n",
692
+ " print(f'{name:<22s} {r_short:10.4f} {r_ext:10.4f} {status}')"
693
+ ]
495
694
  }
496
695
  ],
497
696
  "metadata": {
498
697
  "kernelspec": {
499
- "display_name": "p312",
698
+ "display_name": "era",
500
699
  "language": "python",
501
700
  "name": "python3"
502
701
  },
@@ -510,7 +709,7 @@
510
709
  "name": "python",
511
710
  "nbconvert_exporter": "python",
512
711
  "pygments_lexer": "ipython3",
513
- "version": "3.12.11"
712
+ "version": "3.12.12"
514
713
  }
515
714
  },
516
715
  "nbformat": 4,