diff --git a/CHANGELOG.md b/CHANGELOG.md index 53683f1c..2be0ab30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,28 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.26.0.dev3] - 2026-10-14 - -### Added - -- Added `benchmarks/hierarchical_profile.py`, which shows where the time of a `VariationalBayes` fit goes and counts the objective evaluations per participant and iteration; against cbm (RLRW, 100 participants, 120 trials), cpm makes about as many evaluations but each one costs more, at 17.3 against 5.0 ms per participant and iteration -- Added a `hessian` argument to `cpm.optimisation.FminBound`, `Fmin`, `Minimize` and `Bads`; `hessian="finite_differences"` computes the Hessian at the optimum with bounded finite differences (`cpm.core.optimisers.finite_difference_hessian`), cutting Hessian evaluations from 22 to 7 per participant and iteration in the speed comparison. The default, `"numdifftools"`, keeps the previous Hessian -- Added a `start` argument to `cpm.hierarchical.EmpiricalBayes` and `cpm.hierarchical.VariationalBayes`; `start="prior_mean"` starts the first optimisation of every participant from the current prior's location, clipped into the bounds, as cbm does, so fits stop sooner. The default, `"random"`, keeps the previous starts -- Added a `positive_definite` column to the `fit` of `cpm.hierarchical.EmpiricalBayes` and `cpm.hierarchical.VariationalBayes`, recording whether each participant's Hessian was positive definite, and a `not_positive_definite` column to their `hyperparameters` with the count; an estimate on a bound can have a non-positive-definite Hessian and is kept, as the bounds require -- Added the results of the speed comparison with cbm (100 participants, 120 trials) in `benchmarks/results/hierarchical-comparison-*.csv`: combining `hessian="finite_differences"`, `start="prior_mean"` and `number_of_starts=1` brings `EmpiricalBayes`/`VariationalBayes` from 20.8/20.1 to 6.8/7.0 ms per participant and iteration, against cbm's 4.4 ms, with RMSE against 0.26.0.dev1 staying within bootstrap 95% intervals throughout - -### Changed - -- `cpm.optimisation.FminBound` with `approx_grad=True` now computes the finite-difference gradient itself, together with the objective, exactly as SciPy does, with identical results; with `LogLikelihood.bernoulli`, this makes the hierarchical fits of the speed comparison 19% faster -- The defaults of the new arguments, `hessian="numdifftools"` and `start="random"`, give the same results as before for the same seed; the faster options have to be chosen - -### Fixed - -- Fixed fits with `parallel=True` and `prior=True` going back to the priors the model was created with after the first evaluation in every worker, so that priors updated with `update_prior`, such as the population priors of `cpm.hierarchical.EmpiricalBayes` and `cpm.hierarchical.VariationalBayes`, were ignored; parallel fits now equal serial ones, and parallel results with updated priors change. `cpm.generators` no longer deletes its submodules, which made dill copy its classes into the workers instead of referencing them -- Fixed `Fmin`, `FminBound`, `Minimize` and `Bads` comparing every later start with the first instead of the best so far, which with three or more starts could replace a participant's best fit with a worse one; results with three or more starts can change -- Fixed the `cpm.hierarchical.VariationalBayes` docstring giving 1000 as the default of `iteration`, which is 50 - -## [0.26.0.dev2] - 2026-10-06 +## [0.26.0] - 2026-10-16 ### Added @@ -51,6 +30,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added test units for `SessionWrapper`, `cpm.models.kernels`, the fast priors, and the built-in applications with and without numba - Added a benchmark suite (`benchmarks/run.py` for one evaluation, `benchmarks/hierarchical.py` for the hierarchical tutorials) and `scripts/local_tests.py`, which runs the tests with and without numba - Added a GitHub Actions workflow that runs the tests with and without numba, on Python 3.11 to 3.14 +- Added `benchmarks/hierarchical_profile.py`, which shows where the time of a `VariationalBayes` fit goes and counts the objective evaluations per participant and iteration; against cbm (RLRW, 100 participants, 120 trials), cpm makes about as many evaluations but each one costs more, at 17.3 against 5.0 ms per participant and iteration +- Added a `hessian` argument to `cpm.optimisation.FminBound`, `Fmin`, `Minimize` and `Bads`; `hessian="finite_differences"` computes the Hessian at the optimum with bounded finite differences (`cpm.core.optimisers.finite_difference_hessian`), cutting Hessian evaluations from 22 to 7 per participant and iteration in the speed comparison. The default, `"numdifftools"`, keeps the previous Hessian +- Added a `start` argument to `cpm.hierarchical.EmpiricalBayes` and `cpm.hierarchical.VariationalBayes`; `start="prior_mean"` starts the first optimisation of every participant from the current prior's location, clipped into the bounds, as cbm does, so fits stop sooner. The default, `"random"`, keeps the previous starts +- Added a `positive_definite` column to the `fit` of `cpm.hierarchical.EmpiricalBayes` and `cpm.hierarchical.VariationalBayes`, recording whether each participant's Hessian was positive definite, and a `not_positive_definite` column to their `hyperparameters` with the count; an estimate on a bound can have a non-positive-definite Hessian and is kept, as the bounds require +- Added the results of the speed comparison with cbm (100 participants, 120 trials) in `benchmarks/results/hierarchical-comparison-*.csv`: combining `hessian="finite_differences"`, `start="prior_mean"` and `number_of_starts=1` brings `EmpiricalBayes`/`VariationalBayes` from 20.8/20.1 to 6.8/7.0 ms per participant and iteration, against cbm's 4.4 ms, with RMSE against 0.26.0.dev1 staying within bootstrap 95% intervals throughout ### Changed @@ -70,6 +54,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `cpm.models.activation.ProspectUtility.weights` and `.utilities` are float arrays instead of object arrays, and the `simulation` records of `HybridMBMF` hold NumPy scalars instead of Python numbers - `PTSM2025` always uses its power utility: replacing `parameters.utility_curvature` on a model no longer changes it - Required Python 3.11 or later (previously `>3.11.0`, which excluded 3.11.0), removed the PyPy classifier, and tagged the wheel for Python 3 only +- `cpm.optimisation.FminBound` with `approx_grad=True` now computes the finite-difference gradient itself, together with the objective, exactly as SciPy does, with identical results; with `LogLikelihood.bernoulli`, this makes the hierarchical fits of the speed comparison 19% faster +- The defaults of the new arguments, `hessian="numdifftools"` and `start="random"`, give the same results as before for the same seed; the faster options have to be chosen ### Fixed @@ -101,6 +87,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed a clean install raising `ModuleNotFoundError` in `diagnostics()`, by adding `matplotlib` to the dependencies - Fixed `cpm.utils.data` and `cpm.utils.metad` not being reachable after `import cpm` - Fixed `cpm.core.diagnostics.gelman_rubin` and `cpm.core.diagnostics.psrf` failing on every call, and `gelman_rubin` computing the statistic incorrectly +- Fixed fits with `parallel=True` and `prior=True` going back to the priors the model was created with after the first evaluation in every worker, so that priors updated with `update_prior`, such as the population priors of `cpm.hierarchical.EmpiricalBayes` and `cpm.hierarchical.VariationalBayes`, were ignored; parallel fits now equal serial ones, and parallel results with updated priors change. `cpm.generators` no longer deletes its submodules, which made dill copy its classes into the workers instead of referencing them +- Fixed `Fmin`, `FminBound`, `Minimize` and `Bads` comparing every later start with the first instead of the best so far, which with three or more starts could replace a participant's best fit with a worse one; results with three or more starts can change +- Fixed the `cpm.hierarchical.VariationalBayes` docstring giving 1000 as the default of `iteration`, which is 50 ## [0.25.6] - 2026-04-15 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d8b1c6a1..85b5ec5b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -209,11 +209,18 @@ Best ways to get help: ## Build and release notes -If you are preparing a release artifact: +To prepare a release: -```bash -python setup.py sdist bdist_wheel -``` +1. Set the version in `cpm/__version__.py` and date its section in `CHANGELOG.md`. +2. Build and check the source distribution and wheel: + + ```bash + pip install build twine + python -m build + twine check dist/* + ``` + +3. After merging into `main`, tag the release with the bare version (for example `0.26.0`, not `v0.26.0`); the documentation links to the source at this tag. Publishing to PyPI is maintainer-only and typically done with: diff --git a/LICENSES-BUNDLE b/LICENSES-BUNDLE index b9fbfc9b..7c8cb514 100644 --- a/LICENSES-BUNDLE +++ b/LICENSES-BUNDLE @@ -4,16 +4,16 @@ The cpm repository and source distributions bundle a number of libraries that are compatibly licensed. We list these here. Name: metadpy -Files: cpm/application/signal_detection.py +Files: cpm/applications/signal_detection.py License: GPLv3 - For details, see header comments in cpm/application/signal_detection.py. + For details, see header comments in cpm/applications/signal_detection.py. Name: meta-d MATLAB scripts Files: cpm/applications/signal_detection.py License: None - For details, see header comments in cpm/application/signal_detection.py. + For details, see header comments in cpm/applications/signal_detection.py. The MATLAB scripts are not included in the cpm repository, but are - referenced in the cpm/application/signal_detection.py file. + referenced in the cpm/applications/signal_detection.py file. The MATLAB scripts are available at and were written by Brian Maniscalco. There is no accompanying license information, but they are still referenced here for completeness. diff --git a/README.md b/README.md index e1f9fe4c..a717d493 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ python -m sphinx -b html docs docs/_build/html ``` Then open `docs/_build/html/index.html` in a browser. -See [CONTRIBUTING.md](CONTRIBUTING.md) for how to write documentation and tutorials, and for a live preview while you write. +See [CONTRIBUTING.md](https://github.com/DevComPsy/cpm/blob/main/CONTRIBUTING.md) for how to write documentation and tutorials, and for a live preview while you write. The documentation is published to GitHub Pages by the `docs` GitHub Actions workflow whenever `main` changes. diff --git a/cpm/__version__.py b/cpm/__version__.py index 1f113989..7c4a9591 100644 --- a/cpm/__version__.py +++ b/cpm/__version__.py @@ -1 +1 @@ -__version__ = "0.26.0.dev3" +__version__ = "0.26.0" diff --git a/docs/news/2026-09-faster-fitting.md b/docs/news/2026-09-faster-fitting.md index 21a7b0a9..1f5bd6ce 100644 --- a/docs/news/2026-09-faster-fitting.md +++ b/docs/news/2026-09-faster-fitting.md @@ -7,7 +7,7 @@ kernelspec: # Faster fitting in cpm 0.26 -*28 September 2026 · cpm 0.26.0, in development* +*28 September 2026 · cpm 0.26.0* The built-in models of cpm now compute all trials of a participant in one call instead of one call per trial, and, when [numba](https://numba.pydata.org/) is installed, that loop over trials is compiled. Fitting them is 90 to 220 times faster than in cpm 0.25, and more than 1,000 times faster for {py:class}`~cpm.applications.decision_making.PTSM2025`, with the same results. diff --git a/pyproject.toml b/pyproject.toml index 64227bae..87e4ddbe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] requires = [ - "setuptools>=61.0", + "setuptools>=77.0", ] build-backend = "setuptools.build_meta" @@ -20,15 +20,22 @@ authors = [ maintainers = [ { name = "Lenard Dome", email = "lenarddome@gmail.com" } ] -license = { text = "AGPLv3" } +license = "AGPL-3.0-only" +license-files = ["LICENSE", "LICENSES-BUNDLE"] requires-python = ">=3.11" keywords = ["cpm-toolbox", "cpm", "computational-psychiatry", "computational-psychology", "psychometrics", "psychology"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", - "License :: OSI Approved :: GNU Affero General Public License v3", + "Intended Audience :: Science/Research", "Natural Language :: English", - "Programming Language :: Python :: 3" + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Topic :: Scientific/Engineering" ] dependencies = [ "numpy>=2.0.0", @@ -78,6 +85,9 @@ notebooks = [ [project.urls] Homepage = "https://cpm-toolbox.net" Documentation = "https://devcompsy.github.io/cpm/" +Repository = "https://github.com/DevComPsy/cpm" +Issues = "https://github.com/DevComPsy/cpm/issues" +Changelog = "https://github.com/DevComPsy/cpm/blob/main/CHANGELOG.md" [tool.setuptools] include-package-data = true