pyrecest 2.2.0__tar.gz → 2.2.2__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 (371) hide show
  1. {pyrecest-2.2.0 → pyrecest-2.2.2}/PKG-INFO +1 -1
  2. {pyrecest-2.2.0 → pyrecest-2.2.2}/pyproject.toml +1 -1
  3. pyrecest-2.2.2/src/pyrecest/_backend/_shared_numpy/random.py +51 -0
  4. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/autodiff.py +24 -12
  5. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/random.py +22 -6
  6. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/_so3_helpers.py +30 -4
  7. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_dirac_distribution.py +27 -6
  8. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_grid_distribution.py +4 -4
  9. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_manifold_specific_distribution.py +51 -10
  10. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_mixture.py +39 -8
  11. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_orthogonal_basis_distribution.py +23 -4
  12. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_hypercylindrical_distribution.py +18 -11
  13. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_bounded_cart_prod_distribution.py +1 -1
  14. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/gauss_von_mises_distribution.py +12 -8
  15. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/mardia_sutton_distribution.py +25 -3
  16. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/circular_dirac_distribution.py +4 -2
  17. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/circular_fourier_distribution.py +19 -4
  18. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/circular_grid_distribution.py +3 -0
  19. pyrecest-2.2.2/src/pyrecest/distributions/circle/circular_mixture.py +117 -0
  20. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/sine_skewed_distributions.py +12 -3
  21. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/von_mises_distribution.py +67 -10
  22. pyrecest-2.2.2/src/pyrecest/distributions/circle/wrapped_cauchy_distribution.py +55 -0
  23. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/wrapped_normal_distribution.py +89 -30
  24. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/ellipsoidal_ball_uniform_distribution.py +11 -1
  25. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hyperhemispherical_distribution.py +15 -17
  26. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hypersphere_subset_distribution.py +88 -43
  27. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hypersphere_subset_grid_distribution.py +23 -8
  28. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hyperspherical_distribution.py +18 -9
  29. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_sphere_subset_distribution.py +19 -7
  30. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/bingham_distribution.py +38 -5
  31. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_grid_distribution.py +16 -12
  32. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_watson_distribution.py +11 -9
  33. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperspherical_dirac_distribution.py +8 -7
  34. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperspherical_grid_distribution.py +30 -12
  35. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperspherical_uniform_distribution.py +2 -1
  36. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/spherical_grid_distribution.py +21 -5
  37. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/spherical_harmonics_distribution_complex.py +5 -0
  38. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/von_mises_fisher_distribution.py +137 -40
  39. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/watson_distribution.py +9 -8
  40. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/abstract_hypertoroidal_distribution.py +22 -6
  41. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_dirac_distribution.py +40 -4
  42. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_fourier_distribution.py +54 -23
  43. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_grid_distribution.py +40 -5
  44. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_wrapped_normal_distribution.py +27 -15
  45. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_fourier_distribution.py +3 -4
  46. pyrecest-2.2.2/src/pyrecest/distributions/hypertorus/toroidal_von_mises_cosine_distribution.py +120 -0
  47. pyrecest-2.2.2/src/pyrecest/distributions/hypertorus/toroidal_von_mises_sine_distribution.py +76 -0
  48. pyrecest-2.2.2/src/pyrecest/distributions/hypertorus/toroidal_wrapped_normal_distribution.py +114 -0
  49. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/abstract_linear_distribution.py +47 -12
  50. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/custom_linear_distribution.py +3 -3
  51. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/gaussian_distribution.py +28 -17
  52. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_helpers.py +2 -0
  53. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_product_tangent_gaussian_distribution.py +18 -9
  54. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_tangent_gaussian_distribution.py +19 -13
  55. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/eot_shape_database.py +1 -0
  56. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/evaluate_for_file.py +1 -1
  57. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/perform_predict_update_cycles.py +2 -2
  58. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/__init__.py +114 -3
  59. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/_ukf.py +40 -11
  60. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_particle_filter.py +34 -3
  61. pyrecest-2.2.2/src/pyrecest/filters/association_hypotheses.py +659 -0
  62. pyrecest-2.2.2/src/pyrecest/filters/block_particle_filter.py +506 -0
  63. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/circular_ukf.py +157 -72
  64. pyrecest-2.2.2/src/pyrecest/filters/euclidean_boxed_particle_filter.py +554 -0
  65. pyrecest-2.2.2/src/pyrecest/filters/factorized_giw_random_matrix_tracker.py +256 -0
  66. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperhemisphere_cart_prod_particle_filter.py +9 -4
  67. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperhemispherical_grid_filter.py +6 -6
  68. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperspherical_particle_filter.py +3 -1
  69. pyrecest-2.2.2/src/pyrecest/filters/information_form_distributed_kalman_filter.py +597 -0
  70. pyrecest-2.2.2/src/pyrecest/filters/iterated_batch_mem_qkf_tracker.py +478 -0
  71. pyrecest-2.2.2/src/pyrecest/filters/lomem_tracker.py +604 -0
  72. pyrecest-2.2.2/src/pyrecest/filters/mem_ekf_star_oa_tracker.py +154 -0
  73. pyrecest-2.2.2/src/pyrecest/filters/mem_qkf_tracker.py +610 -0
  74. pyrecest-2.2.2/src/pyrecest/filters/mem_rbpf_tracker.py +682 -0
  75. pyrecest-2.2.2/src/pyrecest/filters/mode_rbpf_manifold_ukf_tracker.py +899 -0
  76. pyrecest-2.2.2/src/pyrecest/filters/multi_bernoulli_mixture_tracker.py +467 -0
  77. pyrecest-2.2.2/src/pyrecest/filters/orientation_vector_eot_tracker.py +670 -0
  78. pyrecest-2.2.2/src/pyrecest/filters/out_of_sequence.py +611 -0
  79. pyrecest-2.2.2/src/pyrecest/filters/partitioned_so3_product_particle_filter.py +7 -0
  80. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/se2_ukf.py +36 -19
  81. pyrecest-2.2.2/src/pyrecest/filters/so3_product_block_particle_filter.py +123 -0
  82. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/unscented_kalman_filter.py +45 -3
  83. pyrecest-2.2.2/src/pyrecest/filters/vbrm_tracker.py +602 -0
  84. pyrecest-2.2.2/src/pyrecest/filters/velocity_aided_mem_qkf_tracker.py +306 -0
  85. pyrecest-2.2.2/src/pyrecest/filters/velocity_locked_mem_qkf_tracker.py +249 -0
  86. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/von_mises_filter.py +3 -1
  87. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/wrapped_normal_filter.py +5 -4
  88. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/__init__.py +78 -0
  89. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/additive_noise.py +18 -0
  90. pyrecest-2.2.2/src/pyrecest/models/motion_models.py +523 -0
  91. pyrecest-2.2.2/src/pyrecest/models/sensor_models.py +352 -0
  92. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/filters.py +4 -6
  93. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/hyperspherical_sampler.py +0 -3
  94. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/leopardi_sampler.py +5 -6
  95. pyrecest-2.2.2/src/pyrecest/smoothers/__init__.py +87 -0
  96. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/abstract_smoother.py +22 -14
  97. pyrecest-2.2.2/src/pyrecest/smoothers/fixed_lag_mem_qkf_smoother.py +1204 -0
  98. pyrecest-2.2.2/src/pyrecest/smoothers/fixed_lag_random_matrix_smoother.py +918 -0
  99. pyrecest-2.2.2/src/pyrecest/smoothers/fixed_lag_velocity_locked_mem_qkf_smoother.py +597 -0
  100. pyrecest-2.2.2/src/pyrecest/smoothers/mem_rbpf_ffbsi_smoother.py +504 -0
  101. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/__init__.py +74 -0
  102. pyrecest-2.2.2/src/pyrecest/utils/metrics.py +681 -0
  103. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/plotting.py +1 -1
  104. pyrecest-2.2.2/src/pyrecest/utils/track_metrics.py +341 -0
  105. pyrecest-2.2.0/src/pyrecest/_backend/_shared_numpy/random.py +0 -29
  106. pyrecest-2.2.0/src/pyrecest/distributions/circle/circular_mixture.py +0 -48
  107. pyrecest-2.2.0/src/pyrecest/distributions/circle/wrapped_cauchy_distribution.py +0 -36
  108. pyrecest-2.2.0/src/pyrecest/distributions/hypertorus/toroidal_von_mises_cosine_distribution.py +0 -86
  109. pyrecest-2.2.0/src/pyrecest/distributions/hypertorus/toroidal_von_mises_sine_distribution.py +0 -40
  110. pyrecest-2.2.0/src/pyrecest/distributions/hypertorus/toroidal_wrapped_normal_distribution.py +0 -133
  111. pyrecest-2.2.0/src/pyrecest/filters/partitioned_so3_product_particle_filter.py +0 -467
  112. pyrecest-2.2.0/src/pyrecest/smoothers/__init__.py +0 -19
  113. pyrecest-2.2.0/src/pyrecest/utils/metrics.py +0 -37
  114. {pyrecest-2.2.0 → pyrecest-2.2.2}/LICENSE +0 -0
  115. {pyrecest-2.2.0 → pyrecest-2.2.2}/README.md +0 -0
  116. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/__init__.py +0 -0
  117. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/.pylintrc +0 -0
  118. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/LICENSE_geomstats +0 -0
  119. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/README.md +0 -0
  120. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/__init__.py +0 -0
  121. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_backend_config.py +0 -0
  122. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_common.py +0 -0
  123. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_dtype_utils.py +0 -0
  124. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_shared_numpy/__init__.py +0 -0
  125. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_shared_numpy/_common.py +0 -0
  126. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_shared_numpy/_dispatch.py +0 -0
  127. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_shared_numpy/linalg.py +0 -0
  128. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/__init__.py +0 -0
  129. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/_common.py +0 -0
  130. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/_dtype.py +0 -0
  131. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/autodiff.py +0 -0
  132. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/linalg.py +0 -0
  133. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/random.py +0 -0
  134. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/__init__.py +0 -0
  135. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/_dtype.py +0 -0
  136. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/fft.py +0 -0
  137. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/linalg.py +0 -0
  138. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/signal.py +0 -0
  139. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/spatial.py +0 -0
  140. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/__init__.py +0 -0
  141. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/_common.py +0 -0
  142. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/_dtype.py +0 -0
  143. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/autodiff.py +0 -0
  144. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/fft.py +0 -0
  145. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/linalg.py +0 -0
  146. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/random.py +0 -0
  147. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/signal.py +0 -0
  148. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/spatial.py +0 -0
  149. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/__init__.py +0 -0
  150. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/_common.py +0 -0
  151. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/_dtype.py +0 -0
  152. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/autodiff.py +0 -0
  153. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/fft.py +0 -0
  154. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/linalg.py +0 -0
  155. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/random.py +0 -0
  156. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/signal.py +0 -0
  157. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/spatial.py +0 -0
  158. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/__init__.py +0 -0
  159. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_bounded_domain_distribution.py +0 -0
  160. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_bounded_nonperiodic_distribution.py +0 -0
  161. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_custom_distribution.py +0 -0
  162. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_custom_nonperiodic_distribution.py +0 -0
  163. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_disk_distribution.py +0 -0
  164. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_distribution_type.py +0 -0
  165. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_ellipsoidal_ball_distribution.py +0 -0
  166. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_nonperiodic_distribution.py +0 -0
  167. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_periodic_distribution.py +0 -0
  168. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_periodic_grid_distribution.py +0 -0
  169. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_se2_distribution.py +0 -0
  170. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_se3_distribution.py +0 -0
  171. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_uniform_distribution.py +0 -0
  172. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/__init__.py +0 -0
  173. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_cart_prod_distribution.py +0 -0
  174. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_custom_lin_bounded_cart_prod_distribution.py +0 -0
  175. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_hemisphere_cart_prod_distribution.py +0 -0
  176. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_hyperhemisphere_cart_prod_distribution.py +0 -0
  177. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_hypersphere_cart_prod_distribution.py +0 -0
  178. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_hypersphere_subset_cart_prod_distribution.py +0 -0
  179. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_periodic_cart_prod_distribution.py +0 -0
  180. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/cart_prod_dirac_distribution.py +0 -0
  181. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/cart_prod_stacked_distribution.py +0 -0
  182. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/custom_hypercylindrical_distribution.py +0 -0
  183. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/hypercylindrical_dirac_distribution.py +0 -0
  184. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/hypercylindrical_state_space_subdivision_distribution.py +0 -0
  185. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/hypercylindrical_state_space_subdivision_gaussian_distribution.py +0 -0
  186. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/hyperhemisphere_cart_prod_dirac_distribution.py +0 -0
  187. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/lin_bounded_cart_prod_dirac_distribution.py +0 -0
  188. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/lin_hypersphere_cart_prod_dirac_distribution.py +0 -0
  189. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/lin_hypersphere_subset_dirac_distribution.py +0 -0
  190. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/lin_periodic_cart_prod_dirac_distribution.py +0 -0
  191. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/partially_wrapped_normal_distribution.py +0 -0
  192. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/se2_bingham_distribution.py +0 -0
  193. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/se2_pwn_distribution.py +0 -0
  194. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/se2_state_space_subdivision_gaussian_distribution.py +0 -0
  195. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/se3_lin_vel_cart_prod_stacked_distribution.py +0 -0
  196. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/state_space_subdivision_distribution.py +0 -0
  197. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/state_space_subdivision_gaussian_distribution.py +0 -0
  198. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/__init__.py +0 -0
  199. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/abstract_circular_distribution.py +0 -0
  200. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/circular_uniform_distribution.py +0 -0
  201. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/custom_circular_distribution.py +0 -0
  202. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/generalized_von_mises_distribution.py +0 -0
  203. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/piecewise_constant_distribution.py +0 -0
  204. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/wrapped_exponential_distribution.py +0 -0
  205. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/wrapped_laplace_distribution.py +0 -0
  206. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/__init__.py +0 -0
  207. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/abstract_conditional_distribution.py +0 -0
  208. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/s2_cond_s2_grid_distribution.py +0 -0
  209. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/sd_cond_sd_grid_distribution.py +0 -0
  210. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/sd_half_cond_sd_half_grid_distribution.py +0 -0
  211. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/td_cond_td_grid_distribution.py +0 -0
  212. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conversion.py +0 -0
  213. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/custom_hyperrectangular_distribution.py +0 -0
  214. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/disk_uniform_distribution.py +0 -0
  215. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/__init__.py +0 -0
  216. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_complex_hyperspherical_distribution.py +0 -0
  217. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hemispherical_distribution.py +0 -0
  218. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hypersphere_subset_dirac_distribution.py +0 -0
  219. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hypersphere_subset_uniform_distribution.py +0 -0
  220. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_spherical_distribution.py +0 -0
  221. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_spherical_harmonics_distribution.py +0 -0
  222. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/bayesian_complex_watson_mixture_model.py +0 -0
  223. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/complex_angular_central_gaussian_distribution.py +0 -0
  224. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/complex_bingham_distribution.py +0 -0
  225. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/complex_watson_distribution.py +0 -0
  226. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/custom_hemispherical_distribution.py +0 -0
  227. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/custom_hyperhemispherical_distribution.py +0 -0
  228. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/custom_hyperspherical_distribution.py +0 -0
  229. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hemispherical_uniform_distribution.py +0 -0
  230. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_bingham_distribution.py +0 -0
  231. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_dirac_distribution.py +0 -0
  232. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_uniform_distribution.py +0 -0
  233. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperspherical_mixture.py +0 -0
  234. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/spherical_harmonics_distribution_real.py +0 -0
  235. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/__init__.py +0 -0
  236. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/abstract_toroidal_bivar_vm_distribution.py +0 -0
  237. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/abstract_toroidal_distribution.py +0 -0
  238. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/custom_hypertoroidal_distribution.py +0 -0
  239. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/custom_toroidal_distribution.py +0 -0
  240. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_mixture.py +0 -0
  241. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_uniform_distribution.py +0 -0
  242. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_dirac_distribution.py +0 -0
  243. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_mixture.py +0 -0
  244. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_uniform_distribution.py +0 -0
  245. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_vm_matrix_distribution.py +0 -0
  246. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_vm_rivest_distribution.py +0 -0
  247. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/__init__.py +0 -0
  248. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/abstract_hyperrectangular_distribution.py +0 -0
  249. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/gaussian_mixture.py +0 -0
  250. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/hyperrectangular_uniform_distribution.py +0 -0
  251. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/linear_box_particle_distribution.py +0 -0
  252. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/linear_dirac_distribution.py +0 -0
  253. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/linear_mixture.py +0 -0
  254. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/se2_dirac_distribution.py +0 -0
  255. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/se3_cart_prod_stacked_distribution.py +0 -0
  256. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/se3_dirac_distribution.py +0 -0
  257. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_bingham_distribution.py +0 -0
  258. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_conversion.py +0 -0
  259. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_dirac_distribution.py +0 -0
  260. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_product_dirac_distribution.py +0 -0
  261. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_uniform_distribution.py +0 -0
  262. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/__init__.py +0 -0
  263. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/check_and_fix_config.py +0 -0
  264. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/configure_for_filter.py +0 -0
  265. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/determine_all_deviations.py +0 -0
  266. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/evaluate_for_simulation_config.py +0 -0
  267. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/evaluate_for_variables.py +0 -0
  268. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/generate_groundtruth.py +0 -0
  269. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/generate_measurements.py +0 -0
  270. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/generate_simulated_scenarios.py +0 -0
  271. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/get_axis_label.py +0 -0
  272. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/get_distance_function.py +0 -0
  273. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/get_extract_mean.py +0 -0
  274. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/group_results_by_filter.py +0 -0
  275. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/iterate_configs_and_runs.py +0 -0
  276. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/plot_results.py +0 -0
  277. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/simulation_database.py +0 -0
  278. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/summarize_filter_results.py +0 -0
  279. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/_linear_gaussian.py +0 -0
  280. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_axial_filter.py +0 -0
  281. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_circular_filter.py +0 -0
  282. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_dummy_filter.py +0 -0
  283. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_extended_object_tracker.py +0 -0
  284. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_filter.py +0 -0
  285. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_grid_filter.py +0 -0
  286. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_multiple_extended_object_tracker.py +0 -0
  287. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_multitarget_tracker.py +0 -0
  288. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_nearest_neighbor_tracker.py +0 -0
  289. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_tracker_with_logging.py +0 -0
  290. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/axial_kalman_filter.py +0 -0
  291. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/bingham_filter.py +0 -0
  292. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/circular_fourier_filter.py +0 -0
  293. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/circular_particle_filter.py +0 -0
  294. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/ekf_spline_tracker.py +0 -0
  295. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/euclidean_box_particle_filter.py +0 -0
  296. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/euclidean_particle_filter.py +0 -0
  297. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/fourier_rhm_tracker.py +0 -0
  298. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/gaussian_mixture_phd_filter.py +0 -0
  299. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/ggiw_tracker.py +0 -0
  300. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/global_nearest_neighbor.py +0 -0
  301. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/goal_conditioned_replay_imm_filter.py +0 -0
  302. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/goal_conditioned_replay_particle_filter.py +0 -0
  303. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/goal_conditioned_replay_particle_imm_filter.py +0 -0
  304. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/gprhm_tracker.py +0 -0
  305. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hypercylindrical_particle_filter.py +0 -0
  306. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperhemispherical_particle_filter.py +0 -0
  307. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperspherical_dummy_filter.py +0 -0
  308. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperspherical_ukf.py +0 -0
  309. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hypertoroidal_dummy_filter.py +0 -0
  310. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hypertoroidal_fourier_filter.py +0 -0
  311. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hypertoroidal_particle_filter.py +0 -0
  312. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/interacting_multiple_model_filter.py +0 -0
  313. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/joint_probabilistic_data_association_filter.py +0 -0
  314. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/kalman_filter.py +0 -0
  315. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/kernel_sme_filter.py +0 -0
  316. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/lin_bounded_particle_filter.py +0 -0
  317. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/lin_periodic_particle_filter.py +0 -0
  318. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/manifold_exponential_moving_average.py +0 -0
  319. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/manifold_mixins.py +0 -0
  320. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/mem_ekf_star_tracker.py +0 -0
  321. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/mem_ekf_tracker.py +0 -0
  322. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/mem_soekf_tracker.py +0 -0
  323. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/multi_bernoulli_tracker.py +0 -0
  324. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/multi_hypothesis_tracker.py +0 -0
  325. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/piecewise_constant_filter.py +0 -0
  326. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/random_matrix_tracker.py +0 -0
  327. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/relaxed_s3f_circular.py +0 -0
  328. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/relaxed_s3f_so3.py +0 -0
  329. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/so3_grid_transition.py +0 -0
  330. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/so3_product_particle_filter.py +0 -0
  331. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/spherical_harmonics_eot_tracker.py +0 -0
  332. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/spherical_harmonics_filter.py +0 -0
  333. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/state_space_subdivision_filter.py +0 -0
  334. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/toroidal_particle_filter.py +0 -0
  335. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/toroidal_wrapped_normal_filter.py +0 -0
  336. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/track_manager.py +0 -0
  337. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/ukf_on_manifolds.py +0 -0
  338. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/von_mises_fisher_filter.py +0 -0
  339. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/adapters.py +0 -0
  340. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/grid.py +0 -0
  341. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/likelihood.py +0 -0
  342. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/linear_gaussian.py +0 -0
  343. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/particle.py +0 -0
  344. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/validation.py +0 -0
  345. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/__init__.py +0 -0
  346. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/common.py +0 -0
  347. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/models.py +0 -0
  348. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/testing.py +0 -0
  349. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/py.typed +0 -0
  350. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/__init__.py +0 -0
  351. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/abstract_sampler.py +0 -0
  352. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/euclidean_sampler.py +0 -0
  353. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/hypertoroidal_sampler.py +0 -0
  354. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/sigma_points.py +0 -0
  355. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/rauch_tung_striebel_smoother.py +0 -0
  356. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/sliding_window_manifold_mean_smoother.py +0 -0
  357. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/so3_chordal_mean_smoother.py +0 -0
  358. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/unscented_rauch_tung_striebel_smoother.py +0 -0
  359. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/_point_set_registration_common.py +0 -0
  360. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/assignment.py +0 -0
  361. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/association_features.py +0 -0
  362. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/association_models.py +0 -0
  363. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/history_recorder.py +0 -0
  364. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/multisession_assignment.py +0 -0
  365. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/multisession_assignment_observation_costs.py +0 -0
  366. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/multisession_assignment_score.py +0 -0
  367. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/nonrigid_point_set_registration.py +0 -0
  368. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/pairwise_covariance_features.py +0 -0
  369. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/point_set_registration.py +0 -0
  370. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/roi_assignment.py +0 -0
  371. {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/track_evaluation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrecest
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: Framework for recursive Bayesian estimation in Python.
5
5
  License-File: LICENSE
6
6
  Author: Florian Pfaff
@@ -3,7 +3,7 @@ name = "pyrecest"
3
3
  description = "Framework for recursive Bayesian estimation in Python."
4
4
  readme = "README.md"
5
5
  authors = ["Florian Pfaff <pfaff@ias.uni-stuttgart.de>"]
6
- version = "2.2.0"
6
+ version = "2.2.2"
7
7
 
8
8
  [build-system]
9
9
  requires = ["poetry-core>=2.0.0,<3.0.0"]
@@ -0,0 +1,51 @@
1
+ from ._dispatch import _common
2
+ from ._dispatch import numpy as _np
3
+
4
+ _modify_func_default_dtype = _common._modify_func_default_dtype
5
+ _allow_complex_dtype = _common._allow_complex_dtype
6
+
7
+
8
+ rand = _modify_func_default_dtype(
9
+ copy=False, kw_only=True, target=_allow_complex_dtype(target=_np.random.rand)
10
+ )
11
+
12
+ uniform = _modify_func_default_dtype(
13
+ copy=False, kw_only=True, target=_allow_complex_dtype(target=_np.random.uniform)
14
+ )
15
+
16
+
17
+ normal = _modify_func_default_dtype(
18
+ copy=False, kw_only=True, target=_allow_complex_dtype(target=_np.random.normal)
19
+ )
20
+
21
+ multivariate_normal = _modify_func_default_dtype(
22
+ copy=False,
23
+ kw_only=True,
24
+ target=_allow_complex_dtype(target=_np.random.multivariate_normal),
25
+ )
26
+
27
+
28
+ def choice(a, size=None, replace=True, p=None, axis=0, shuffle=True):
29
+ """Draw samples using NumPy's seeded global random state.
30
+
31
+ ``numpy.random.Generator.choice`` supports sampling rows from a multidimensional
32
+ array, but it is independent of ``numpy.random.seed`` when a fresh generator is
33
+ created for every call. The backend exposes ``random.seed``/``get_state`` from
34
+ ``numpy.random``, so this wrapper samples indices through the seeded legacy RNG
35
+ and then gathers along ``axis`` for multidimensional inputs.
36
+ """
37
+ del shuffle # ``numpy.random.choice`` has no equivalent shuffle argument.
38
+
39
+ a_array = _np.asarray(a)
40
+ if a_array.ndim == 0:
41
+ return _np.random.choice(a, size=size, replace=replace, p=p)
42
+
43
+ axis = axis % a_array.ndim
44
+ if a_array.ndim == 1 and axis == 0:
45
+ return _np.random.choice(a_array, size=size, replace=replace, p=p)
46
+
47
+ if p is not None:
48
+ p = _np.asarray(p)
49
+
50
+ indices = _np.random.choice(a_array.shape[axis], size=size, replace=replace, p=p)
51
+ return _np.take(a_array, indices, axis=axis)
@@ -6,10 +6,9 @@ https://github.com/oxcsml/geomstats/blob/master/geomstats/_backend/jax/autodiff.
6
6
 
7
7
 
8
8
  import jax.numpy as anp
9
- from jax import vmap, grad
10
- from jax import jacfwd
11
- from jax import value_and_grad as _value_and_grad
12
9
  from autograd.extend import defvjp, primitive # TODO: replace
10
+ from jax import grad, jacfwd
11
+ from jax import value_and_grad as _value_and_grad
13
12
 
14
13
 
15
14
  def detach(x):
@@ -33,7 +32,14 @@ def elementwise_grad(func):
33
32
  func : callable
34
33
  Function for which the element-wise grad is computed.
35
34
  """
36
- return vmap(grad(func))(func) # NOTE: cf https://github.com/google/jax/issues/564
35
+
36
+ def _elementwise_grad(*args, **kwargs):
37
+ def _summed_func(*inner_args):
38
+ return anp.sum(func(*inner_args, **kwargs))
39
+
40
+ return grad(_summed_func)(*args)
41
+
42
+ return _elementwise_grad
37
43
 
38
44
 
39
45
  def custom_gradient(*grad_funcs):
@@ -116,14 +122,20 @@ def value_and_grad(func, to_numpy=False):
116
122
 
117
123
  return aux_value_and_grad
118
124
 
125
+
119
126
  unsupported_functions = [
120
- 'hessian',
121
- 'hessian_vec',
122
- 'jacobian_vec',
123
- 'jacobian_and_hessian',
124
- 'value_jacobian_and_hessian',
125
- 'value_and_jacobian',
127
+ "hessian",
128
+ "hessian_vec",
129
+ "jacobian_vec",
130
+ "jacobian_and_hessian",
131
+ "value_jacobian_and_hessian",
132
+ "value_and_jacobian",
126
133
  ]
127
- for func_name in unsupported_functions:
128
- exec(f"{func_name} = lambda *args, **kwargs: NotImplementedError('This function is not supported in this JAX backend.')")
129
134
 
135
+
136
+ def _raise_unsupported(*args, **kwargs):
137
+ raise NotImplementedError("This function is not supported in this JAX backend.")
138
+
139
+
140
+ for func_name in unsupported_functions:
141
+ globals()[func_name] = _raise_unsupported
@@ -120,15 +120,31 @@ def choice(a, n, *args, **kwargs):
120
120
  return set_state_return(has_state, state, res)
121
121
 
122
122
 
123
- def _multivariate_normal(state, size, *args, **kwargs):
124
- state, key = jax.random.split(state)
125
- return state, jax.random.multivariate_normal(key, shape=size, *args, **kwargs)
123
+ def _shape_from_size(size):
124
+ """Convert a NumPy-style ``size`` argument to JAX's ``shape`` argument."""
125
+ if size is None:
126
+ return None
127
+ if hasattr(size, "__iter__"):
128
+ return tuple(int(dim) for dim in size)
129
+ return (int(size),)
126
130
 
127
131
 
128
- def multivariate_normal(size, *args, **kwargs):
129
- size = size if hasattr(size, "__iter__") else (size,)
132
+ def _multivariate_normal(state, mean, cov, size=None, *args, **kwargs):
133
+ state, key = jax.random.split(state)
134
+ if "shape" in kwargs:
135
+ if size is not None:
136
+ raise TypeError("Specify only one of 'size' or 'shape'.")
137
+ size = kwargs.pop("shape")
138
+ shape = _shape_from_size(size)
139
+ return state, jax.random.multivariate_normal(
140
+ key, mean, cov, shape, *args, **kwargs
141
+ )
142
+
143
+
144
+ def multivariate_normal(mean, cov, size=None, *args, **kwargs):
145
+ """Draw samples with NumPy-compatible ``multivariate_normal`` arguments."""
130
146
  state, has_state, kwargs = _get_state(**kwargs)
131
- state, res = _multivariate_normal(state, size, *args, **kwargs)
147
+ state, res = _multivariate_normal(state, mean, cov, size, *args, **kwargs)
132
148
  return set_state_return(has_state, state, res)
133
149
 
134
150
 
@@ -11,6 +11,7 @@ from pyrecest.backend import (
11
11
  concatenate,
12
12
  cos,
13
13
  linalg,
14
+ log,
14
15
  ndim,
15
16
  reshape,
16
17
  sin,
@@ -72,6 +73,28 @@ def quaternion_multiply(left, right):
72
73
  return normalize_quaternions(product)
73
74
 
74
75
 
76
+ def so3_exp_map_volume_log_jacobian(tangent_vectors):
77
+ """Return the SO(3) exponential-map volume log-Jacobian.
78
+
79
+ For scalar-last unit quaternions with the canonical ``w >= 0`` sign, the
80
+ principal rotation-vector chart maps the ball ``||v|| <= pi`` to the upper
81
+ unit-quaternion half sphere. With ``theta = ||v||``, its volume element is
82
+
83
+ dV = sin(theta / 2)^2 / (2 * theta^2) dv,
84
+
85
+ with limiting value ``1 / 8`` at the identity. The returned value is
86
+ ``log(dV / dv)`` and preserves all leading dimensions of ``tangent_vectors``.
87
+ """
88
+ tangent_vectors = array(tangent_vectors, dtype=float)
89
+ assert tangent_vectors.shape[-1] == 3, "SO(3) tangent vectors must have length 3."
90
+
91
+ angles = linalg.norm(tangent_vectors, axis=-1)
92
+ safe_angles = where(angles > 1e-8, angles, 1.0)
93
+ direct = 2.0 * (log(sin(0.5 * safe_angles)) - log(safe_angles)) - log(2.0)
94
+ small_angle_series = -log(8.0) - angles**2 / 12.0 - angles**4 / 1440.0
95
+ return where(angles > 1e-8, direct, small_angle_series)
96
+
97
+
75
98
  def exp_map_identity(tangent_vectors):
76
99
  """Map SO(3) tangent vectors at identity to scalar-last quaternions."""
77
100
  tangent_vectors = array(tangent_vectors, dtype=float)
@@ -107,10 +130,13 @@ def log_map_identity(rotations):
107
130
  angles = 2.0 * arctan2(vector_norm, scalar_part)
108
131
  vector_norm_col = reshape(vector_norm, tuple(vector_norm.shape) + (1,))
109
132
  safe_norm = where(vector_norm_col > 1e-12, vector_norm_col, 1.0)
110
- scale = where(
111
- vector_norm_col > 1e-12,
112
- reshape(angles, tuple(angles.shape) + (1,)) / safe_norm,
113
- 2.0,
133
+ scale = (
134
+ where(
135
+ vector_norm_col > 1e-12,
136
+ reshape(angles, tuple(angles.shape) + (1,)),
137
+ 2.0 * safe_norm,
138
+ )
139
+ / safe_norm
114
140
  )
115
141
  return vector_part * scale
116
142
 
@@ -9,10 +9,12 @@ from beartype import beartype
9
9
  from pyrecest.backend import (
10
10
  all,
11
11
  apply_along_axis,
12
+ arange,
12
13
  argmax,
13
14
  int32,
14
15
  int64,
15
16
  isclose,
17
+ isfinite,
16
18
  log,
17
19
  ones,
18
20
  random,
@@ -42,13 +44,31 @@ class AbstractDiracDistribution(AbstractDistributionType):
42
44
  self.w = copy.copy(w)
43
45
  self.normalize_in_place()
44
46
 
47
+ @staticmethod
48
+ def _validate_weights(w):
49
+ """
50
+ Validate Dirac weights and return their total mass.
51
+ """
52
+ if not bool(all(isfinite(w))):
53
+ raise ValueError("Dirac weights must be finite.")
54
+
55
+ if not bool(all(w >= 0)):
56
+ raise ValueError("Dirac weights must be nonnegative.")
57
+
58
+ total_weight = sum(w)
59
+ if not bool(isfinite(total_weight)) or not bool(total_weight > 0):
60
+ raise ValueError("Dirac weights must have positive finite total mass.")
61
+
62
+ return total_weight
63
+
45
64
  def normalize_in_place(self):
46
65
  """
47
66
  Normalize the weights in-place to ensure they sum to 1.
48
67
  """
49
- if not isclose(sum(self.w), 1.0, atol=1e-10):
68
+ total_weight = self._validate_weights(self.w)
69
+ if not isclose(total_weight, 1.0, atol=1e-10):
50
70
  warnings.warn("Weights are not normalized.", RuntimeWarning)
51
- self.w = self.w / sum(self.w)
71
+ self.w = self.w / total_weight
52
72
 
53
73
  def normalize(self) -> "AbstractDiracDistribution":
54
74
  dist = copy.deepcopy(self)
@@ -75,16 +95,17 @@ class AbstractDiracDistribution(AbstractDistributionType):
75
95
  w_new = f(dist.d)
76
96
 
77
97
  assert w_new.shape == dist.w.shape, "Function returned wrong output dimensions."
78
- assert all(w_new >= 0), "All weights should be greater than or equal to 0."
79
- assert sum(w_new) > 0, "The sum of all weights should be greater than 0."
98
+ self._validate_weights(w_new)
80
99
 
81
100
  dist.w = w_new * dist.w
82
- dist.w = dist.w / sum(dist.w)
101
+ total_weight = self._validate_weights(dist.w)
102
+ dist.w = dist.w / total_weight
83
103
 
84
104
  return dist
85
105
 
86
106
  def sample(self, n: Union[int, int32, int64]):
87
- samples = random.choice(self.d, n, p=self.w)
107
+ indices = random.choice(arange(self.d.shape[0]), n, p=self.w)
108
+ samples = self.d[indices]
88
109
  return samples
89
110
 
90
111
  def entropy(self) -> float:
@@ -74,14 +74,14 @@ class AbstractGridDistribution(AbstractDistributionType):
74
74
 
75
75
  def normalize_in_place(self, tol=1e-4, warn_unnorm=True):
76
76
  int_val = self.integrate()
77
+ if float(abs(int_val)) < 1e-200:
78
+ raise ValueError(
79
+ "Sum of grid values is too close to zero, this usually points to a user error."
80
+ )
77
81
  if any(self.grid_values < 0):
78
82
  warnings.warn(
79
83
  "Warning: There are negative values. This usually points to a user error."
80
84
  )
81
- elif abs(int_val) < 1e-200:
82
- raise ValueError(
83
- "Sum of grid values is too close to zero, this usually points to a user error."
84
- )
85
85
  elif abs(int_val - 1) > tol:
86
86
  if warn_unnorm:
87
87
  warnings.warn(
@@ -9,6 +9,16 @@ import pyrecest.backend
9
9
  from pyrecest.backend import empty, int32, int64, log, random, squeeze
10
10
 
11
11
 
12
+ def _to_scalar(value):
13
+ """Convert a backend scalar or length-one array to a Python float."""
14
+ try:
15
+ return float(value.item())
16
+ except AttributeError:
17
+ return float(value)
18
+ except (TypeError, ValueError, RuntimeError):
19
+ return float(value.reshape(-1)[0])
20
+
21
+
12
22
  class AbstractManifoldSpecificDistribution(ABC):
13
23
  """
14
24
  Abstract base class for distributions catering to specific manifolds.
@@ -98,7 +108,7 @@ class AbstractManifoldSpecificDistribution(ABC):
98
108
  return self.sample_metropolis_hastings(n)
99
109
 
100
110
  # jscpd:ignore-start
101
- # pylint: disable=too-many-positional-arguments,too-many-locals
111
+ # pylint: disable=too-many-positional-arguments,too-many-locals,too-many-arguments
102
112
  def sample_metropolis_hastings(
103
113
  self,
104
114
  n: Union[int, int32, int64],
@@ -106,9 +116,19 @@ class AbstractManifoldSpecificDistribution(ABC):
106
116
  skipping: Union[int, int32, int64] = 5,
107
117
  proposal: Callable | None = None,
108
118
  start_point=None,
119
+ proposal_log_pdf: Callable | None = None,
109
120
  ):
110
121
  # jscpd:ignore-end
111
- """Metropolis Hastings sampling algorithm."""
122
+ """Metropolis-Hastings sampling algorithm.
123
+
124
+ ``proposal`` generates a candidate state from the current state. For
125
+ non-JAX backends it must be callable as ``proposal(x)``; for JAX it
126
+ must be callable as ``proposal(key, x)``.
127
+
128
+ ``proposal_log_pdf`` is optional and must evaluate
129
+ ``log q(candidate | current)``. If it is omitted, the proposal is
130
+ assumed symmetric, recovering the ordinary Metropolis ratio.
131
+ """
112
132
  if pyrecest.backend.__backend_name__ == "jax":
113
133
  # Get a key from your global JAX random state *outside* of lax.scan
114
134
  import jax as _jax # pylint: disable=import-error
@@ -132,6 +152,7 @@ class AbstractManifoldSpecificDistribution(ABC):
132
152
  n=int(n),
133
153
  burn_in=int(burn_in),
134
154
  skipping=int(skipping),
155
+ proposal_log_pdf=proposal_log_pdf,
135
156
  )
136
157
  # You could optionally stash `key_out` somewhere if you want chain continuation.
137
158
  return squeeze(samples)
@@ -146,20 +167,30 @@ class AbstractManifoldSpecificDistribution(ABC):
146
167
  s = empty((total_samples, self.input_dim))
147
168
  x = start_point
148
169
  i = 0
149
- pdfx = self.pdf(x)
170
+ log_pdfx = _to_scalar(self.ln_pdf(x))
150
171
 
151
172
  while i < total_samples:
152
173
  x_new = proposal(x)
153
174
  assert (
154
175
  x_new.shape == x.shape
155
176
  ), "Proposal must return a vector of same shape as input"
156
- pdfx_new = self.pdf(x_new)
157
- a = pdfx_new / pdfx
158
- if a.item() > 1 or a.item() > random.rand(1):
159
- s[i, :] = x_new.squeeze()
177
+ log_pdfx_new = _to_scalar(self.ln_pdf(x_new))
178
+ log_acceptance_ratio = log_pdfx_new - log_pdfx
179
+
180
+ if proposal_log_pdf is not None:
181
+ log_acceptance_ratio += _to_scalar(
182
+ proposal_log_pdf(x, x_new)
183
+ ) - _to_scalar(proposal_log_pdf(x_new, x))
184
+
185
+ if (
186
+ log_acceptance_ratio >= 0.0
187
+ or _to_scalar(log(random.rand(1))) < log_acceptance_ratio
188
+ ):
160
189
  x = x_new
161
- pdfx = pdfx_new
162
- i += 1
190
+ log_pdfx = log_pdfx_new
191
+ # Record every chain step; rejected proposals keep the current state.
192
+ s[i, :] = x.squeeze()
193
+ i += 1
163
194
 
164
195
  relevant_samples = s[burn_in::skipping, :]
165
196
  return squeeze(relevant_samples)
@@ -174,6 +205,8 @@ def sample_metropolis_hastings_jax(
174
205
  n: int,
175
206
  burn_in: int = 10,
176
207
  skipping: int = 5,
208
+ # function: (candidate, current) -> log q(candidate | current)
209
+ proposal_log_pdf=None,
177
210
  ):
178
211
  """
179
212
  Metropolis-Hastings sampler in JAX using a plain Python loop.
@@ -186,6 +219,8 @@ def sample_metropolis_hastings_jax(
186
219
  proposal: callable (key, x) -> x_proposed
187
220
  start_point: initial state (array)
188
221
  n: number of samples to return (after burn-in and thinning)
222
+ proposal_log_pdf: optional callable evaluating log q(candidate | current).
223
+ If omitted, the proposal is assumed symmetric.
189
224
  """
190
225
  import jax.numpy as _jnp # pylint: disable=import-error
191
226
  from jax import random as _random # pylint: disable=import-error
@@ -209,8 +244,14 @@ def sample_metropolis_hastings_jax(
209
244
  x_prop = proposal(key_prop, x)
210
245
  log_px_prop = _to_scalar(log_pdf(x_prop))
211
246
 
212
- # Metropolis acceptance
247
+ # Metropolis-Hastings acceptance. The proposal correction vanishes for
248
+ # symmetric proposals.
213
249
  log_alpha = log_px_prop - log_px
250
+ if proposal_log_pdf is not None:
251
+ log_alpha += _to_scalar(proposal_log_pdf(x, x_prop)) - _to_scalar(
252
+ proposal_log_pdf(x_prop, x)
253
+ )
254
+
214
255
  log_u = _to_scalar(_jnp.log(_random.uniform(key_u, shape=())))
215
256
 
216
257
  if log_u < min(0.0, log_alpha):
@@ -7,12 +7,14 @@ import pyrecest.backend
7
7
 
8
8
  # pylint: disable=redefined-builtin,no-name-in-module,no-member
9
9
  from pyrecest.backend import (
10
- count_nonzero,
10
+ array,
11
+ asarray,
11
12
  empty,
12
13
  int32,
13
14
  int64,
14
15
  ones,
15
16
  random,
17
+ reshape,
16
18
  sum,
17
19
  zeros,
18
20
  )
@@ -39,21 +41,29 @@ class AbstractMixture(AbstractDistributionType):
39
41
 
40
42
  if weights is None:
41
43
  weights = ones(num_distributions) / num_distributions
44
+ else:
45
+ weights = asarray(weights)
42
46
 
43
47
  if num_distributions != len(weights):
44
48
  raise ValueError("Sizes of distributions and weights must be equal")
45
49
 
50
+ if any(bool(weight < 0) for weight in weights):
51
+ raise ValueError("Mixture weights must be nonnegative")
52
+
46
53
  if not all(dists[0].dim == dist.dim for dist in dists):
47
54
  raise ValueError("All distributions must have the same dimension")
48
55
 
49
- non_zero_indices = count_nonzero(weights)
56
+ non_zero_indices = [i for i, weight in enumerate(weights) if bool(weight != 0)]
50
57
 
51
- if non_zero_indices < len(weights):
58
+ if len(non_zero_indices) == 0:
59
+ raise ValueError("At least one mixture weight must be nonzero")
60
+
61
+ if len(non_zero_indices) < len(weights):
52
62
  warnings.warn(
53
63
  "Elements with zero weights detected. Pruning elements in mixture with weight zero."
54
64
  )
55
65
  dists = [dists[i] for i in non_zero_indices]
56
- weights = weights[non_zero_indices]
66
+ weights = weights[array(non_zero_indices, dtype=int64)]
57
67
 
58
68
  self.dists = dists
59
69
 
@@ -67,6 +77,17 @@ class AbstractMixture(AbstractDistributionType):
67
77
  def input_dim(self) -> int:
68
78
  return self.dists[0].input_dim
69
79
 
80
+ def _as_sample_matrix(self, samples, n_samples: int):
81
+ samples = asarray(samples)
82
+
83
+ if self.input_dim == 1 and samples.ndim == 0:
84
+ return reshape(samples, (1, 1))
85
+
86
+ if self.input_dim == 1 and samples.ndim == 1:
87
+ return reshape(samples, (n_samples, 1))
88
+
89
+ return pyrecest.backend.atleast_2d(samples)
90
+
70
91
  def sample(self, n: Union[int, int32, int64]):
71
92
  occurrences = random.multinomial(n, self.w)
72
93
  if pyrecest.backend.__backend_name__ == "jax":
@@ -78,7 +99,7 @@ class AbstractMixture(AbstractDistributionType):
78
99
  sample_i = self.dists[i].sample(occ_val)
79
100
  except (NotImplementedError, AssertionError, ValueError, TypeError):
80
101
  sample_i = self.dists[i].sample_metropolis_hastings(occ_val)
81
- sample_i = pyrecest.backend.atleast_2d(sample_i)
102
+ sample_i = self._as_sample_matrix(sample_i, occ_val)
82
103
  samples.append(sample_i)
83
104
  if not samples:
84
105
  return empty((0, self.input_dim))
@@ -89,15 +110,25 @@ class AbstractMixture(AbstractDistributionType):
89
110
  for i, occ in enumerate(occurrences):
90
111
  occ_val = occ.item() if hasattr(occ, "item") else int(occ)
91
112
  if occ_val != 0:
92
- s[count : count + occ_val] = self.dists[i].sample(occ_val) # noqa: E203
113
+ sample_i = self._as_sample_matrix(
114
+ self.dists[i].sample(occ_val), occ_val
115
+ )
116
+ s[count : count + occ_val] = sample_i # noqa: E203
93
117
  count += occ_val
94
118
 
95
119
  return s
96
120
 
97
121
  def pdf(self, xs):
98
- assert xs.shape[-1] == self.input_dim, "Dimension mismatch"
122
+ xs = asarray(xs)
99
123
 
100
- p = zeros(1) if xs.ndim == 1 else zeros(xs.shape[0])
124
+ if self.input_dim == 1 and xs.ndim <= 1:
125
+ # For one-dimensional distributions, a flat array represents a batch
126
+ # of scalar evaluation points. This matches GaussianDistribution.pdf
127
+ # and avoids rejecting natural inputs such as xs.shape == (n,).
128
+ p = zeros(xs.shape)
129
+ else:
130
+ assert xs.shape[-1] == self.input_dim, "Dimension mismatch"
131
+ p = zeros(1) if xs.ndim == 1 else zeros(xs.shape[0])
101
132
 
102
133
  for i, dist in enumerate(self.dists):
103
134
  p += self.w[i] * dist.pdf(xs)
@@ -4,10 +4,13 @@ from abc import abstractmethod
4
4
 
5
5
  # pylint: disable=redefined-builtin,no-name-in-module,no-member
6
6
  # pylint: disable=no-name-in-module,no-member
7
+ from pyrecest.backend import abs as backend_abs
7
8
  from pyrecest.backend import all, exp, imag, real
8
9
 
9
10
  from .abstract_distribution_type import AbstractDistributionType
10
11
 
12
+ _REAL_DENSITY_IMAG_TOL = 1e-10
13
+
11
14
 
12
15
  class AbstractOrthogonalBasisDistribution(AbstractDistributionType):
13
16
  """
@@ -48,6 +51,23 @@ class AbstractOrthogonalBasisDistribution(AbstractDistributionType):
48
51
  result = copy.deepcopy(self)
49
52
  return result.normalize_in_place()
50
53
 
54
+ @staticmethod
55
+ def _discard_negligible_imaginary_part(val):
56
+ """
57
+ Return the real part of a numerically real value.
58
+
59
+ Non-square-root density representations should evaluate to real-valued
60
+ densities. Small imaginary parts arise from floating-point roundoff in
61
+ complex basis evaluations and can be discarded; larger imaginary parts
62
+ indicate inconsistent coefficients and must not be silently ignored.
63
+ """
64
+ if not all(backend_abs(imag(val)) <= _REAL_DENSITY_IMAG_TOL):
65
+ raise ValueError(
66
+ "Density evaluation has a non-negligible imaginary part. "
67
+ "Check that the coefficients define a real-valued density."
68
+ )
69
+ return real(val)
70
+
51
71
  def pdf(self, xs):
52
72
  """
53
73
  Calculates probability density function for the given input.
@@ -57,14 +77,13 @@ class AbstractOrthogonalBasisDistribution(AbstractDistributionType):
57
77
  """
58
78
  val = self.value(xs)
59
79
  if self.transformation == "sqrt":
60
- assert all(imag(val) < 0.0001)
61
- return real(val) ** 2
80
+ return backend_abs(val) ** 2
62
81
 
63
82
  if self.transformation == "identity":
64
- return val
83
+ return self._discard_negligible_imaginary_part(val)
65
84
 
66
85
  if self.transformation == "log":
67
86
  warnings.warn("Density may not be normalized")
68
- return exp(val)
87
+ return exp(self._discard_negligible_imaginary_part(val))
69
88
 
70
89
  raise ValueError("Transformation not recognized or unsupported")
@@ -71,23 +71,30 @@ class AbstractHypercylindricalDistribution(AbstractLinPeriodicCartProdDistributi
71
71
 
72
72
  def get_reasonable_integration_boundaries(self, scalingFactor=10):
73
73
  """
74
- Returns reasonable integration boundaries for the specific distribution
75
- based on the mode and covariance.
74
+ Return reasonable integration boundaries for numerical integration.
75
+
76
+ The input dimensions are ordered as bounded dimensions first and linear
77
+ dimensions second. SciPy's nquad expects one [lower, upper] interval per
78
+ input dimension, so the periodic dimensions are integrated over a full
79
+ period and the linear dimensions are truncated around the mode according
80
+ to their marginal standard deviations.
76
81
  """
77
- left = empty((self.bound_dim + self.lin_dim, 1))
78
- right = empty((self.bound_dim + self.lin_dim, 1))
79
82
  P = self.linear_covariance()
80
83
  m = self.mode()
81
84
 
82
- for i in range(self.bound_dim, self.bound_dim + self.lin_dim):
83
- left[i] = m[i] - scalingFactor * sqrt(
84
- P[i - self.bound_dim, i - self.bound_dim]
85
- )
86
- right[i] = m[i] + scalingFactor * sqrt(
87
- P[i - self.bound_dim, i - self.bound_dim]
85
+ integration_boundaries = [[0.0, float(2.0 * pi)] for _ in range(self.bound_dim)]
86
+
87
+ for linear_idx in range(self.lin_dim):
88
+ input_idx = self.bound_dim + linear_idx
89
+ linear_std = sqrt(P[linear_idx, linear_idx])
90
+ integration_boundaries.append(
91
+ [
92
+ float(m[input_idx] - scalingFactor * linear_std),
93
+ float(m[input_idx] + scalingFactor * linear_std),
94
+ ]
88
95
  )
89
96
 
90
- return vstack((left, right))
97
+ return integration_boundaries
91
98
 
92
99
  def mode(self):
93
100
  """Find the mode of the distribution by calling mode_numerical."""
@@ -27,7 +27,7 @@ class AbstractLinBoundedCartProdDistribution(AbstractCartProdDistribution):
27
27
  """
28
28
  if not bound_dim >= 1:
29
29
  raise ValueError("bound_dim must be a positive integer")
30
- if not bound_dim >= 1:
30
+ if not lin_dim >= 1:
31
31
  raise ValueError("lin_dim must be a positive integer")
32
32
 
33
33
  AbstractCartProdDistribution.__init__(self, bound_dim + lin_dim)