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.
- {pyrecest-2.2.0 → pyrecest-2.2.2}/PKG-INFO +1 -1
- {pyrecest-2.2.0 → pyrecest-2.2.2}/pyproject.toml +1 -1
- pyrecest-2.2.2/src/pyrecest/_backend/_shared_numpy/random.py +51 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/autodiff.py +24 -12
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/random.py +22 -6
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/_so3_helpers.py +30 -4
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_dirac_distribution.py +27 -6
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_grid_distribution.py +4 -4
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_manifold_specific_distribution.py +51 -10
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_mixture.py +39 -8
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_orthogonal_basis_distribution.py +23 -4
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_hypercylindrical_distribution.py +18 -11
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_bounded_cart_prod_distribution.py +1 -1
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/gauss_von_mises_distribution.py +12 -8
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/mardia_sutton_distribution.py +25 -3
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/circular_dirac_distribution.py +4 -2
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/circular_fourier_distribution.py +19 -4
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/circular_grid_distribution.py +3 -0
- pyrecest-2.2.2/src/pyrecest/distributions/circle/circular_mixture.py +117 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/sine_skewed_distributions.py +12 -3
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/von_mises_distribution.py +67 -10
- pyrecest-2.2.2/src/pyrecest/distributions/circle/wrapped_cauchy_distribution.py +55 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/wrapped_normal_distribution.py +89 -30
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/ellipsoidal_ball_uniform_distribution.py +11 -1
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hyperhemispherical_distribution.py +15 -17
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hypersphere_subset_distribution.py +88 -43
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hypersphere_subset_grid_distribution.py +23 -8
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hyperspherical_distribution.py +18 -9
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_sphere_subset_distribution.py +19 -7
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/bingham_distribution.py +38 -5
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_grid_distribution.py +16 -12
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_watson_distribution.py +11 -9
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperspherical_dirac_distribution.py +8 -7
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperspherical_grid_distribution.py +30 -12
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperspherical_uniform_distribution.py +2 -1
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/spherical_grid_distribution.py +21 -5
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/spherical_harmonics_distribution_complex.py +5 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/von_mises_fisher_distribution.py +137 -40
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/watson_distribution.py +9 -8
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/abstract_hypertoroidal_distribution.py +22 -6
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_dirac_distribution.py +40 -4
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_fourier_distribution.py +54 -23
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_grid_distribution.py +40 -5
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_wrapped_normal_distribution.py +27 -15
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_fourier_distribution.py +3 -4
- pyrecest-2.2.2/src/pyrecest/distributions/hypertorus/toroidal_von_mises_cosine_distribution.py +120 -0
- pyrecest-2.2.2/src/pyrecest/distributions/hypertorus/toroidal_von_mises_sine_distribution.py +76 -0
- pyrecest-2.2.2/src/pyrecest/distributions/hypertorus/toroidal_wrapped_normal_distribution.py +114 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/abstract_linear_distribution.py +47 -12
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/custom_linear_distribution.py +3 -3
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/gaussian_distribution.py +28 -17
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_helpers.py +2 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_product_tangent_gaussian_distribution.py +18 -9
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_tangent_gaussian_distribution.py +19 -13
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/eot_shape_database.py +1 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/evaluate_for_file.py +1 -1
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/perform_predict_update_cycles.py +2 -2
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/__init__.py +114 -3
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/_ukf.py +40 -11
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_particle_filter.py +34 -3
- pyrecest-2.2.2/src/pyrecest/filters/association_hypotheses.py +659 -0
- pyrecest-2.2.2/src/pyrecest/filters/block_particle_filter.py +506 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/circular_ukf.py +157 -72
- pyrecest-2.2.2/src/pyrecest/filters/euclidean_boxed_particle_filter.py +554 -0
- pyrecest-2.2.2/src/pyrecest/filters/factorized_giw_random_matrix_tracker.py +256 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperhemisphere_cart_prod_particle_filter.py +9 -4
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperhemispherical_grid_filter.py +6 -6
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperspherical_particle_filter.py +3 -1
- pyrecest-2.2.2/src/pyrecest/filters/information_form_distributed_kalman_filter.py +597 -0
- pyrecest-2.2.2/src/pyrecest/filters/iterated_batch_mem_qkf_tracker.py +478 -0
- pyrecest-2.2.2/src/pyrecest/filters/lomem_tracker.py +604 -0
- pyrecest-2.2.2/src/pyrecest/filters/mem_ekf_star_oa_tracker.py +154 -0
- pyrecest-2.2.2/src/pyrecest/filters/mem_qkf_tracker.py +610 -0
- pyrecest-2.2.2/src/pyrecest/filters/mem_rbpf_tracker.py +682 -0
- pyrecest-2.2.2/src/pyrecest/filters/mode_rbpf_manifold_ukf_tracker.py +899 -0
- pyrecest-2.2.2/src/pyrecest/filters/multi_bernoulli_mixture_tracker.py +467 -0
- pyrecest-2.2.2/src/pyrecest/filters/orientation_vector_eot_tracker.py +670 -0
- pyrecest-2.2.2/src/pyrecest/filters/out_of_sequence.py +611 -0
- pyrecest-2.2.2/src/pyrecest/filters/partitioned_so3_product_particle_filter.py +7 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/se2_ukf.py +36 -19
- pyrecest-2.2.2/src/pyrecest/filters/so3_product_block_particle_filter.py +123 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/unscented_kalman_filter.py +45 -3
- pyrecest-2.2.2/src/pyrecest/filters/vbrm_tracker.py +602 -0
- pyrecest-2.2.2/src/pyrecest/filters/velocity_aided_mem_qkf_tracker.py +306 -0
- pyrecest-2.2.2/src/pyrecest/filters/velocity_locked_mem_qkf_tracker.py +249 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/von_mises_filter.py +3 -1
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/wrapped_normal_filter.py +5 -4
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/__init__.py +78 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/additive_noise.py +18 -0
- pyrecest-2.2.2/src/pyrecest/models/motion_models.py +523 -0
- pyrecest-2.2.2/src/pyrecest/models/sensor_models.py +352 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/filters.py +4 -6
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/hyperspherical_sampler.py +0 -3
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/leopardi_sampler.py +5 -6
- pyrecest-2.2.2/src/pyrecest/smoothers/__init__.py +87 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/abstract_smoother.py +22 -14
- pyrecest-2.2.2/src/pyrecest/smoothers/fixed_lag_mem_qkf_smoother.py +1204 -0
- pyrecest-2.2.2/src/pyrecest/smoothers/fixed_lag_random_matrix_smoother.py +918 -0
- pyrecest-2.2.2/src/pyrecest/smoothers/fixed_lag_velocity_locked_mem_qkf_smoother.py +597 -0
- pyrecest-2.2.2/src/pyrecest/smoothers/mem_rbpf_ffbsi_smoother.py +504 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/__init__.py +74 -0
- pyrecest-2.2.2/src/pyrecest/utils/metrics.py +681 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/plotting.py +1 -1
- pyrecest-2.2.2/src/pyrecest/utils/track_metrics.py +341 -0
- pyrecest-2.2.0/src/pyrecest/_backend/_shared_numpy/random.py +0 -29
- pyrecest-2.2.0/src/pyrecest/distributions/circle/circular_mixture.py +0 -48
- pyrecest-2.2.0/src/pyrecest/distributions/circle/wrapped_cauchy_distribution.py +0 -36
- pyrecest-2.2.0/src/pyrecest/distributions/hypertorus/toroidal_von_mises_cosine_distribution.py +0 -86
- pyrecest-2.2.0/src/pyrecest/distributions/hypertorus/toroidal_von_mises_sine_distribution.py +0 -40
- pyrecest-2.2.0/src/pyrecest/distributions/hypertorus/toroidal_wrapped_normal_distribution.py +0 -133
- pyrecest-2.2.0/src/pyrecest/filters/partitioned_so3_product_particle_filter.py +0 -467
- pyrecest-2.2.0/src/pyrecest/smoothers/__init__.py +0 -19
- pyrecest-2.2.0/src/pyrecest/utils/metrics.py +0 -37
- {pyrecest-2.2.0 → pyrecest-2.2.2}/LICENSE +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/README.md +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/.pylintrc +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/LICENSE_geomstats +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/README.md +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_backend_config.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_common.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_dtype_utils.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_shared_numpy/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_shared_numpy/_common.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_shared_numpy/_dispatch.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/_shared_numpy/linalg.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/_common.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/_dtype.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/autodiff.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/linalg.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/autograd/random.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/_dtype.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/fft.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/linalg.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/signal.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/jax/spatial.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/_common.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/_dtype.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/autodiff.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/fft.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/linalg.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/random.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/signal.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/numpy/spatial.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/_common.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/_dtype.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/autodiff.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/fft.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/linalg.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/random.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/signal.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/_backend/pytorch/spatial.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_bounded_domain_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_bounded_nonperiodic_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_custom_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_custom_nonperiodic_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_disk_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_distribution_type.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_ellipsoidal_ball_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_nonperiodic_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_periodic_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_periodic_grid_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_se2_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_se3_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/abstract_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_cart_prod_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_custom_lin_bounded_cart_prod_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_hemisphere_cart_prod_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_hyperhemisphere_cart_prod_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_hypersphere_cart_prod_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_hypersphere_subset_cart_prod_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/abstract_lin_periodic_cart_prod_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/cart_prod_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/cart_prod_stacked_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/custom_hypercylindrical_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/hypercylindrical_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/hypercylindrical_state_space_subdivision_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/hypercylindrical_state_space_subdivision_gaussian_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/hyperhemisphere_cart_prod_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/lin_bounded_cart_prod_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/lin_hypersphere_cart_prod_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/lin_hypersphere_subset_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/lin_periodic_cart_prod_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/partially_wrapped_normal_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/se2_bingham_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/se2_pwn_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/se2_state_space_subdivision_gaussian_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/se3_lin_vel_cart_prod_stacked_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/state_space_subdivision_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/cart_prod/state_space_subdivision_gaussian_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/abstract_circular_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/circular_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/custom_circular_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/generalized_von_mises_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/piecewise_constant_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/wrapped_exponential_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/circle/wrapped_laplace_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/abstract_conditional_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/s2_cond_s2_grid_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/sd_cond_sd_grid_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/sd_half_cond_sd_half_grid_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conditional/td_cond_td_grid_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/conversion.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/custom_hyperrectangular_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/disk_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_complex_hyperspherical_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hemispherical_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hypersphere_subset_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_hypersphere_subset_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_spherical_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/abstract_spherical_harmonics_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/bayesian_complex_watson_mixture_model.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/complex_angular_central_gaussian_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/complex_bingham_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/complex_watson_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/custom_hemispherical_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/custom_hyperhemispherical_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/custom_hyperspherical_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hemispherical_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_bingham_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperhemispherical_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/hyperspherical_mixture.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypersphere_subset/spherical_harmonics_distribution_real.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/abstract_toroidal_bivar_vm_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/abstract_toroidal_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/custom_hypertoroidal_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/custom_toroidal_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_mixture.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/hypertoroidal_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_mixture.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_vm_matrix_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/hypertorus/toroidal_vm_rivest_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/abstract_hyperrectangular_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/gaussian_mixture.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/hyperrectangular_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/linear_box_particle_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/linear_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/nonperiodic/linear_mixture.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/se2_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/se3_cart_prod_stacked_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/se3_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_bingham_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_conversion.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_product_dirac_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/distributions/so3_uniform_distribution.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/check_and_fix_config.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/configure_for_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/determine_all_deviations.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/evaluate_for_simulation_config.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/evaluate_for_variables.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/generate_groundtruth.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/generate_measurements.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/generate_simulated_scenarios.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/get_axis_label.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/get_distance_function.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/get_extract_mean.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/group_results_by_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/iterate_configs_and_runs.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/plot_results.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/simulation_database.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/evaluation/summarize_filter_results.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/_linear_gaussian.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_axial_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_circular_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_dummy_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_extended_object_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_grid_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_multiple_extended_object_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_multitarget_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_nearest_neighbor_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/abstract_tracker_with_logging.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/axial_kalman_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/bingham_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/circular_fourier_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/circular_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/ekf_spline_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/euclidean_box_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/euclidean_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/fourier_rhm_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/gaussian_mixture_phd_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/ggiw_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/global_nearest_neighbor.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/goal_conditioned_replay_imm_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/goal_conditioned_replay_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/goal_conditioned_replay_particle_imm_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/gprhm_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hypercylindrical_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperhemispherical_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperspherical_dummy_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hyperspherical_ukf.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hypertoroidal_dummy_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hypertoroidal_fourier_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/hypertoroidal_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/interacting_multiple_model_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/joint_probabilistic_data_association_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/kalman_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/kernel_sme_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/lin_bounded_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/lin_periodic_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/manifold_exponential_moving_average.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/manifold_mixins.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/mem_ekf_star_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/mem_ekf_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/mem_soekf_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/multi_bernoulli_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/multi_hypothesis_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/piecewise_constant_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/random_matrix_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/relaxed_s3f_circular.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/relaxed_s3f_so3.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/so3_grid_transition.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/so3_product_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/spherical_harmonics_eot_tracker.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/spherical_harmonics_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/state_space_subdivision_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/toroidal_particle_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/toroidal_wrapped_normal_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/track_manager.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/ukf_on_manifolds.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/filters/von_mises_fisher_filter.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/adapters.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/grid.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/likelihood.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/linear_gaussian.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/particle.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/models/validation.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/common.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/models.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/protocols/testing.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/py.typed +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/__init__.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/abstract_sampler.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/euclidean_sampler.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/hypertoroidal_sampler.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/sampling/sigma_points.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/rauch_tung_striebel_smoother.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/sliding_window_manifold_mean_smoother.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/so3_chordal_mean_smoother.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/smoothers/unscented_rauch_tung_striebel_smoother.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/_point_set_registration_common.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/assignment.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/association_features.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/association_models.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/history_recorder.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/multisession_assignment.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/multisession_assignment_observation_costs.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/multisession_assignment_score.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/nonrigid_point_set_registration.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/pairwise_covariance_features.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/point_set_registration.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/roi_assignment.py +0 -0
- {pyrecest-2.2.0 → pyrecest-2.2.2}/src/pyrecest/utils/track_evaluation.py +0 -0
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
|
124
|
-
|
|
125
|
-
|
|
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
|
|
129
|
-
|
|
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 =
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
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 /
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
162
|
-
|
|
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
|
-
|
|
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 =
|
|
56
|
+
non_zero_indices = [i for i, weight in enumerate(weights) if bool(weight != 0)]
|
|
50
57
|
|
|
51
|
-
if non_zero_indices
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
122
|
+
xs = asarray(xs)
|
|
99
123
|
|
|
100
|
-
|
|
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
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
|
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
|
|
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)
|