pybhatlib 0.3.0__tar.gz → 0.3.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.
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/.gitignore +20 -0
- pybhatlib-0.3.2/CHANGELOG.md +47 -0
- pybhatlib-0.3.2/CONTRIBUTING.md +188 -0
- pybhatlib-0.3.2/PKG-INFO +219 -0
- pybhatlib-0.3.2/README.md +179 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/data/TRAVELMODE.csv +1126 -1126
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/data/TRAVELMODE_synthetic.csv +1126 -1126
- pybhatlib-0.3.2/examples/data/WorkshopData_ToursimExp.csv +1501 -0
- pybhatlib-0.3.2/examples/data/Workshop_SCAG_Est.csv +1501 -0
- pybhatlib-0.3.2/examples/data/modeData.csv +3594 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/mnp_age45.py +1 -1
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/mnp_flexible_cov.py +1 -1
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/mnp_iid.py +1 -1
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/mnp_mixture.py +1 -1
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/mnp_random_coefficients.py +1 -1
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/morp_example.py +12 -4
- pybhatlib-0.3.2/examples/tutorials/_convert_to_ipynb.py +445 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t00_quickstart.py +137 -129
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t01a_vectorization.py +163 -142
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t01b_ldlt.py +135 -130
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t01c_truncated_mvn.py +169 -115
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t02a_gradcovcor.py +227 -151
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t02b_spherical.py +147 -141
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t02c_chain_rules.py +202 -174
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t03a_mvncd_methods.py +199 -132
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t03b_mvncd_gradients.py +166 -150
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t03c_mvncd_rect.py +172 -156
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t03d_univariate_cdfs.py +189 -160
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t03e_bhat2018_table1.py +40 -3
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t04a_mnp_iid.py +107 -17
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t04b_mnp_flexible_cov.py +132 -17
- pybhatlib-0.3.2/examples/tutorials/python_scripts/t04c_mnp_heteronly.py +250 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t04d_mnp_random_coefficients.py +93 -15
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t04e_mnp_mixture.py +98 -34
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t04f_mnp_control_options.py +314 -189
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t04g_mnp_forecasting.py +262 -164
- pybhatlib-0.3.2/examples/tutorials/python_scripts/t04h_bhatlib_table1.py +565 -0
- pybhatlib-0.3.2/examples/tutorials/python_scripts/t04i_bhat2018_table2.py +736 -0
- pybhatlib-0.3.2/examples/tutorials/python_scripts/t05b_morp_ate_predict.py +342 -0
- pybhatlib-0.3.2/examples/tutorials/python_scripts/t06a_backend_switching.py +353 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t06b_custom_specs.py +228 -222
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/python_scripts/t06c_gradient_verification.py +298 -269
- pybhatlib-0.3.2/examples/tutorials/python_scripts/t07a_mdcev_trad.py +286 -0
- pybhatlib-0.3.2/examples/tutorials/python_scripts/t07b_mdcev_lin.py +254 -0
- pybhatlib-0.3.2/examples/tutorials/python_scripts/t08a_mnl.py +38 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/t00_quickstart.ipynb +150 -115
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/t01a_vectorization.ipynb +173 -131
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/t01b_ldlt.ipynb +140 -99
- pybhatlib-0.3.2/examples/tutorials/t01c_truncated_mvn.ipynb +194 -0
- pybhatlib-0.3.2/examples/tutorials/t02a_gradcovcor.ipynb +232 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/t02b_spherical.ipynb +133 -115
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/t02c_chain_rules.ipynb +114 -114
- pybhatlib-0.3.2/examples/tutorials/t03a_mvncd_methods.ipynb +195 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/t03b_mvncd_gradients.ipynb +140 -115
- pybhatlib-0.3.2/examples/tutorials/t03c_mvncd_rect.ipynb +180 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/t03d_univariate_cdfs.ipynb +130 -115
- pybhatlib-0.3.2/examples/tutorials/t03e_bhat2018_table1.ipynb +224 -0
- pybhatlib-0.3.2/examples/tutorials/t04a_mnp_iid.ipynb +314 -0
- pybhatlib-0.3.2/examples/tutorials/t04b_mnp_flexible_cov.ipynb +331 -0
- pybhatlib-0.3.2/examples/tutorials/t04c_mnp_heteronly.ipynb +196 -0
- pybhatlib-0.3.2/examples/tutorials/t04d_mnp_random_coefficients.ipynb +340 -0
- pybhatlib-0.3.2/examples/tutorials/t04e_mnp_mixture.ipynb +314 -0
- pybhatlib-0.3.2/examples/tutorials/t04f_mnp_control_options.ipynb +295 -0
- pybhatlib-0.3.2/examples/tutorials/t04g_mnp_forecasting.ipynb +211 -0
- pybhatlib-0.3.2/examples/tutorials/t04h_bhatlib_table1.ipynb +580 -0
- pybhatlib-0.3.2/examples/tutorials/t04i_bhat2018_table2.ipynb +507 -0
- pybhatlib-0.3.2/examples/tutorials/t05b_morp_ate_predict.ipynb +272 -0
- pybhatlib-0.3.2/examples/tutorials/t06a_backend_switching.ipynb +307 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/tutorials/t06b_custom_specs.ipynb +130 -130
- pybhatlib-0.3.2/examples/tutorials/t06c_gradient_verification.ipynb +315 -0
- pybhatlib-0.3.2/examples/tutorials/t07a_mdcev_trad.ipynb +298 -0
- pybhatlib-0.3.2/examples/tutorials/t07b_mdcev_lin.ipynb +267 -0
- pybhatlib-0.3.2/examples/tutorials/t08a_mnl.ipynb +35 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/pyproject.toml +27 -2
- pybhatlib-0.3.2/src/pybhatlib/__init__.py +54 -0
- pybhatlib-0.3.2/src/pybhatlib/_version.py +1 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/backend/_numpy_backend.py +6 -4
- pybhatlib-0.3.2/src/pybhatlib/gradmvn/__init__.py +116 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_bivariate_trunc.py +15 -9
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_cond_trunc_grads.py +11 -5
- pybhatlib-0.3.2/src/pybhatlib/gradmvn/_logit_dist.py +1491 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_mvncd.py +711 -46
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_mvncd_grad.py +8 -2
- pybhatlib-0.3.2/src/pybhatlib/gradmvn/_mvncd_grad_analytic.py +738 -0
- pybhatlib-0.3.2/src/pybhatlib/gradmvn/_mvncd_grad_ovus.py +539 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_mvncd_ssj.py +4 -4
- pybhatlib-0.3.2/src/pybhatlib/gradmvn/_mvncd_torch.py +372 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_ordering.py +10 -3
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_other_dists.py +10 -4
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_partial_cdf.py +3 -2
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_trunc_grads.py +20 -14
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_truncated.py +15 -9
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/gradmvn/_univariate.py +198 -9
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/matgradient/__init__.py +6 -1
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/matgradient/_spherical.py +73 -0
- pybhatlib-0.3.2/src/pybhatlib/models/_ate_common.py +228 -0
- pybhatlib-0.3.2/src/pybhatlib/models/_base.py +41 -0
- pybhatlib-0.3.2/src/pybhatlib/models/_results_common.py +162 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mdcev/__init__.py +34 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mdcev/_mdcev_ate.py +282 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mdcev/_mdcev_control.py +96 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mdcev/_mdcev_forecast.py +429 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mdcev/_mdcev_loglik.py +651 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mdcev/_mdcev_model.py +593 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mdcev/_mdcev_results.py +371 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnl/__init__.py +18 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnl/_mnl_ate.py +316 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnl/_mnl_control.py +65 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnl/_mnl_forecast.py +73 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnl/_mnl_loglik.py +266 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnl/_mnl_model.py +410 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnl/_mnl_results.py +280 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnp/__init__.py +24 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnp/_mnp_ate.py +417 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnp/_mnp_control.py +147 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/models/mnp/_mnp_forecast.py +18 -39
- pybhatlib-0.3.2/src/pybhatlib/models/mnp/_mnp_grad_analytic.py +1488 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnp/_mnp_grad_gpu.py +447 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnp/_mnp_loglik.py +1707 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnp/_mnp_model.py +1695 -0
- pybhatlib-0.3.2/src/pybhatlib/models/mnp/_mnp_results.py +425 -0
- pybhatlib-0.3.2/src/pybhatlib/models/morp/__init__.py +35 -0
- pybhatlib-0.3.2/src/pybhatlib/models/morp/_morp_ate.py +404 -0
- pybhatlib-0.3.2/src/pybhatlib/models/morp/_morp_control.py +277 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/models/morp/_morp_forecast.py +25 -21
- pybhatlib-0.3.2/src/pybhatlib/models/morp/_morp_grad_analytic.py +756 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/models/morp/_morp_loglik.py +169 -40
- pybhatlib-0.3.2/src/pybhatlib/models/morp/_morp_model.py +631 -0
- pybhatlib-0.3.2/src/pybhatlib/models/morp/_morp_report.py +316 -0
- pybhatlib-0.3.2/src/pybhatlib/models/morp/_morp_results.py +468 -0
- pybhatlib-0.3.2/src/pybhatlib/optim/_scipy_optim.py +287 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/utils/_qmc.py +2 -2
- pybhatlib-0.3.2/src/pybhatlib/vecup/_ldlt.py +297 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/vecup/_truncnorm.py +11 -5
- pybhatlib-0.3.2/tests/fixtures/bhatlib_table2_targets.json +102 -0
- pybhatlib-0.3.2/tests/test_api_harmonization.py +337 -0
- pybhatlib-0.3.2/tests/test_gradmvn/test_mvncd_batch.py +169 -0
- pybhatlib-0.3.2/tests/test_gradmvn/test_mvncd_grad_ovus.py +303 -0
- pybhatlib-0.3.2/tests/test_gradmvn/test_mvncd_rect_inf_bounds.py +400 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_matgradient/test_spherical.py +29 -0
- pybhatlib-0.3.2/tests/test_models/test_ate_common.py +99 -0
- pybhatlib-0.3.2/tests/test_models/test_ate_from_params.py +189 -0
- pybhatlib-0.3.2/tests/test_models/test_mdcev.py +229 -0
- pybhatlib-0.3.2/tests/test_models/test_mdcev_scenarios.py +82 -0
- pybhatlib-0.3.2/tests/test_models/test_mnl.py +180 -0
- pybhatlib-0.3.2/tests/test_models/test_mnl_ate_from_params.py +76 -0
- pybhatlib-0.3.2/tests/test_models/test_mnp_active_mask_verbose.py +454 -0
- pybhatlib-0.3.2/tests/test_models/test_mnp_ate_scenarios.py +449 -0
- pybhatlib-0.3.2/tests/test_models/test_mnp_gauss_parity.py +134 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_models/test_mnp_grad.py +9 -7
- pybhatlib-0.3.2/tests/test_models/test_mnp_grad_mixture.py +450 -0
- pybhatlib-0.3.2/tests/test_models/test_mnp_mixture_ranvars.py +571 -0
- pybhatlib-0.3.2/tests/test_models/test_mnp_perobs_scores.py +173 -0
- pybhatlib-0.3.2/tests/test_models/test_mnp_se_options.py +140 -0
- pybhatlib-0.3.2/tests/test_models/test_mnp_table2_parity.py +371 -0
- pybhatlib-0.3.2/tests/test_models/test_mnp_unpar_se.py +556 -0
- pybhatlib-0.3.2/tests/test_models/test_model_facade.py +227 -0
- pybhatlib-0.3.2/tests/test_models/test_morp.py +631 -0
- pybhatlib-0.3.2/tests/test_models/test_morp_analytic_gradient.py +531 -0
- pybhatlib-0.3.2/tests/test_models/test_morp_gauss_parity.py +257 -0
- pybhatlib-0.3.2/tests/test_models/test_morp_per_outcome_spec.py +451 -0
- pybhatlib-0.3.2/tests/test_models/test_morp_scenarios.py +131 -0
- pybhatlib-0.3.2/tests/test_models/test_results_harmonization.py +209 -0
- pybhatlib-0.3.0/CLAUDE.md +0 -42
- pybhatlib-0.3.0/GAUSS_INTEGRATION_PLAN.md +0 -235
- pybhatlib-0.3.0/IMPLEMENTATION_PLAN.md +0 -497
- pybhatlib-0.3.0/PKG-INFO +0 -124
- pybhatlib-0.3.0/README.md +0 -86
- pybhatlib-0.3.0/examples/tutorials/_convert_to_ipynb.py +0 -224
- pybhatlib-0.3.0/examples/tutorials/python_scripts/t04c_mnp_heteronly.py +0 -154
- pybhatlib-0.3.0/examples/tutorials/python_scripts/t05b_morp_ate_predict.py +0 -171
- pybhatlib-0.3.0/examples/tutorials/python_scripts/t06a_backend_switching.py +0 -139
- pybhatlib-0.3.0/examples/tutorials/t01c_truncated_mvn.ipynb +0 -99
- pybhatlib-0.3.0/examples/tutorials/t02a_gradcovcor.ipynb +0 -115
- pybhatlib-0.3.0/examples/tutorials/t03a_mvncd_methods.ipynb +0 -99
- pybhatlib-0.3.0/examples/tutorials/t03c_mvncd_rect.ipynb +0 -99
- pybhatlib-0.3.0/examples/tutorials/t03e_bhat2018_table1.ipynb +0 -44
- pybhatlib-0.3.0/examples/tutorials/t04a_mnp_iid.ipynb +0 -99
- pybhatlib-0.3.0/examples/tutorials/t04b_mnp_flexible_cov.ipynb +0 -115
- pybhatlib-0.3.0/examples/tutorials/t04c_mnp_heteronly.ipynb +0 -115
- pybhatlib-0.3.0/examples/tutorials/t04d_mnp_random_coefficients.ipynb +0 -99
- pybhatlib-0.3.0/examples/tutorials/t04e_mnp_mixture.ipynb +0 -99
- pybhatlib-0.3.0/examples/tutorials/t04f_mnp_control_options.ipynb +0 -131
- pybhatlib-0.3.0/examples/tutorials/t04g_mnp_forecasting.ipynb +0 -115
- pybhatlib-0.3.0/examples/tutorials/t05b_morp_ate_predict.ipynb +0 -115
- pybhatlib-0.3.0/examples/tutorials/t06a_backend_switching.ipynb +0 -115
- pybhatlib-0.3.0/examples/tutorials/t06c_gradient_verification.ipynb +0 -131
- pybhatlib-0.3.0/src/pybhatlib/__init__.py +0 -5
- pybhatlib-0.3.0/src/pybhatlib/_version.py +0 -1
- pybhatlib-0.3.0/src/pybhatlib/gradmvn/__init__.py +0 -52
- pybhatlib-0.3.0/src/pybhatlib/gradmvn/_mvncd_grad_analytic.py +0 -255
- pybhatlib-0.3.0/src/pybhatlib/models/_base.py +0 -14
- pybhatlib-0.3.0/src/pybhatlib/models/mnp/__init__.py +0 -14
- pybhatlib-0.3.0/src/pybhatlib/models/mnp/_mnp_ate.py +0 -192
- pybhatlib-0.3.0/src/pybhatlib/models/mnp/_mnp_control.py +0 -89
- pybhatlib-0.3.0/src/pybhatlib/models/mnp/_mnp_grad_analytic.py +0 -386
- pybhatlib-0.3.0/src/pybhatlib/models/mnp/_mnp_loglik.py +0 -575
- pybhatlib-0.3.0/src/pybhatlib/models/mnp/_mnp_model.py +0 -421
- pybhatlib-0.3.0/src/pybhatlib/models/mnp/_mnp_results.py +0 -181
- pybhatlib-0.3.0/src/pybhatlib/models/morp/__init__.py +0 -17
- pybhatlib-0.3.0/src/pybhatlib/models/morp/_morp_ate.py +0 -119
- pybhatlib-0.3.0/src/pybhatlib/models/morp/_morp_control.py +0 -56
- pybhatlib-0.3.0/src/pybhatlib/models/morp/_morp_model.py +0 -276
- pybhatlib-0.3.0/src/pybhatlib/models/morp/_morp_results.py +0 -154
- pybhatlib-0.3.0/src/pybhatlib/optim/_scipy_optim.py +0 -156
- pybhatlib-0.3.0/src/pybhatlib/vecup/_ldlt.py +0 -160
- pybhatlib-0.3.0/tests/test_models/test_morp.py +0 -210
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/LICENSE +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/data/generate_travelmode.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/examples/mnp_ate_analysis.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/backend/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/backend/_array_api.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/backend/_torch_backend.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/io/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/io/_data_loader.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/io/_spec_parser.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/matgradient/_chain_rules.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/matgradient/_gomegxomegax.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/matgradient/_gradcovcor.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/matgradient/_mat_grad_helpers.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/matgradient/_radial.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/models/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/optim/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/optim/_convergence.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/optim/_torch_optim.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/utils/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/utils/_seeds.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/utils/_validation.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/vecup/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/vecup/_mask.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/vecup/_nondiag.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/src/pybhatlib/vecup/_vec_ops.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/conftest.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_backend/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_backend/test_array_api.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_bivariate_trunc.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_cond_trunc_grads.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_mvncd.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_mvncd_grad_analytic.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_mvncd_methods.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_mvncd_rect.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_ordering.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_other_dists.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_gradmvn/test_trunc_grads.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_integration/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_matgradient/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_matgradient/test_gradcovcor.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_matgradient/test_mat_grad_helpers.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_matgradient/test_radial.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_models/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_models/test_mnp_control.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_vecup/__init__.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_vecup/test_ldlt.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_vecup/test_ldlt_rank2.py +0 -0
- {pybhatlib-0.3.0 → pybhatlib-0.3.2}/tests/test_vecup/test_vec_ops.py +0 -0
|
@@ -28,10 +28,23 @@ htmlcov/
|
|
|
28
28
|
*.dat
|
|
29
29
|
*.pkl
|
|
30
30
|
*.pdf
|
|
31
|
+
*.tar.gz
|
|
31
32
|
results/
|
|
33
|
+
experiments/
|
|
34
|
+
pr32-*.md
|
|
32
35
|
|
|
33
36
|
# Original GAUSS source
|
|
34
37
|
chandra_code/
|
|
38
|
+
UTAcode_0402/
|
|
39
|
+
slides/
|
|
40
|
+
docs/
|
|
41
|
+
Gauss Files and Comparison/
|
|
42
|
+
anna0605/
|
|
43
|
+
|
|
44
|
+
# Project-local docs (not for repo)
|
|
45
|
+
CLAUDE.md
|
|
46
|
+
GAUSS_INTEGRATION_PLAN.md
|
|
47
|
+
IMPLEMENTATION_PLAN.md
|
|
35
48
|
|
|
36
49
|
# OS
|
|
37
50
|
.DS_Store
|
|
@@ -50,3 +63,10 @@ nul
|
|
|
50
63
|
*.fdb_latexmk
|
|
51
64
|
*.fls
|
|
52
65
|
*.synctex.gz
|
|
66
|
+
|
|
67
|
+
# PESOSE proposal working files — internal, NOT for the (soon-public) repo
|
|
68
|
+
PESOSE_*
|
|
69
|
+
PESOSE-related
|
|
70
|
+
.env
|
|
71
|
+
.claude
|
|
72
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to pybhatlib are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.3.2] - 2026-07-22
|
|
8
|
+
|
|
9
|
+
First version available on PyPI. Identical in code to 0.3.1; released under a new
|
|
10
|
+
patch number only because 0.3.1's filenames had already been reserved on PyPI (an
|
|
11
|
+
earlier 0.3.1 upload was deleted, and PyPI never permits reusing a deleted
|
|
12
|
+
filename). See the 0.3.1 entry below for the full feature list.
|
|
13
|
+
|
|
14
|
+
## [0.3.1] - 2026-07-22
|
|
15
|
+
|
|
16
|
+
Prepared as the first PyPI release but withdrawn before general availability; never
|
|
17
|
+
installable from PyPI. Superseded by 0.3.2 (same code). Contents:
|
|
18
|
+
|
|
19
|
+
### Models
|
|
20
|
+
- **Multinomial Probit (MNP)** — IID, flexible covariance, heteroscedastic-only,
|
|
21
|
+
random coefficients, and mixture-of-normals specifications.
|
|
22
|
+
- **Multivariate Ordered Response Probit (MORP)** — multiple ordinal outcomes
|
|
23
|
+
with shared covariance and per-outcome `spec` mapping.
|
|
24
|
+
- **Multiple Discrete-Continuous Extreme Value (MDCEV)** — traditional
|
|
25
|
+
(Bhat 2008) and linear (Bhat 2018) outside-good utility specifications.
|
|
26
|
+
- **Multinomial Logit (MNL)**.
|
|
27
|
+
|
|
28
|
+
### Numerical core
|
|
29
|
+
- `vecup` — vecdup, matdupfull, LDLT decomposition, truncated MVN moments.
|
|
30
|
+
- `matgradient` — gradcovcor, gomegxomegax, spherical / Cholesky parameterizations.
|
|
31
|
+
- `gradmvn` — Bhat (2018) MVNCD analytic approximation with analytic gradients.
|
|
32
|
+
|
|
33
|
+
### Estimation & post-estimation
|
|
34
|
+
- BHHH / Hessian / sandwich standard-error estimators, computed at fit time.
|
|
35
|
+
- Average Treatment Effects (ATE) with scenario-matrix support, forecasting,
|
|
36
|
+
per-category MORP probability prediction, and ATEs computed directly from
|
|
37
|
+
supplied coefficients without re-fitting.
|
|
38
|
+
- Optional PyTorch backend (`pip install pybhatlib[torch]`) with GPU support;
|
|
39
|
+
all numerical functions accept an optional `xp` backend kwarg.
|
|
40
|
+
|
|
41
|
+
### Verification
|
|
42
|
+
- Reproduces Table 1 of Bhat (2018) on the TRAVELMODE dataset: models (a)-(c)
|
|
43
|
+
match published log-likelihoods and BHHH standard errors to =0.001; model (d)
|
|
44
|
+
is documented as multi-modal.
|
|
45
|
+
|
|
46
|
+
[0.3.2]: https://github.com/UMN-Choi-Lab/pybhatlib/releases/tag/v0.3.2
|
|
47
|
+
[0.3.1]: https://github.com/UMN-Choi-Lab/pybhatlib/releases/tag/v0.3.1
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Contributing to pybhatlib
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing. This guide covers the pull request
|
|
4
|
+
workflow, local development setup, and the standards we maintain for
|
|
5
|
+
numerical correctness. It is written to be usable even if you are new to
|
|
6
|
+
GitHub — read top to bottom the first time.
|
|
7
|
+
|
|
8
|
+
## Quick overview
|
|
9
|
+
|
|
10
|
+
- All changes go through a **pull request (PR)** — nobody pushes directly to `main`.
|
|
11
|
+
- Each PR covers **one logical change**, not a batch of unrelated edits.
|
|
12
|
+
- CI runs `pytest` automatically on every PR. **CI must pass before merging.**
|
|
13
|
+
- Because pybhatlib reproduces published log-likelihood values exactly, any
|
|
14
|
+
change that alters numerical results must be justified and verified.
|
|
15
|
+
|
|
16
|
+
## Setting up locally
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git clone https://github.com/UMN-Choi-Lab/pybhatlib.git
|
|
20
|
+
cd pybhatlib
|
|
21
|
+
pip install -e ".[dev]"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Verify the install:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pytest tests/ -m "not slow"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
All tests should pass. If they do not, open an issue before making changes —
|
|
31
|
+
something in your environment is off, and PRs built on a broken baseline
|
|
32
|
+
waste review time.
|
|
33
|
+
|
|
34
|
+
## The pull request workflow
|
|
35
|
+
|
|
36
|
+
### 1. Create a branch
|
|
37
|
+
|
|
38
|
+
One branch per logical change. Short, descriptive names — not your username,
|
|
39
|
+
not a date.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git checkout main
|
|
43
|
+
git pull origin main
|
|
44
|
+
git checkout -b fix-mixture-shared-coefs
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Good branch names: `fix-mixture-shared-coefs`, `add-mvncd-j5-benchmark`,
|
|
48
|
+
`docs-contributing-guide`.
|
|
49
|
+
|
|
50
|
+
Avoid: `dales-changes`, `update`, `wip`, `patch-1`.
|
|
51
|
+
|
|
52
|
+
### 2. Make changes and commit
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Edit files...
|
|
56
|
+
pytest tests/ -m "not slow" # Run tests before committing
|
|
57
|
+
git add <files>
|
|
58
|
+
git commit -m "Short imperative summary of the change"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If you touch a tutorial, edit the `.py` script under
|
|
62
|
+
`examples/tutorials/python_scripts/` (the single source of truth) and
|
|
63
|
+
regenerate the notebooks — the `notebooks` CI job fails if they are stale or
|
|
64
|
+
missing:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
python examples/tutorials/_convert_to_ipynb.py
|
|
68
|
+
git add examples/tutorials/*.ipynb
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Commit message style:
|
|
72
|
+
|
|
73
|
+
- First line: imperative mood, under 72 characters
|
|
74
|
+
(`"Add shared-coefficient support for mixture-of-normals"`, not
|
|
75
|
+
`"Added ..."` or `"Changes to mixture"`).
|
|
76
|
+
- Optional body after a blank line explains *why*, not *what*.
|
|
77
|
+
- One commit per logical step is fine; squash trivial fixup commits before
|
|
78
|
+
pushing (`git rebase -i main`).
|
|
79
|
+
|
|
80
|
+
### 3. Push and open the PR
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
git push -u origin fix-mixture-shared-coefs
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
GitHub prints a URL for opening the PR after the push — click it, or visit
|
|
87
|
+
the repo on github.com and look for the "Compare & pull request" banner.
|
|
88
|
+
|
|
89
|
+
PR description should cover:
|
|
90
|
+
|
|
91
|
+
- **What** changed (one or two sentences).
|
|
92
|
+
- **Why** the change is needed (link to an issue or email thread if relevant).
|
|
93
|
+
- **How it was tested** — which tests you ran, which tutorials you re-executed,
|
|
94
|
+
any benchmark numbers.
|
|
95
|
+
- **Verification impact** — if your change could affect log-likelihoods,
|
|
96
|
+
explicitly state whether you re-ran the Table 1 verification (see below).
|
|
97
|
+
|
|
98
|
+
### 4. Review and merge
|
|
99
|
+
|
|
100
|
+
A maintainer reviews the PR, may request changes, and merges it. While the
|
|
101
|
+
PR is open:
|
|
102
|
+
|
|
103
|
+
- Push new commits to the same branch — they update the PR automatically.
|
|
104
|
+
- Do not force-push unless asked.
|
|
105
|
+
- Do not merge `main` into your branch unless requested; rebase if you must
|
|
106
|
+
update.
|
|
107
|
+
|
|
108
|
+
After merge, delete your branch:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
git checkout main
|
|
112
|
+
git pull origin main
|
|
113
|
+
git branch -d fix-mixture-shared-coefs
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Numerical verification (important)
|
|
117
|
+
|
|
118
|
+
pybhatlib reproduces exact log-likelihood values from BHATLIB Table 1:
|
|
119
|
+
|
|
120
|
+
| Model | LL |
|
|
121
|
+
|-------|-----|
|
|
122
|
+
| (a)(i) IID | −670.956 |
|
|
123
|
+
| (a)(ii) Flexible | −661.111 |
|
|
124
|
+
| (b) + AGE45 | −659.285 |
|
|
125
|
+
| (c) Random coefficient | −635.871 |
|
|
126
|
+
| (d) Mixture (nseg=2) | ≈−634.975 |
|
|
127
|
+
|
|
128
|
+
If your change touches any code under `src/pybhatlib/gradmvn/`,
|
|
129
|
+
`src/pybhatlib/matgradient/`, `src/pybhatlib/vecup/`, or
|
|
130
|
+
`src/pybhatlib/models/mnp/`, run the Table 1 tutorial locally before
|
|
131
|
+
requesting review:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
jupyter nbconvert --to notebook --execute examples/tutorials/t04h_bhatlib_table1.ipynb
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Include the resulting LL values in the PR description. If they differ from
|
|
138
|
+
the table, explain why the change is intentional — do not merge a regression
|
|
139
|
+
without discussion.
|
|
140
|
+
|
|
141
|
+
## Code standards
|
|
142
|
+
|
|
143
|
+
- **Python**: PEP 8, 88-char line length (matches `ruff` config).
|
|
144
|
+
- **Type hints** on all public function signatures.
|
|
145
|
+
- **Docstrings** in NumPy style on all public functions.
|
|
146
|
+
- **Backend-aware numerical code** accepts an optional `xp` keyword for
|
|
147
|
+
NumPy / PyTorch backend selection.
|
|
148
|
+
- **Numba-compatible** in hot paths — use `scipy.special.ndtr`, not
|
|
149
|
+
`scipy.stats.norm.cdf`; avoid Python-level scipy.stats objects inside
|
|
150
|
+
JIT-compiled functions.
|
|
151
|
+
- **No module-level mutable state** — thread safety matters for parallel
|
|
152
|
+
gradient evaluations.
|
|
153
|
+
- **Private modules** are prefixed with an underscore (`_vec_ops.py`).
|
|
154
|
+
|
|
155
|
+
## Running specific test subsets
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
pytest tests/ # Everything including slow integration tests
|
|
159
|
+
pytest tests/ -m "not slow" # Skip slow tests (what CI runs)
|
|
160
|
+
pytest tests/ -m torch # Only PyTorch-backend tests (needs torch installed)
|
|
161
|
+
pytest tests/test_models/ # Just the model tests
|
|
162
|
+
pytest tests/ -k mnp # Tests matching "mnp" in name
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Scope rules
|
|
166
|
+
|
|
167
|
+
- **One logical change per PR.** Bundling a bug fix, a feature, and a refactor
|
|
168
|
+
into one PR makes review painful and makes `git bisect` useless if a
|
|
169
|
+
regression shows up later.
|
|
170
|
+
- **Do not reformat unrelated code** in your PR. If you notice style issues
|
|
171
|
+
elsewhere, open a separate PR for cleanup.
|
|
172
|
+
- **Performance changes need before/after numbers.** "Faster" is not
|
|
173
|
+
reviewable; "1.40s → 0.82s on Table 1 Model (a)(ii)" is.
|
|
174
|
+
- **Feature additions that change model semantics** (e.g., allowing
|
|
175
|
+
coefficients to be shared across mixture segments) should include a test
|
|
176
|
+
that pins the new behavior.
|
|
177
|
+
|
|
178
|
+
## Getting help
|
|
179
|
+
|
|
180
|
+
- **Questions about an existing PR**: comment on the PR directly.
|
|
181
|
+
- **Questions about where to start**: open an issue with the `question` label.
|
|
182
|
+
- **Something is broken**: open an issue with a minimal reproducer and the
|
|
183
|
+
output of `pip freeze`.
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
By contributing, you agree that your contributions are licensed under the
|
|
188
|
+
MIT license (see `LICENSE`).
|
pybhatlib-0.3.2/PKG-INFO
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pybhatlib
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: Python implementation of BHATLIB: matrix-based inference for advanced econometric models
|
|
5
|
+
Project-URL: Homepage, https://github.com/UMN-Choi-Lab/pybhatlib
|
|
6
|
+
Project-URL: Repository, https://github.com/UMN-Choi-Lab/pybhatlib
|
|
7
|
+
Project-URL: Documentation, https://github.com/UMN-Choi-Lab/pybhatlib#readme
|
|
8
|
+
Project-URL: Issues, https://github.com/UMN-Choi-Lab/pybhatlib/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Seongjin Choi <choi@umn.edu>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: MVNCD,covariance matrix,discrete choice,econometrics,multinomial probit,transportation
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: numba>=0.59
|
|
23
|
+
Requires-Dist: numpy>=1.24
|
|
24
|
+
Requires-Dist: pandas>=2.0
|
|
25
|
+
Requires-Dist: scipy>=1.10
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: mypy; extra == 'all'
|
|
28
|
+
Requires-Dist: pytest-cov; extra == 'all'
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == 'all'
|
|
30
|
+
Requires-Dist: ruff; extra == 'all'
|
|
31
|
+
Requires-Dist: torch>=2.0; extra == 'all'
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
37
|
+
Provides-Extra: torch
|
|
38
|
+
Requires-Dist: torch>=2.0; extra == 'torch'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# pybhatlib
|
|
42
|
+
|
|
43
|
+
[](https://pypi.org/project/pybhatlib/)
|
|
44
|
+
[](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/LICENSE)
|
|
45
|
+
|
|
46
|
+
Python reimplementation of **BHATLIB** — an open-source library for statistical and
|
|
47
|
+
econometric matrix-based inference methods.
|
|
48
|
+
|
|
49
|
+
BHATLIB (Bhat, Clower, Haddad, Jones; UT Austin / Aptech Systems) provides efficient
|
|
50
|
+
matrix operations, gradient-enabled routines for multivariate distribution evaluation
|
|
51
|
+
(including Bhat's 2018 MVNCD analytic approximation), and pre-built econometric models.
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git clone https://github.com/UMN-Choi-Lab/pybhatlib.git
|
|
57
|
+
cd pybhatlib
|
|
58
|
+
pip install -e . # core (NumPy + SciPy + Numba)
|
|
59
|
+
pip install -e ".[torch]" # add PyTorch backend (optional GPU)
|
|
60
|
+
pip install -e ".[dev]" # add pytest, ruff, mypy
|
|
61
|
+
pip install -e ".[all]" # everything (torch + dev)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quick Start — Multinomial Probit (MNP)
|
|
65
|
+
|
|
66
|
+
Sample data: `examples/data/TRAVELMODE.csv` (3 modes — DA / SR / TR, 1125 observations).
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from pybhatlib.models.mnp import MNPModel, MNPControl
|
|
70
|
+
|
|
71
|
+
model = MNPModel(
|
|
72
|
+
data="examples/data/TRAVELMODE.csv",
|
|
73
|
+
alternatives=["Alt1_ch", "Alt2_ch", "Alt3_ch"],
|
|
74
|
+
availability="none",
|
|
75
|
+
spec={
|
|
76
|
+
"CON_SR": {"Alt1_ch": "sero", "Alt2_ch": "uno", "Alt3_ch": "sero"},
|
|
77
|
+
"CON_TR": {"Alt1_ch": "sero", "Alt2_ch": "sero", "Alt3_ch": "uno"},
|
|
78
|
+
"IVTT": {"Alt1_ch": "IVTT_DA", "Alt2_ch": "IVTT_SR", "Alt3_ch": "IVTT_TR"},
|
|
79
|
+
"OVTT": {"Alt1_ch": "OVTT_DA", "Alt2_ch": "OVTT_SR", "Alt3_ch": "OVTT_TR"},
|
|
80
|
+
"COST": {"Alt1_ch": "COST_DA", "Alt2_ch": "COST_SR", "Alt3_ch": "COST_TR"},
|
|
81
|
+
},
|
|
82
|
+
control=MNPControl(iid=True),
|
|
83
|
+
)
|
|
84
|
+
results = model.fit()
|
|
85
|
+
results.summary()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Quick Start — Multivariate Ordered Response Probit (MORP)
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from pybhatlib.models.morp import MORPModel, MORPControl
|
|
92
|
+
|
|
93
|
+
model = MORPModel(
|
|
94
|
+
data=df, # DataFrame or CSV path
|
|
95
|
+
dep_vars=["satisfaction", "recommendation"], # ordinal outcome columns
|
|
96
|
+
spec={
|
|
97
|
+
"income": {"satisfaction": "income", "recommendation": "income"},
|
|
98
|
+
"age": {"satisfaction": "age", "recommendation": "age"},
|
|
99
|
+
"education": {"satisfaction": "education", "recommendation": "education"},
|
|
100
|
+
},
|
|
101
|
+
n_categories=[3, 3],
|
|
102
|
+
control=MORPControl(iid=True, seed=42),
|
|
103
|
+
)
|
|
104
|
+
results = model.fit()
|
|
105
|
+
results.summary()
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
A runnable end-to-end example (with `morp_ate`, `morp_predict`,
|
|
109
|
+
`morp_predict_category`) is at
|
|
110
|
+
[`examples/tutorials/t05b_morp_ate_predict.ipynb`](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/examples/tutorials/t05b_morp_ate_predict.ipynb).
|
|
111
|
+
|
|
112
|
+
## Features
|
|
113
|
+
|
|
114
|
+
**Models**
|
|
115
|
+
- **Multinomial Probit (MNP)** — IID, flexible covariance, heteroscedastic-only,
|
|
116
|
+
random coefficients, mixture-of-normals
|
|
117
|
+
- **Multivariate Ordered Response Probit (MORP)** — multiple ordinal outcomes
|
|
118
|
+
with shared covariance; per-outcome `spec` mapping
|
|
119
|
+
- **Multiple Discrete-Continuous Extreme Value (MDCEV)** — traditional
|
|
120
|
+
(Bhat 2008) and linear (Bhat 2018) outside-good utility specifications,
|
|
121
|
+
selected via `MDCEVControl.utility`
|
|
122
|
+
|
|
123
|
+
**Numerical core**
|
|
124
|
+
- `vecup` — vecdup, matdupfull, LDLT decomposition, truncated MVN moments
|
|
125
|
+
- `matgradient` — gradcovcor, gomegxomegax, spherical / Cholesky parameterizations
|
|
126
|
+
- `gradmvn` — Bhat (2018) MVNCD analytic approximation with analytic gradients
|
|
127
|
+
|
|
128
|
+
**Estimation**
|
|
129
|
+
- Multiple SE estimators (`se_method="bhhh" | "hessian" | "sandwich"`); BHHH is
|
|
130
|
+
the default to match GAUSS BHATLIB's `_max_CovPar=2`. All three are computed
|
|
131
|
+
at fit time and exposed as `se_bhhh` / `se_hessian` / `se_sandwich`;
|
|
132
|
+
`results.summary()` prints a side-by-side diagnostic block (a large
|
|
133
|
+
Hessian/BHHH divergence is a misspecification signal).
|
|
134
|
+
- `MNPControl.active_mask` to freeze a subset of parameters at their starting
|
|
135
|
+
values without recoding the model.
|
|
136
|
+
- `verbose` levels: `0` silent, `1` summary, `2` per-iteration NLL,
|
|
137
|
+
`3` per-iteration parameter / gradient / relative-gradient table.
|
|
138
|
+
|
|
139
|
+
**Backend**
|
|
140
|
+
- NumPy by default; optional PyTorch backend with GPU support (install with
|
|
141
|
+
`[torch]`). All numerical functions take an optional `xp` kwarg.
|
|
142
|
+
|
|
143
|
+
**Post-estimation**
|
|
144
|
+
- Average Treatment Effects (ATE) with scenario-matrix support, forecasting,
|
|
145
|
+
per-category MORP probability prediction.
|
|
146
|
+
- MORP ATEs from supplied coefficients without re-fitting:
|
|
147
|
+
`MORPResults.from_estimates(beta, thresholds, correlation)` rebuilds a results
|
|
148
|
+
object from natural-space estimates, and `morp_ate_from_params` /
|
|
149
|
+
`morp_joint_probs` (mean joint category-combination probabilities, the GAUSS
|
|
150
|
+
`ate1.csv` equivalent) compute effects directly from them.
|
|
151
|
+
|
|
152
|
+
## Verification
|
|
153
|
+
|
|
154
|
+
pybhatlib reproduces Table 1 from the BHATLIB paper (Bhat 2018) using the
|
|
155
|
+
TRAVELMODE dataset (3 modes — DA, SR, TR; 1125 observations):
|
|
156
|
+
|
|
157
|
+
| Model | Specification | Target LL | Achieved LL | Status |
|
|
158
|
+
|-------|--------------|-----------|-------------|--------|
|
|
159
|
+
| (a)(i) | IID errors | -670.956 | -670.956 | exact match |
|
|
160
|
+
| (a)(ii) | Flexible covariance | -661.111 | -661.111 | exact match |
|
|
161
|
+
| (b) | + AGE45 demographics | -659.285 | -659.284 | exact match |
|
|
162
|
+
| (c) | + Random coeff. OVTT | -635.871 | -635.871 | exact match |
|
|
163
|
+
| (d) | 2-segment mixture | -634.975 | -632.912 | close (multi-modal) |
|
|
164
|
+
|
|
165
|
+
Models (a)–(c) reproduce the published estimates and BHHH standard errors to
|
|
166
|
+
≤0.001 on every parameter (verified end-to-end against GAUSS 26.1.1 + MaxLik
|
|
167
|
+
5.0.9). Model (d) is documented as multi-modal — the Python optimum is a
|
|
168
|
+
slightly better local mode than the published one.
|
|
169
|
+
|
|
170
|
+
For MORP, `iid=False` now uses GAUSS BHATLIB's unit-variance identification by
|
|
171
|
+
default (`MORPControl.fix_scales=True`): the latent-utility variances are fixed
|
|
172
|
+
at 1 and only correlations are estimated. The full-covariance `MORP_DINING` /
|
|
173
|
+
`MORP_WALK` models reproduce the GAUSS mean log-likelihoods (−4.6598 / −3.7591)
|
|
174
|
+
and correlation matrices. `summary()` reports the actual threshold cut-points
|
|
175
|
+
(with delta-method standard errors) and a gradient column, matching GAUSS's
|
|
176
|
+
output. See `docs/plans/MORP_BHATLIB_PARITY.md`.
|
|
177
|
+
|
|
178
|
+
The driving notebooks are
|
|
179
|
+
[`t04h_bhatlib_table1.ipynb`](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/examples/tutorials/t04h_bhatlib_table1.ipynb) and
|
|
180
|
+
[`t04i_bhat2018_table2.ipynb`](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/examples/tutorials/t04i_bhat2018_table2.ipynb).
|
|
181
|
+
|
|
182
|
+
## Tutorials
|
|
183
|
+
|
|
184
|
+
A complete tutorial series lives under
|
|
185
|
+
[`examples/tutorials/`](https://github.com/UMN-Choi-Lab/pybhatlib/tree/main/examples/tutorials/) as Jupyter notebooks (each with a
|
|
186
|
+
matching `.py` script under `python_scripts/`):
|
|
187
|
+
|
|
188
|
+
| Track | Notebooks |
|
|
189
|
+
|-------|-----------|
|
|
190
|
+
| Foundations | `t00_quickstart`, `t01a_vectorization`, `t01b_ldlt`, `t01c_truncated_mvn` |
|
|
191
|
+
| Matrix gradients | `t02a_gradcovcor`, `t02b_spherical`, `t02c_chain_rules` |
|
|
192
|
+
| MVNCD | `t03a_mvncd_methods`, `t03b_mvncd_gradients`, `t03c_mvncd_rect`, `t03d_univariate_cdfs`, `t03e_bhat2018_table1` |
|
|
193
|
+
| MNP | `t04a_mnp_iid` … `t04g_mnp_forecasting`, `t04h_bhatlib_table1`, `t04i_bhat2018_table2` |
|
|
194
|
+
| MORP | `t05b_morp_ate_predict` |
|
|
195
|
+
| MDCEV | `t07a_mdcev_trad`, `t07b_mdcev_lin` |
|
|
196
|
+
| Backends & verification | `t06a_backend_switching`, `t06b_custom_specs`, `t06c_gradient_verification` |
|
|
197
|
+
|
|
198
|
+
## Contributing
|
|
199
|
+
|
|
200
|
+
See [`CONTRIBUTING.md`](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/CONTRIBUTING.md) for development setup, the PR-test
|
|
201
|
+
workflow, and CODEOWNERS conventions. Key tests:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
pytest tests/ # full suite
|
|
205
|
+
pytest tests/ -m "not slow" # skip integration tests
|
|
206
|
+
pytest tests/ -m torch # PyTorch backend tests only
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## References
|
|
210
|
+
|
|
211
|
+
1. Bhat, C. R. (2018). New Matrix-Based Methods for the Analytic Evaluation of the
|
|
212
|
+
Multivariate Cumulative Normal Distribution Function. *Transportation Research
|
|
213
|
+
Part B*, 109: 238–256.
|
|
214
|
+
2. Bhat, C. R., Clower, E., Haddad, A. J., Jones, J. BHATLIB: An Open-Source
|
|
215
|
+
Library for Statistical and Econometric Matrix-Based Inference Methods in GAUSS.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# pybhatlib
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/pybhatlib/)
|
|
4
|
+
[](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
Python reimplementation of **BHATLIB** — an open-source library for statistical and
|
|
7
|
+
econometric matrix-based inference methods.
|
|
8
|
+
|
|
9
|
+
BHATLIB (Bhat, Clower, Haddad, Jones; UT Austin / Aptech Systems) provides efficient
|
|
10
|
+
matrix operations, gradient-enabled routines for multivariate distribution evaluation
|
|
11
|
+
(including Bhat's 2018 MVNCD analytic approximation), and pre-built econometric models.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/UMN-Choi-Lab/pybhatlib.git
|
|
17
|
+
cd pybhatlib
|
|
18
|
+
pip install -e . # core (NumPy + SciPy + Numba)
|
|
19
|
+
pip install -e ".[torch]" # add PyTorch backend (optional GPU)
|
|
20
|
+
pip install -e ".[dev]" # add pytest, ruff, mypy
|
|
21
|
+
pip install -e ".[all]" # everything (torch + dev)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start — Multinomial Probit (MNP)
|
|
25
|
+
|
|
26
|
+
Sample data: `examples/data/TRAVELMODE.csv` (3 modes — DA / SR / TR, 1125 observations).
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from pybhatlib.models.mnp import MNPModel, MNPControl
|
|
30
|
+
|
|
31
|
+
model = MNPModel(
|
|
32
|
+
data="examples/data/TRAVELMODE.csv",
|
|
33
|
+
alternatives=["Alt1_ch", "Alt2_ch", "Alt3_ch"],
|
|
34
|
+
availability="none",
|
|
35
|
+
spec={
|
|
36
|
+
"CON_SR": {"Alt1_ch": "sero", "Alt2_ch": "uno", "Alt3_ch": "sero"},
|
|
37
|
+
"CON_TR": {"Alt1_ch": "sero", "Alt2_ch": "sero", "Alt3_ch": "uno"},
|
|
38
|
+
"IVTT": {"Alt1_ch": "IVTT_DA", "Alt2_ch": "IVTT_SR", "Alt3_ch": "IVTT_TR"},
|
|
39
|
+
"OVTT": {"Alt1_ch": "OVTT_DA", "Alt2_ch": "OVTT_SR", "Alt3_ch": "OVTT_TR"},
|
|
40
|
+
"COST": {"Alt1_ch": "COST_DA", "Alt2_ch": "COST_SR", "Alt3_ch": "COST_TR"},
|
|
41
|
+
},
|
|
42
|
+
control=MNPControl(iid=True),
|
|
43
|
+
)
|
|
44
|
+
results = model.fit()
|
|
45
|
+
results.summary()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick Start — Multivariate Ordered Response Probit (MORP)
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from pybhatlib.models.morp import MORPModel, MORPControl
|
|
52
|
+
|
|
53
|
+
model = MORPModel(
|
|
54
|
+
data=df, # DataFrame or CSV path
|
|
55
|
+
dep_vars=["satisfaction", "recommendation"], # ordinal outcome columns
|
|
56
|
+
spec={
|
|
57
|
+
"income": {"satisfaction": "income", "recommendation": "income"},
|
|
58
|
+
"age": {"satisfaction": "age", "recommendation": "age"},
|
|
59
|
+
"education": {"satisfaction": "education", "recommendation": "education"},
|
|
60
|
+
},
|
|
61
|
+
n_categories=[3, 3],
|
|
62
|
+
control=MORPControl(iid=True, seed=42),
|
|
63
|
+
)
|
|
64
|
+
results = model.fit()
|
|
65
|
+
results.summary()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
A runnable end-to-end example (with `morp_ate`, `morp_predict`,
|
|
69
|
+
`morp_predict_category`) is at
|
|
70
|
+
[`examples/tutorials/t05b_morp_ate_predict.ipynb`](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/examples/tutorials/t05b_morp_ate_predict.ipynb).
|
|
71
|
+
|
|
72
|
+
## Features
|
|
73
|
+
|
|
74
|
+
**Models**
|
|
75
|
+
- **Multinomial Probit (MNP)** — IID, flexible covariance, heteroscedastic-only,
|
|
76
|
+
random coefficients, mixture-of-normals
|
|
77
|
+
- **Multivariate Ordered Response Probit (MORP)** — multiple ordinal outcomes
|
|
78
|
+
with shared covariance; per-outcome `spec` mapping
|
|
79
|
+
- **Multiple Discrete-Continuous Extreme Value (MDCEV)** — traditional
|
|
80
|
+
(Bhat 2008) and linear (Bhat 2018) outside-good utility specifications,
|
|
81
|
+
selected via `MDCEVControl.utility`
|
|
82
|
+
|
|
83
|
+
**Numerical core**
|
|
84
|
+
- `vecup` — vecdup, matdupfull, LDLT decomposition, truncated MVN moments
|
|
85
|
+
- `matgradient` — gradcovcor, gomegxomegax, spherical / Cholesky parameterizations
|
|
86
|
+
- `gradmvn` — Bhat (2018) MVNCD analytic approximation with analytic gradients
|
|
87
|
+
|
|
88
|
+
**Estimation**
|
|
89
|
+
- Multiple SE estimators (`se_method="bhhh" | "hessian" | "sandwich"`); BHHH is
|
|
90
|
+
the default to match GAUSS BHATLIB's `_max_CovPar=2`. All three are computed
|
|
91
|
+
at fit time and exposed as `se_bhhh` / `se_hessian` / `se_sandwich`;
|
|
92
|
+
`results.summary()` prints a side-by-side diagnostic block (a large
|
|
93
|
+
Hessian/BHHH divergence is a misspecification signal).
|
|
94
|
+
- `MNPControl.active_mask` to freeze a subset of parameters at their starting
|
|
95
|
+
values without recoding the model.
|
|
96
|
+
- `verbose` levels: `0` silent, `1` summary, `2` per-iteration NLL,
|
|
97
|
+
`3` per-iteration parameter / gradient / relative-gradient table.
|
|
98
|
+
|
|
99
|
+
**Backend**
|
|
100
|
+
- NumPy by default; optional PyTorch backend with GPU support (install with
|
|
101
|
+
`[torch]`). All numerical functions take an optional `xp` kwarg.
|
|
102
|
+
|
|
103
|
+
**Post-estimation**
|
|
104
|
+
- Average Treatment Effects (ATE) with scenario-matrix support, forecasting,
|
|
105
|
+
per-category MORP probability prediction.
|
|
106
|
+
- MORP ATEs from supplied coefficients without re-fitting:
|
|
107
|
+
`MORPResults.from_estimates(beta, thresholds, correlation)` rebuilds a results
|
|
108
|
+
object from natural-space estimates, and `morp_ate_from_params` /
|
|
109
|
+
`morp_joint_probs` (mean joint category-combination probabilities, the GAUSS
|
|
110
|
+
`ate1.csv` equivalent) compute effects directly from them.
|
|
111
|
+
|
|
112
|
+
## Verification
|
|
113
|
+
|
|
114
|
+
pybhatlib reproduces Table 1 from the BHATLIB paper (Bhat 2018) using the
|
|
115
|
+
TRAVELMODE dataset (3 modes — DA, SR, TR; 1125 observations):
|
|
116
|
+
|
|
117
|
+
| Model | Specification | Target LL | Achieved LL | Status |
|
|
118
|
+
|-------|--------------|-----------|-------------|--------|
|
|
119
|
+
| (a)(i) | IID errors | -670.956 | -670.956 | exact match |
|
|
120
|
+
| (a)(ii) | Flexible covariance | -661.111 | -661.111 | exact match |
|
|
121
|
+
| (b) | + AGE45 demographics | -659.285 | -659.284 | exact match |
|
|
122
|
+
| (c) | + Random coeff. OVTT | -635.871 | -635.871 | exact match |
|
|
123
|
+
| (d) | 2-segment mixture | -634.975 | -632.912 | close (multi-modal) |
|
|
124
|
+
|
|
125
|
+
Models (a)–(c) reproduce the published estimates and BHHH standard errors to
|
|
126
|
+
≤0.001 on every parameter (verified end-to-end against GAUSS 26.1.1 + MaxLik
|
|
127
|
+
5.0.9). Model (d) is documented as multi-modal — the Python optimum is a
|
|
128
|
+
slightly better local mode than the published one.
|
|
129
|
+
|
|
130
|
+
For MORP, `iid=False` now uses GAUSS BHATLIB's unit-variance identification by
|
|
131
|
+
default (`MORPControl.fix_scales=True`): the latent-utility variances are fixed
|
|
132
|
+
at 1 and only correlations are estimated. The full-covariance `MORP_DINING` /
|
|
133
|
+
`MORP_WALK` models reproduce the GAUSS mean log-likelihoods (−4.6598 / −3.7591)
|
|
134
|
+
and correlation matrices. `summary()` reports the actual threshold cut-points
|
|
135
|
+
(with delta-method standard errors) and a gradient column, matching GAUSS's
|
|
136
|
+
output. See `docs/plans/MORP_BHATLIB_PARITY.md`.
|
|
137
|
+
|
|
138
|
+
The driving notebooks are
|
|
139
|
+
[`t04h_bhatlib_table1.ipynb`](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/examples/tutorials/t04h_bhatlib_table1.ipynb) and
|
|
140
|
+
[`t04i_bhat2018_table2.ipynb`](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/examples/tutorials/t04i_bhat2018_table2.ipynb).
|
|
141
|
+
|
|
142
|
+
## Tutorials
|
|
143
|
+
|
|
144
|
+
A complete tutorial series lives under
|
|
145
|
+
[`examples/tutorials/`](https://github.com/UMN-Choi-Lab/pybhatlib/tree/main/examples/tutorials/) as Jupyter notebooks (each with a
|
|
146
|
+
matching `.py` script under `python_scripts/`):
|
|
147
|
+
|
|
148
|
+
| Track | Notebooks |
|
|
149
|
+
|-------|-----------|
|
|
150
|
+
| Foundations | `t00_quickstart`, `t01a_vectorization`, `t01b_ldlt`, `t01c_truncated_mvn` |
|
|
151
|
+
| Matrix gradients | `t02a_gradcovcor`, `t02b_spherical`, `t02c_chain_rules` |
|
|
152
|
+
| MVNCD | `t03a_mvncd_methods`, `t03b_mvncd_gradients`, `t03c_mvncd_rect`, `t03d_univariate_cdfs`, `t03e_bhat2018_table1` |
|
|
153
|
+
| MNP | `t04a_mnp_iid` … `t04g_mnp_forecasting`, `t04h_bhatlib_table1`, `t04i_bhat2018_table2` |
|
|
154
|
+
| MORP | `t05b_morp_ate_predict` |
|
|
155
|
+
| MDCEV | `t07a_mdcev_trad`, `t07b_mdcev_lin` |
|
|
156
|
+
| Backends & verification | `t06a_backend_switching`, `t06b_custom_specs`, `t06c_gradient_verification` |
|
|
157
|
+
|
|
158
|
+
## Contributing
|
|
159
|
+
|
|
160
|
+
See [`CONTRIBUTING.md`](https://github.com/UMN-Choi-Lab/pybhatlib/blob/main/CONTRIBUTING.md) for development setup, the PR-test
|
|
161
|
+
workflow, and CODEOWNERS conventions. Key tests:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
pytest tests/ # full suite
|
|
165
|
+
pytest tests/ -m "not slow" # skip integration tests
|
|
166
|
+
pytest tests/ -m torch # PyTorch backend tests only
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## References
|
|
170
|
+
|
|
171
|
+
1. Bhat, C. R. (2018). New Matrix-Based Methods for the Analytic Evaluation of the
|
|
172
|
+
Multivariate Cumulative Normal Distribution Function. *Transportation Research
|
|
173
|
+
Part B*, 109: 238–256.
|
|
174
|
+
2. Bhat, C. R., Clower, E., Haddad, A. J., Jones, J. BHATLIB: An Open-Source
|
|
175
|
+
Library for Statistical and Econometric Matrix-Based Inference Methods in GAUSS.
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT
|