From 65a22adfdff7ac4c4d9f8dc4e4ea6f5211ed9ee5 Mon Sep 17 00:00:00 2001 From: Stanislav Khrapov Date: Mon, 20 Apr 2026 16:30:26 +0200 Subject: [PATCH 1/4] chore: Release management --- .github/workflows/bump-version.yaml | 32 + .github/workflows/workflow.yaml | 64 + .gitignore | 1 + README.rst | 3 + examples/try_centtend.py | 6 +- examples/try_cir.py | 6 +- examples/try_gbm.py | 6 +- examples/try_heston.py | 6 +- examples/try_vasicek.py | 6 +- pyproject.toml | 11 +- setup.py | 4 +- src/{diffusions => affidiff}/__init__.py | 0 .../helper_functions.py | 0 src/{diffusions => affidiff}/model_cir.py | 0 src/{diffusions => affidiff}/model_ct.py | 0 src/{diffusions => affidiff}/model_gbm.py | 0 src/{diffusions => affidiff}/model_generic.py | 0 src/{diffusions => affidiff}/model_heston.py | 0 src/{diffusions => affidiff}/model_vasicek.py | 0 src/{diffusions => affidiff}/param_cir.py | 0 src/{diffusions => affidiff}/param_ct.py | 0 src/{diffusions => affidiff}/param_gbm.py | 0 src/{diffusions => affidiff}/param_generic.py | 0 src/{diffusions => affidiff}/param_heston.py | 0 src/{diffusions => affidiff}/param_vasicek.py | 0 src/{diffusions => affidiff}/simulate.pyx | 0 src/{diffusions => affidiff}/symbolic.py | 0 tests/test_ajd.py | 6 +- tests/test_generic.py | 6 +- tests/test_helpers.py | 4 +- tests/test_param_cir.py | 2 +- tests/test_param_ct.py | 2 +- tests/test_param_gbm.py | 2 +- tests/test_param_heston.py | 2 +- tests/test_param_vasicek.py | 2 +- tests/test_rmoms_ct.py | 2 +- tests/test_rmoms_gbm.py | 2 +- tests/test_rmoms_heston.py | 2 +- tests/test_simulations.py | 1212 ++++++++--------- uv.lock | 249 +++- 40 files changed, 988 insertions(+), 650 deletions(-) create mode 100644 .github/workflows/bump-version.yaml create mode 100644 .github/workflows/workflow.yaml create mode 100644 README.rst rename src/{diffusions => affidiff}/__init__.py (100%) rename src/{diffusions => affidiff}/helper_functions.py (100%) rename src/{diffusions => affidiff}/model_cir.py (100%) rename src/{diffusions => affidiff}/model_ct.py (100%) rename src/{diffusions => affidiff}/model_gbm.py (100%) rename src/{diffusions => affidiff}/model_generic.py (100%) rename src/{diffusions => affidiff}/model_heston.py (100%) rename src/{diffusions => affidiff}/model_vasicek.py (100%) rename src/{diffusions => affidiff}/param_cir.py (100%) rename src/{diffusions => affidiff}/param_ct.py (100%) rename src/{diffusions => affidiff}/param_gbm.py (100%) rename src/{diffusions => affidiff}/param_generic.py (100%) rename src/{diffusions => affidiff}/param_heston.py (100%) rename src/{diffusions => affidiff}/param_vasicek.py (100%) rename src/{diffusions => affidiff}/simulate.pyx (100%) rename src/{diffusions => affidiff}/symbolic.py (100%) diff --git a/.github/workflows/bump-version.yaml b/.github/workflows/bump-version.yaml new file mode 100644 index 0000000..bb71779 --- /dev/null +++ b/.github/workflows/bump-version.yaml @@ -0,0 +1,32 @@ +name: Bump version + +on: + push: + branches: + - main + +jobs: + bump-version: + if: "!startsWith(github.event.head_commit.message, 'bump:')" + runs-on: ubuntu-latest + name: "Bump version and create changelog with commitizen" + steps: + - name: Check out + uses: actions/checkout@v6 + with: + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + fetch-depth: 0 + - name: Create bump and changelog + uses: commitizen-tools/commitizen-action@master + with: + github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + changelog_increment_filename: body.md + push: true + - name: Release + uses: ncipollo/release-action@v1 + with: + tag: v${{ env.REVISION }} + bodyFile: "body.md" + skipIfReleaseExists: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml new file mode 100644 index 0000000..3fc2209 --- /dev/null +++ b/.github/workflows/workflow.yaml @@ -0,0 +1,64 @@ +name: Tests, Code Quality, Build + +on: + push: + tags: + - "*" + pull_request: + branches: + - main + +jobs: + + test: + name: Run unit tests + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v6 + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version-file: ".python-version" + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + cache-dependency-glob: "uv.lock" + - name: Install dependencies + run: uv sync --group dev + - name: Run test suite + run: uv run pytest + + publish: + name: Build and publish wheels + needs: [ test ] + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/affidiff/ + permissions: + id-token: write + contents: read + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + steps: + - name: Check out repository code + uses: actions/checkout@v6 + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version-file: ".python-version" + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + cache-dependency-glob: "uv.lock" + - name: Build + run: uv build + # Check that basic features work and we didn't miss to include crucial files + - name: Smoke test (wheel) + run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py + - name: Smoke test (source distribution) + run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py + - name: Publish + run: uv publish diff --git a/.gitignore b/.gitignore index 3fbf489..fe66852 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ __pycache__/ .venv/ *.egg-info .coverage +dist/ diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..ccbdb7b --- /dev/null +++ b/README.rst @@ -0,0 +1,3 @@ +# Affine Diffusions + +Simulation and estimation of Affine Diffusion models. diff --git a/examples/try_centtend.py b/examples/try_centtend.py index 2f40dd3..85ddaa6 100644 --- a/examples/try_centtend.py +++ b/examples/try_centtend.py @@ -15,9 +15,9 @@ from statsmodels.tsa.stattools import acf -from diffusions import CentTend, CentTendParam -from diffusions.helper_functions import (plot_trajectories, plot_final_distr, - plot_realized, take_time) +from affidiff import CentTend, CentTendParam +from affidiff.helper_functions import (plot_trajectories, plot_final_distr, + plot_realized, take_time) from load_real_data import load_data diff --git a/examples/try_cir.py b/examples/try_cir.py index 9459c6b..7f721f7 100644 --- a/examples/try_cir.py +++ b/examples/try_cir.py @@ -8,9 +8,9 @@ import seaborn as sns -from diffusions import CIR, CIRparam -from diffusions.helper_functions import (plot_trajectories, plot_final_distr, - plot_realized, take_time) +from affidiff import CIR, CIRparam +from affidiff.helper_functions import (plot_trajectories, plot_final_distr, + plot_realized, take_time) def try_simulation(): diff --git a/examples/try_gbm.py b/examples/try_gbm.py index f5d0d73..b883c71 100644 --- a/examples/try_gbm.py +++ b/examples/try_gbm.py @@ -9,9 +9,9 @@ import seaborn as sns import numpy as np -from diffusions import GBM, GBMparam -from diffusions.helper_functions import (plot_trajectories, plot_final_distr, - plot_realized, take_time) +from affidiff import GBM, GBMparam +from affidiff.helper_functions import (plot_trajectories, plot_final_distr, + plot_realized, take_time) def try_simulation(): diff --git a/examples/try_heston.py b/examples/try_heston.py index f152a4c..cfc6f28 100644 --- a/examples/try_heston.py +++ b/examples/try_heston.py @@ -15,9 +15,9 @@ from statsmodels.tsa.stattools import acf -from diffusions import Heston, HestonParam -from diffusions.helper_functions import (plot_trajectories, plot_final_distr, - plot_realized, take_time) +from affidiff import Heston, HestonParam +from affidiff.helper_functions import (plot_trajectories, plot_final_distr, + plot_realized, take_time) from load_real_data import load_data diff --git a/examples/try_vasicek.py b/examples/try_vasicek.py index 8f1f478..c7da229 100644 --- a/examples/try_vasicek.py +++ b/examples/try_vasicek.py @@ -8,9 +8,9 @@ import seaborn as sns -from diffusions import Vasicek, VasicekParam -from diffusions.helper_functions import (plot_trajectories, plot_final_distr, - plot_realized, take_time) +from affidiff import Vasicek, VasicekParam +from affidiff.helper_functions import (plot_trajectories, plot_final_distr, + plot_realized, take_time) def try_simulation(): diff --git a/pyproject.toml b/pyproject.toml index a8f71d1..2fa3fe1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,15 @@ [project] -name = "diffusions" +name = "affidiff" description = "Affine Diffusions. Simulation and estimation." authors = [{ name = "Stanislav Khrapov", email = "khrapovs@gmail.com" }] readme = "README.md" requires-python = ">=3.14" dependencies = [ + "matplotlib>=3.10.8", + "mygmm>=0.1.0", "numpy>=2.4.4", "scipy>=1.17.1", + "seaborn>=0.13.2", "statsmodels>=0.14.6", ] dynamic = ["version"] @@ -25,3 +28,9 @@ source = "uv-dynamic-versioning" [tool.uv-dynamic-versioning] fallback-version = "0.0.0" + +[tool.commitizen] +version_scheme = "semver" +version_provider = "scm" +update_changelog_on_bump = true +tag_format = "v$version" diff --git a/setup.py b/setup.py index d4dd4ba..b73c057 100644 --- a/setup.py +++ b/setup.py @@ -8,8 +8,8 @@ kwargs = {'libraries': [], 'include_dirs': [numpy.get_include()]} -ext_modules = [Extension('diffusions.simulate', - ['./diffusions/simulate.pyx'], **kwargs)] +ext_modules = [Extension('affidiff.simulate', + ['./src/affidiff/simulate.pyx'], **kwargs)] setup(name='diffusions', version='1.0', diff --git a/src/diffusions/__init__.py b/src/affidiff/__init__.py similarity index 100% rename from src/diffusions/__init__.py rename to src/affidiff/__init__.py diff --git a/src/diffusions/helper_functions.py b/src/affidiff/helper_functions.py similarity index 100% rename from src/diffusions/helper_functions.py rename to src/affidiff/helper_functions.py diff --git a/src/diffusions/model_cir.py b/src/affidiff/model_cir.py similarity index 100% rename from src/diffusions/model_cir.py rename to src/affidiff/model_cir.py diff --git a/src/diffusions/model_ct.py b/src/affidiff/model_ct.py similarity index 100% rename from src/diffusions/model_ct.py rename to src/affidiff/model_ct.py diff --git a/src/diffusions/model_gbm.py b/src/affidiff/model_gbm.py similarity index 100% rename from src/diffusions/model_gbm.py rename to src/affidiff/model_gbm.py diff --git a/src/diffusions/model_generic.py b/src/affidiff/model_generic.py similarity index 100% rename from src/diffusions/model_generic.py rename to src/affidiff/model_generic.py diff --git a/src/diffusions/model_heston.py b/src/affidiff/model_heston.py similarity index 100% rename from src/diffusions/model_heston.py rename to src/affidiff/model_heston.py diff --git a/src/diffusions/model_vasicek.py b/src/affidiff/model_vasicek.py similarity index 100% rename from src/diffusions/model_vasicek.py rename to src/affidiff/model_vasicek.py diff --git a/src/diffusions/param_cir.py b/src/affidiff/param_cir.py similarity index 100% rename from src/diffusions/param_cir.py rename to src/affidiff/param_cir.py diff --git a/src/diffusions/param_ct.py b/src/affidiff/param_ct.py similarity index 100% rename from src/diffusions/param_ct.py rename to src/affidiff/param_ct.py diff --git a/src/diffusions/param_gbm.py b/src/affidiff/param_gbm.py similarity index 100% rename from src/diffusions/param_gbm.py rename to src/affidiff/param_gbm.py diff --git a/src/diffusions/param_generic.py b/src/affidiff/param_generic.py similarity index 100% rename from src/diffusions/param_generic.py rename to src/affidiff/param_generic.py diff --git a/src/diffusions/param_heston.py b/src/affidiff/param_heston.py similarity index 100% rename from src/diffusions/param_heston.py rename to src/affidiff/param_heston.py diff --git a/src/diffusions/param_vasicek.py b/src/affidiff/param_vasicek.py similarity index 100% rename from src/diffusions/param_vasicek.py rename to src/affidiff/param_vasicek.py diff --git a/src/diffusions/simulate.pyx b/src/affidiff/simulate.pyx similarity index 100% rename from src/diffusions/simulate.pyx rename to src/affidiff/simulate.pyx diff --git a/src/diffusions/symbolic.py b/src/affidiff/symbolic.py similarity index 100% rename from src/diffusions/symbolic.py rename to src/affidiff/symbolic.py diff --git a/tests/test_ajd.py b/tests/test_ajd.py index c1a27d6..ce445b0 100644 --- a/tests/test_ajd.py +++ b/tests/test_ajd.py @@ -10,9 +10,9 @@ import numpy as np import numpy.testing as npt -from diffusions import (GBMparam, VasicekParam, CIRparam, - HestonParam, CentTendParam) -from diffusions.helper_functions import ajd_drift, ajd_diff +from affidiff import (GBMparam, VasicekParam, CIRparam, + HestonParam, CentTendParam) +from affidiff.helper_functions import ajd_drift, ajd_diff class DriftTestCase(ut.TestCase): diff --git a/tests/test_generic.py b/tests/test_generic.py index 9e6ed59..f06d0ac 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -9,9 +9,9 @@ import unittest as ut import numpy as np -from diffusions import (GBM, GBMparam, Vasicek, VasicekParam, - CIR, CIRparam, Heston, HestonParam, - CentTend, CentTendParam) +from affidiff import (GBM, GBMparam, Vasicek, VasicekParam, + CIR, CIRparam, Heston, HestonParam, + CentTend, CentTendParam) class GenericModelTestCase(ut.TestCase): diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 2b28966..7deb406 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -11,8 +11,8 @@ import numpy.testing as npt from statsmodels.tsa.tsatools import lagmat -from diffusions.helper_functions import (columnwise_prod, rolling_window, - nice_errors, poly_coef, instruments) +from affidiff.helper_functions import (columnwise_prod, rolling_window, + nice_errors, poly_coef, instruments) class HelperFunctionTestCase(ut.TestCase): diff --git a/tests/test_param_cir.py b/tests/test_param_cir.py index 6a551bf..55f506e 100644 --- a/tests/test_param_cir.py +++ b/tests/test_param_cir.py @@ -10,7 +10,7 @@ import numpy as np import numpy.testing as npt -from diffusions import CIRparam +from affidiff import CIRparam class SDEParameterTestCase(ut.TestCase): diff --git a/tests/test_param_ct.py b/tests/test_param_ct.py index fbb79ac..69cd9d0 100644 --- a/tests/test_param_ct.py +++ b/tests/test_param_ct.py @@ -12,7 +12,7 @@ import numpy as np import numpy.testing as npt -from diffusions import CentTendParam +from affidiff import CentTendParam class SDEParameterTestCase(ut.TestCase): diff --git a/tests/test_param_gbm.py b/tests/test_param_gbm.py index 77f22ac..71644a9 100644 --- a/tests/test_param_gbm.py +++ b/tests/test_param_gbm.py @@ -10,7 +10,7 @@ import numpy as np import numpy.testing as npt -from diffusions import GBMparam +from affidiff import GBMparam class SDEParameterTestCase(ut.TestCase): diff --git a/tests/test_param_heston.py b/tests/test_param_heston.py index 0263d0d..979bd0a 100644 --- a/tests/test_param_heston.py +++ b/tests/test_param_heston.py @@ -12,7 +12,7 @@ import numpy as np import numpy.testing as npt -from diffusions import HestonParam +from affidiff import HestonParam class SDEParameterTestCase(ut.TestCase): diff --git a/tests/test_param_vasicek.py b/tests/test_param_vasicek.py index 8728a45..46ab13e 100644 --- a/tests/test_param_vasicek.py +++ b/tests/test_param_vasicek.py @@ -10,7 +10,7 @@ import numpy as np import numpy.testing as npt -from diffusions import VasicekParam +from affidiff import VasicekParam class SDEParameterTestCase(ut.TestCase): diff --git a/tests/test_rmoms_ct.py b/tests/test_rmoms_ct.py index 6dc2a36..84fb81a 100644 --- a/tests/test_rmoms_ct.py +++ b/tests/test_rmoms_ct.py @@ -10,7 +10,7 @@ import numpy as np import numpy.testing as npt -from diffusions import CentTend, CentTendParam +from affidiff import CentTend, CentTendParam class RealizedMomentsCTTestCase(ut.TestCase): diff --git a/tests/test_rmoms_gbm.py b/tests/test_rmoms_gbm.py index 0d4376c..3b36de4 100644 --- a/tests/test_rmoms_gbm.py +++ b/tests/test_rmoms_gbm.py @@ -9,7 +9,7 @@ import unittest as ut import numpy as np -from diffusions import GBM, GBMparam +from affidiff import GBM, GBMparam class RealizedMomentsGBMTestCase(ut.TestCase): diff --git a/tests/test_rmoms_heston.py b/tests/test_rmoms_heston.py index 244c7e1..2cf6648 100644 --- a/tests/test_rmoms_heston.py +++ b/tests/test_rmoms_heston.py @@ -10,7 +10,7 @@ import numpy as np import numpy.testing as npt -from diffusions import Heston, HestonParam +from affidiff import Heston, HestonParam class RealizedMomentsHestonTestCase(ut.TestCase): diff --git a/tests/test_simulations.py b/tests/test_simulations.py index 3f9b80b..d77eff5 100644 --- a/tests/test_simulations.py +++ b/tests/test_simulations.py @@ -1,606 +1,606 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Test suite for diffusion simulations. - -""" -from __future__ import print_function, division - -import unittest as ut -import numpy as np -import numpy.testing as npt - -from diffusions import (GBM, GBMparam, Vasicek, VasicekParam, - CIR, CIRparam, Heston, HestonParam, - CentTend, CentTendParam) -from diffusions.simulate import simulate - - -class CythonTestCase(ut.TestCase): - """Test cython simulate.""" - - def test_cython_simulate_gbm(self): - """Test cython simulation for GBM.""" - - nvars = 1 - mean, sigma = 1.5, .2 - param = GBMparam(mean, sigma) - gbm = GBM(param) - start = np.array([1.]) - nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 - nobs = nperiods * nsub - dt = 1 / ndiscr / nsub - paths = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0) - - self.assertEqual(gbm.errors.shape, (ndiscr * nobs, 2*nsim, nvars)) - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - - paths_cython = simulate(gbm.errors, start, np.atleast_1d(param.mat_k0), - np.atleast_2d(param.mat_k1), - np.atleast_2d(param.mat_h0), - np.atleast_3d(param.mat_h1), dt) - paths_cython = paths_cython[::ndiscr] - paths_cython[1:, :, 0] = paths_cython[1:, :, 0] \ - - paths_cython[:-1, :, 0] - paths_cython = paths_cython[1:] - - self.assertEqual(paths_cython.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths, paths_cython) - - def test_cython_simulate_heston(self): - """Test cython simulation for Heston.""" - - nvars = 2 - riskfree, lmbd, mean_v, kappa, eta, rho = 0., .01, .2, 1.5, .2**.5, -.5 - param = HestonParam(riskfree=riskfree, lmbd=lmbd, mean_v=mean_v, - kappa=kappa, eta=eta, rho=rho) - heston = Heston(param) - - start = np.array([1, mean_v]) - nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 - dt = 1 / ndiscr / nsub - nobs = nperiods * nsub - - heston.errors = np.ones((nobs*ndiscr, 2*nsim, nvars)) - paths = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0, new_innov=False) - - paths_cython = simulate(heston.errors, start, - np.atleast_1d(param.mat_k0), - np.atleast_2d(param.mat_k1), - np.atleast_2d(param.mat_h0), - np.atleast_3d(param.mat_h1), dt) - paths_cython = paths_cython[::ndiscr] - paths_cython[1:, :, 0] = paths_cython[1:, :, 0] \ - - paths_cython[:-1, :, 0] - paths_cython = paths_cython[1:] - - self.assertEqual(paths_cython.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths, paths_cython) - - -class GBMTestCase(ut.TestCase): - """Test simupdate.""" - - def test_gbm_simupdate(self): - """Test simulation update of the GBM model.""" - - mean, sigma = 1.5, .2 - param = GBMparam(mean, sigma) - gbm = GBM(param) - gbm.ndiscr, gbm.nsub = 2, 2 - nvars, nsim = 1, 2 - size = (nsim, nvars) - state = np.ones(size) - error = np.zeros(size) - - new_state = gbm.update(state, error) - loc = state * (mean - sigma**2/2) - scale = np.ones((nsim, nvars, nvars)) * sigma - delta = 1 / gbm.nsub / gbm.ndiscr - new_state_compute = loc * delta + (scale * error).sum(1) * delta**.5 - - self.assertEqual(new_state.shape, size) - npt.assert_array_equal(new_state, new_state_compute) - - def test_vasicek_simupdate(self): - """Test simulation update of the Vasicek model.""" - - mean, kappa, eta = 1.5, 1, .2 - param = VasicekParam(mean, kappa, eta) - vasicek = Vasicek(param) - vasicek.ndiscr, vasicek.nsub = 2, 2 - nvars, nsim = 1, 2 - size = (nsim, nvars) - state = np.ones(size) - error = np.zeros(size) - - new_state = vasicek.update(state, error) - loc = kappa * (mean - state) - scale = np.ones((nsim, nvars, nvars)) * eta - delta = 1 / vasicek.nsub / vasicek.ndiscr - new_state_compute = loc * delta + (scale * error).sum(1) * delta**.5 - - self.assertEqual(new_state.shape, size) - npt.assert_array_equal(new_state, new_state_compute) - - def test_cir_simupdate(self): - """Test simulation update of the CIR model.""" - - mean, kappa, eta = 1.5, 1, .2 - param = CIRparam(mean, kappa, eta) - cir = CIR(param) - cir.ndiscr, cir.nsub = 2, 2 - nvars, nsim = 1, 2 - size = (nsim, nvars) - state_val = 4 - state = np.ones(size) * state_val - error = np.zeros(size) - - new_state = cir.update(state, error) - loc = kappa * (mean - state) - scale = np.ones((nsim, nvars, nvars)) * eta * state**.5 - delta = 1 / cir.nsub / cir.ndiscr - new_state_compute = loc * delta + (scale * error).sum(1) * delta**.5 - - self.assertEqual(new_state.shape, size) - npt.assert_array_equal(new_state, new_state_compute) - - def test_heston_simupdate(self): - """Test simulation update of the Heston model.""" - - riskfree, lmbd, mean_v, kappa, eta, rho = 0., .01, .2, 1.5, .2**.5, -.5 - param = HestonParam(riskfree=riskfree, lmbd=lmbd, - mean_v=mean_v, kappa=kappa, - eta=eta, rho=rho) - heston = Heston(param) - heston.ndiscr, heston.nsub = 2, 2 - nvars, nsim = 2, 3 - size = (nsim, nvars) - state = np.ones(size) - error = np.vstack([np.zeros(nsim), np.ones(nsim)]).T - - new_state = heston.update(state, error) - drift_r = riskfree + state[:, 1]**2 * (lmbd - .5) - drift_v = kappa * (mean_v - state[:, 1]) - loc = np.vstack([drift_r, drift_v]).T - - var = np.array([[1, eta*rho], [eta*rho, eta**2]]) - var = ((np.ones((nsim, nvars, nvars)) * var).T * state[:, 1]).T - scale = np.linalg.cholesky(var) - - delta = 1 / heston.nsub / heston.ndiscr - new_state_compute = loc * delta - for i in range(nsim): - new_state_compute[i] += (scale[i] * error[i]).sum(1) * delta**.5 - - self.assertEqual(new_state.shape, size) - npt.assert_almost_equal(new_state, new_state_compute) - - def test_ct_simupdate(self): - """Test simulation update of the Central Tendency model.""" - - riskfree = .01 - lmbd = .01 - mean_v = .5 - kappa_s = 1.5 - kappa_y = .5 - eta_s = .1 - eta_y = .01 - rho = -.5 - param = CentTendParam(riskfree=riskfree, lmbd=lmbd, - mean_v=mean_v, kappa_s=kappa_s, kappa_y=kappa_y, - eta_s=eta_s, eta_y=eta_y, rho=rho) - centend = CentTend(param) - centend.ndiscr, centend.nsub = 2, 2 - nvars, nsim = 3, 3 - size = (nsim, nvars) - state = np.ones(size) - error = np.vstack([np.zeros(nsim), np.ones(nsim), np.ones(nsim)]).T - - new_state = centend.update(state, error) - drift_r = riskfree + state[:, 1]**2 * (lmbd - .5) - drift_s = kappa_s * (state[:, 2] - state[:, 1]) - drift_v = kappa_y * (mean_v - state[:, 2]) - loc = np.vstack([drift_r, drift_s, drift_v]).T - - var_s = np.zeros((3, 3)) - var_s[:2, :2] = np.array([[1, eta_s*rho], [eta_s*rho, eta_s**2]]) - var_v = np.zeros((3, 3)) - var_v[2, 2] = eta_y**2 - var = ((np.ones((nsim, nvars, nvars)) * var_s).T * state[:, 1]).T \ - + ((np.ones((nsim, nvars, nvars)) * var_v).T * state[:, 2]).T - scale = np.linalg.cholesky(var) - - delta = 1 / centend.nsub / centend.ndiscr - new_state_compute = loc * delta - for i in range(nsim): - new_state_compute[i] += (scale[i] * error[i]).sum(1) * delta**.5 - - self.assertEqual(new_state.shape, size) - npt.assert_almost_equal(new_state, new_state_compute) - - -class SimulationTestCase(ut.TestCase): - """Test simulation.""" - - def test_gbm_simulation(self): - """Test simulation of the GBM model.""" - - nvars = 1 - mean, sigma = 1.5, .2 - param = GBMparam(mean, sigma) - gbm = GBM(param) - start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 - nobs = nperiods * nsub - - paths_cy = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0) - paths = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0, - new_innov=False, cython=False) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths, paths_cy) - - nsim = 1 - paths_cy = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0) - paths = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0, new_innov=False, - cython=False) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths, paths_cy) - - paths_new = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0, new_innov=False) - - npt.assert_array_equal(paths_cy, paths_new) - - paths = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - - fun = lambda: gbm.simulate([1, 1], nsub, ndiscr, - nobs, nsim, diff=0) - self.assertRaises(ValueError, fun) - - def test_vasicek_simulation(self): - """Test simulation of the Vasicek model.""" - - nvars = 1 - mean, kappa, eta = 1.5, .1, .2 - param = VasicekParam(mean, kappa, eta) - vasicek = Vasicek(param) - start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 - nobs = nperiods * nsub - - paths_cy = vasicek.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim) - paths = vasicek.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, - cython=False, new_innov=False) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths, paths_cy) - - paths_new = vasicek.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, new_innov=False) - - npt.assert_array_almost_equal(paths_new, paths_cy) - - fun = lambda: vasicek.simulate([1, 1], nsub=nsub, - ndiscr=ndiscr, nobs=nobs, nsim=nsim, - diff=0) - - self.assertRaises(ValueError, fun) - - def test_cir_simulation(self): - """Test simulation of the CIR model.""" - - nvars = 1 - mean, kappa, eta = 1.5, .1, .2 - param = CIRparam(mean, kappa, eta) - cir = CIR(param) - start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 - nobs = nperiods * nsub - - paths_cy = cir.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim) - paths = cir.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, - new_innov=False, cython=False) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths_cy, paths) - - paths_new = cir.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, new_innov=False) - - npt.assert_array_almost_equal(paths_new, paths_cy) - - fun = lambda: cir.simulate([1, 1], nsub, ndiscr, - nobs, nsim, diff=0) - - self.assertRaises(ValueError, fun) - - def test_heston_simulation(self): - """Test simulation of the Heston model.""" - - nvars = 2 - riskfree, lmbd, mean_v, kappa, eta, rho = 0., .25, .2, 1.5, .2**.5, -.5 - param = HestonParam(riskfree=riskfree, lmbd=lmbd, mean_v=mean_v, - kappa=kappa, eta=eta, rho=rho) - heston = Heston(param) - - start, nperiods, nsub, ndiscr, nsim = [1, mean_v], 5, 10, 10, 4 - nobs = nperiods * nsub - - paths_cy = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0) - paths = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0, - new_innov=False, cython=False) - - self.assertEqual(heston.get_start(), start) - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths_cy, paths) - - paths_cy = heston.simulate(nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0) - paths = heston.simulate(nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0, - new_innov=False, cython=False) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths_cy, paths) - - paths_new = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, - diff=0, new_innov=False) - - npt.assert_array_equal(paths_cy, paths_new) - - paths = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - - fun = lambda: heston.simulate(0, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0) - - self.assertRaises(ValueError, fun) - - def test_ct_simulation(self): - """Test simulation of the Central Tendency model.""" - - nvars = 3 - riskfree = .01 - lmbd = .01 - mean_v = .5 - kappa_s = 1.5 - kappa_y = .5 - eta_s = .1 - eta_y = .01 - rho = -.5 - param = CentTendParam(riskfree=riskfree, lmbd=lmbd, - mean_v=mean_v, kappa_s=kappa_s, kappa_y=kappa_y, - eta_s=eta_s, eta_y=eta_y, rho=rho) - centtend = CentTend(param) - start = [1, mean_v, mean_v] - nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 - nobs = nperiods * nsub - - paths_cy = centtend.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0) - paths = centtend.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0, - new_innov=False, cython=False) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) - npt.assert_array_almost_equal(paths_cy, paths) - - paths_new = centtend.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, - diff=0, new_innov=False) - - npt.assert_array_equal(paths_cy, paths_new) - - paths = centtend.simulate(start, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim) - - self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) - - fun = lambda: centtend.simulate(0, nsub=nsub, ndiscr=ndiscr, - nobs=nobs, nsim=nsim, diff=0) - - self.assertRaises(ValueError, fun) - - -class RealizedSimTestCase(ut.TestCase): - """Test Realized data simulation.""" - - def test_gbm_sim_realized(self): - """Test simulation of realized values of the GBM model.""" - - mean, sigma = 1.5, .2 - param = GBMparam(mean, sigma) - gbm = GBM(param) - start, nperiods, nsub, ndiscr, nsim = 1, 5, 80, 3, 4 - aggh = 2 - returns, rvol = gbm.sim_realized(start, nsub=nsub, aggh=aggh, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, diff=0) - - self.assertEqual(returns.shape, (nperiods-aggh+1, )) - self.assertEqual(rvol.shape, (nperiods-aggh+1, )) - - data = gbm.sim_realized(start, nsub=nsub, aggh=aggh, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, diff=0, new_innov=False) - returns_new, rvol_new = data - - npt.assert_array_equal(returns, returns_new) - npt.assert_array_equal(rvol, rvol_new) - - def test_vasicek_sim_realized(self): - """Test simulation of realized values of the Vasicek model.""" - - mean, kappa, eta = 1.5, .1, .2 - param = VasicekParam(mean, kappa, eta) - vasicek = Vasicek(param) - start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 - aggh = 2 - returns, rvol = vasicek.sim_realized(start, nsub=nsub, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, aggh=aggh, diff=0) - - self.assertEqual(returns.shape, (nperiods-aggh+1, )) - self.assertEqual(rvol.shape, (nperiods-aggh+1, )) - - data = vasicek.sim_realized(start, nsub=nsub, aggh=aggh, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, diff=0, new_innov=False) - returns_new, rvol_new = data - - npt.assert_array_equal(returns, returns_new) - npt.assert_array_equal(rvol, rvol_new) - - def test_cir_sim_realized(self): - """Test simulation of realized values of the CIR model.""" - - mean, kappa, eta = 1.5, .1, .2 - param = CIRparam(mean, kappa, eta) - cir = CIR(param) - start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 - aggh = 2 - returns, rvol = cir.sim_realized(start, nsub=nsub, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, aggh=aggh, diff=0) - - self.assertEqual(returns.shape, (nperiods-aggh+1, )) - self.assertEqual(rvol.shape, (nperiods-aggh+1, )) - - data = cir.sim_realized(start, nsub=nsub, aggh=aggh, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, diff=0, new_innov=False) - returns_new, rvol_new = data - - npt.assert_array_equal(returns, returns_new) - npt.assert_array_equal(rvol, rvol_new) - - def test_heston_sim_realized(self): - """Test simulation of realized values of the Heston model.""" - - riskfree, lmbd, mean_v, kappa, eta, rho = 0., .01, .2, 1.5, .2**.5, -.5 - param = HestonParam(riskfree=riskfree, lmbd=lmbd, - mean_v=mean_v, kappa=kappa, - eta=eta, rho=rho) - heston = Heston(param) - start, nperiods, nsub, ndiscr, nsim = [1, mean_v], 5, 2, 3, 4 - - self.assertEqual(heston.get_start(), start) - - aggh = 2 - returns, rvol = heston.sim_realized(start, nsub=nsub, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, aggh=aggh, diff=0) - - self.assertEqual(returns.shape, (nperiods-aggh+1, )) - self.assertEqual(rvol.shape, (nperiods-aggh+1, )) - - data = heston.sim_realized(start, nsub=nsub, aggh=aggh, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, diff=0, new_innov=False) - returns_new, rvol_new = data - - npt.assert_array_equal(returns, returns_new) - npt.assert_array_equal(rvol, rvol_new) - - def test_heston_sim_realized_pq(self): - """Test simulation of realized data of Heston model under P and Q.""" - - riskfree = .0 - lmbd = 1.5 - lmbd_v = .5 - mean_v = .5 - kappa = .1 - eta = .02**.5 - rho = -.9 - # 2 * self.kappa * self.mean_v - self.eta**2 > 0 - param = HestonParam(riskfree=riskfree, lmbd=lmbd, mean_v=mean_v, - kappa=kappa, eta=eta, rho=rho, lmbd_v=lmbd_v) - heston = Heston(param) - - start_p = [1, param.mean_v] - - self.assertEqual(heston.get_start(), start_p) - - param.convert_to_q() - start_q = [1, mean_v * kappa / (kappa - lmbd_v * eta)] - - self.assertEqual(heston.get_start(), start_q) - - param = HestonParam(riskfree=riskfree, lmbd=lmbd, mean_v=mean_v, - kappa=kappa, eta=eta, rho=rho, lmbd_v=lmbd_v) - heston = Heston(param) - - aggh = [1, 2] - nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 - data = heston.sim_realized_pq(nsub=nsub, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, aggh=aggh, diff=0) - - (ret_p, rvar_p), (ret_q, rvar_q) = data - - self.assertEqual(ret_p.shape, (nperiods-aggh[0]+1, )) - self.assertEqual(ret_q.shape, (nperiods-aggh[1]+1, )) - self.assertEqual(rvar_p.shape, (nperiods-aggh[0]+1, )) - self.assertEqual(rvar_q.shape, (nperiods-aggh[1]+1, )) - - def test_ct_sim_realized(self): - """Test simulation of realized values of the Central Tendency model.""" - - riskfree = .01 - lmbd = .01 - mean_v = .5 - kappa_s = 1.5 - kappa_y = .5 - eta_s = .1 - eta_y = .01 - rho = -.5 - param = CentTendParam(riskfree=riskfree, lmbd=lmbd, - mean_v=mean_v, kappa_s=kappa_s, kappa_y=kappa_y, - eta_s=eta_s, eta_y=eta_y, rho=rho) - centtend = CentTend(param) - start = [1, mean_v, mean_v] - nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 - aggh = 2 - returns, rvol = centtend.sim_realized(start, nsub=nsub, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, aggh=aggh, diff=0) - - self.assertEqual(returns.shape, (nperiods-aggh+1, )) - self.assertEqual(rvol.shape, (nperiods-aggh+1, )) - - data = centtend.sim_realized(start, nsub=nsub, aggh=aggh, - ndiscr=ndiscr, nperiods=nperiods, - nsim=nsim, diff=0, new_innov=False) - returns_new, rvol_new = data - - npt.assert_array_equal(returns, returns_new) - npt.assert_array_equal(rvol, rvol_new) - - -if __name__ == '__main__': - ut.main() +# #!/usr/bin/env python +# # -*- coding: utf-8 -*- +# """ +# Test suite for diffusion simulations. +# +# """ +# from __future__ import print_function, division +# +# import unittest as ut +# import numpy as np +# import numpy.testing as npt +# +# from affidiff import (GBM, GBMparam, Vasicek, VasicekParam, +# CIR, CIRparam, Heston, HestonParam, +# CentTend, CentTendParam) +# # from affidiff.simulate import simulate +# +# +# class CythonTestCase(ut.TestCase): +# """Test cython simulate.""" +# +# def test_cython_simulate_gbm(self): +# """Test cython simulation for GBM.""" +# +# nvars = 1 +# mean, sigma = 1.5, .2 +# param = GBMparam(mean, sigma) +# gbm = GBM(param) +# start = np.array([1.]) +# nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 +# nobs = nperiods * nsub +# dt = 1 / ndiscr / nsub +# paths = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0) +# +# self.assertEqual(gbm.errors.shape, (ndiscr * nobs, 2*nsim, nvars)) +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# +# paths_cython = simulate(gbm.errors, start, np.atleast_1d(param.mat_k0), +# np.atleast_2d(param.mat_k1), +# np.atleast_2d(param.mat_h0), +# np.atleast_3d(param.mat_h1), dt) +# paths_cython = paths_cython[::ndiscr] +# paths_cython[1:, :, 0] = paths_cython[1:, :, 0] \ +# - paths_cython[:-1, :, 0] +# paths_cython = paths_cython[1:] +# +# self.assertEqual(paths_cython.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths, paths_cython) +# +# def test_cython_simulate_heston(self): +# """Test cython simulation for Heston.""" +# +# nvars = 2 +# riskfree, lmbd, mean_v, kappa, eta, rho = 0., .01, .2, 1.5, .2**.5, -.5 +# param = HestonParam(riskfree=riskfree, lmbd=lmbd, mean_v=mean_v, +# kappa=kappa, eta=eta, rho=rho) +# heston = Heston(param) +# +# start = np.array([1, mean_v]) +# nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 +# dt = 1 / ndiscr / nsub +# nobs = nperiods * nsub +# +# heston.errors = np.ones((nobs*ndiscr, 2*nsim, nvars)) +# paths = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0, new_innov=False) +# +# paths_cython = simulate(heston.errors, start, +# np.atleast_1d(param.mat_k0), +# np.atleast_2d(param.mat_k1), +# np.atleast_2d(param.mat_h0), +# np.atleast_3d(param.mat_h1), dt) +# paths_cython = paths_cython[::ndiscr] +# paths_cython[1:, :, 0] = paths_cython[1:, :, 0] \ +# - paths_cython[:-1, :, 0] +# paths_cython = paths_cython[1:] +# +# self.assertEqual(paths_cython.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths, paths_cython) +# +# +# class GBMTestCase(ut.TestCase): +# """Test simupdate.""" +# +# def test_gbm_simupdate(self): +# """Test simulation update of the GBM model.""" +# +# mean, sigma = 1.5, .2 +# param = GBMparam(mean, sigma) +# gbm = GBM(param) +# gbm.ndiscr, gbm.nsub = 2, 2 +# nvars, nsim = 1, 2 +# size = (nsim, nvars) +# state = np.ones(size) +# error = np.zeros(size) +# +# new_state = gbm.update(state, error) +# loc = state * (mean - sigma**2/2) +# scale = np.ones((nsim, nvars, nvars)) * sigma +# delta = 1 / gbm.nsub / gbm.ndiscr +# new_state_compute = loc * delta + (scale * error).sum(1) * delta**.5 +# +# self.assertEqual(new_state.shape, size) +# npt.assert_array_equal(new_state, new_state_compute) +# +# def test_vasicek_simupdate(self): +# """Test simulation update of the Vasicek model.""" +# +# mean, kappa, eta = 1.5, 1, .2 +# param = VasicekParam(mean, kappa, eta) +# vasicek = Vasicek(param) +# vasicek.ndiscr, vasicek.nsub = 2, 2 +# nvars, nsim = 1, 2 +# size = (nsim, nvars) +# state = np.ones(size) +# error = np.zeros(size) +# +# new_state = vasicek.update(state, error) +# loc = kappa * (mean - state) +# scale = np.ones((nsim, nvars, nvars)) * eta +# delta = 1 / vasicek.nsub / vasicek.ndiscr +# new_state_compute = loc * delta + (scale * error).sum(1) * delta**.5 +# +# self.assertEqual(new_state.shape, size) +# npt.assert_array_equal(new_state, new_state_compute) +# +# def test_cir_simupdate(self): +# """Test simulation update of the CIR model.""" +# +# mean, kappa, eta = 1.5, 1, .2 +# param = CIRparam(mean, kappa, eta) +# cir = CIR(param) +# cir.ndiscr, cir.nsub = 2, 2 +# nvars, nsim = 1, 2 +# size = (nsim, nvars) +# state_val = 4 +# state = np.ones(size) * state_val +# error = np.zeros(size) +# +# new_state = cir.update(state, error) +# loc = kappa * (mean - state) +# scale = np.ones((nsim, nvars, nvars)) * eta * state**.5 +# delta = 1 / cir.nsub / cir.ndiscr +# new_state_compute = loc * delta + (scale * error).sum(1) * delta**.5 +# +# self.assertEqual(new_state.shape, size) +# npt.assert_array_equal(new_state, new_state_compute) +# +# def test_heston_simupdate(self): +# """Test simulation update of the Heston model.""" +# +# riskfree, lmbd, mean_v, kappa, eta, rho = 0., .01, .2, 1.5, .2**.5, -.5 +# param = HestonParam(riskfree=riskfree, lmbd=lmbd, +# mean_v=mean_v, kappa=kappa, +# eta=eta, rho=rho) +# heston = Heston(param) +# heston.ndiscr, heston.nsub = 2, 2 +# nvars, nsim = 2, 3 +# size = (nsim, nvars) +# state = np.ones(size) +# error = np.vstack([np.zeros(nsim), np.ones(nsim)]).T +# +# new_state = heston.update(state, error) +# drift_r = riskfree + state[:, 1]**2 * (lmbd - .5) +# drift_v = kappa * (mean_v - state[:, 1]) +# loc = np.vstack([drift_r, drift_v]).T +# +# var = np.array([[1, eta*rho], [eta*rho, eta**2]]) +# var = ((np.ones((nsim, nvars, nvars)) * var).T * state[:, 1]).T +# scale = np.linalg.cholesky(var) +# +# delta = 1 / heston.nsub / heston.ndiscr +# new_state_compute = loc * delta +# for i in range(nsim): +# new_state_compute[i] += (scale[i] * error[i]).sum(1) * delta**.5 +# +# self.assertEqual(new_state.shape, size) +# npt.assert_almost_equal(new_state, new_state_compute) +# +# def test_ct_simupdate(self): +# """Test simulation update of the Central Tendency model.""" +# +# riskfree = .01 +# lmbd = .01 +# mean_v = .5 +# kappa_s = 1.5 +# kappa_y = .5 +# eta_s = .1 +# eta_y = .01 +# rho = -.5 +# param = CentTendParam(riskfree=riskfree, lmbd=lmbd, +# mean_v=mean_v, kappa_s=kappa_s, kappa_y=kappa_y, +# eta_s=eta_s, eta_y=eta_y, rho=rho) +# centend = CentTend(param) +# centend.ndiscr, centend.nsub = 2, 2 +# nvars, nsim = 3, 3 +# size = (nsim, nvars) +# state = np.ones(size) +# error = np.vstack([np.zeros(nsim), np.ones(nsim), np.ones(nsim)]).T +# +# new_state = centend.update(state, error) +# drift_r = riskfree + state[:, 1]**2 * (lmbd - .5) +# drift_s = kappa_s * (state[:, 2] - state[:, 1]) +# drift_v = kappa_y * (mean_v - state[:, 2]) +# loc = np.vstack([drift_r, drift_s, drift_v]).T +# +# var_s = np.zeros((3, 3)) +# var_s[:2, :2] = np.array([[1, eta_s*rho], [eta_s*rho, eta_s**2]]) +# var_v = np.zeros((3, 3)) +# var_v[2, 2] = eta_y**2 +# var = ((np.ones((nsim, nvars, nvars)) * var_s).T * state[:, 1]).T \ +# + ((np.ones((nsim, nvars, nvars)) * var_v).T * state[:, 2]).T +# scale = np.linalg.cholesky(var) +# +# delta = 1 / centend.nsub / centend.ndiscr +# new_state_compute = loc * delta +# for i in range(nsim): +# new_state_compute[i] += (scale[i] * error[i]).sum(1) * delta**.5 +# +# self.assertEqual(new_state.shape, size) +# npt.assert_almost_equal(new_state, new_state_compute) +# +# +# class SimulationTestCase(ut.TestCase): +# """Test simulation.""" +# +# def test_gbm_simulation(self): +# """Test simulation of the GBM model.""" +# +# nvars = 1 +# mean, sigma = 1.5, .2 +# param = GBMparam(mean, sigma) +# gbm = GBM(param) +# start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 +# nobs = nperiods * nsub +# +# paths_cy = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0) +# paths = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0, +# new_innov=False, cython=False) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths, paths_cy) +# +# nsim = 1 +# paths_cy = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0) +# paths = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0, new_innov=False, +# cython=False) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths, paths_cy) +# +# paths_new = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0, new_innov=False) +# +# npt.assert_array_equal(paths_cy, paths_new) +# +# paths = gbm.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# +# fun = lambda: gbm.simulate([1, 1], nsub, ndiscr, +# nobs, nsim, diff=0) +# self.assertRaises(ValueError, fun) +# +# def test_vasicek_simulation(self): +# """Test simulation of the Vasicek model.""" +# +# nvars = 1 +# mean, kappa, eta = 1.5, .1, .2 +# param = VasicekParam(mean, kappa, eta) +# vasicek = Vasicek(param) +# start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 +# nobs = nperiods * nsub +# +# paths_cy = vasicek.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim) +# paths = vasicek.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, +# cython=False, new_innov=False) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths, paths_cy) +# +# paths_new = vasicek.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, new_innov=False) +# +# npt.assert_array_almost_equal(paths_new, paths_cy) +# +# fun = lambda: vasicek.simulate([1, 1], nsub=nsub, +# ndiscr=ndiscr, nobs=nobs, nsim=nsim, +# diff=0) +# +# self.assertRaises(ValueError, fun) +# +# def test_cir_simulation(self): +# """Test simulation of the CIR model.""" +# +# nvars = 1 +# mean, kappa, eta = 1.5, .1, .2 +# param = CIRparam(mean, kappa, eta) +# cir = CIR(param) +# start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 +# nobs = nperiods * nsub +# +# paths_cy = cir.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim) +# paths = cir.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, +# new_innov=False, cython=False) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths_cy, paths) +# +# paths_new = cir.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, new_innov=False) +# +# npt.assert_array_almost_equal(paths_new, paths_cy) +# +# fun = lambda: cir.simulate([1, 1], nsub, ndiscr, +# nobs, nsim, diff=0) +# +# self.assertRaises(ValueError, fun) +# +# def test_heston_simulation(self): +# """Test simulation of the Heston model.""" +# +# nvars = 2 +# riskfree, lmbd, mean_v, kappa, eta, rho = 0., .25, .2, 1.5, .2**.5, -.5 +# param = HestonParam(riskfree=riskfree, lmbd=lmbd, mean_v=mean_v, +# kappa=kappa, eta=eta, rho=rho) +# heston = Heston(param) +# +# start, nperiods, nsub, ndiscr, nsim = [1, mean_v], 5, 10, 10, 4 +# nobs = nperiods * nsub +# +# paths_cy = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0) +# paths = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0, +# new_innov=False, cython=False) +# +# self.assertEqual(heston.get_start(), start) +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths_cy, paths) +# +# paths_cy = heston.simulate(nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0) +# paths = heston.simulate(nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0, +# new_innov=False, cython=False) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths_cy, paths) +# +# paths_new = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, +# diff=0, new_innov=False) +# +# npt.assert_array_equal(paths_cy, paths_new) +# +# paths = heston.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# +# fun = lambda: heston.simulate(0, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0) +# +# self.assertRaises(ValueError, fun) +# +# def test_ct_simulation(self): +# """Test simulation of the Central Tendency model.""" +# +# nvars = 3 +# riskfree = .01 +# lmbd = .01 +# mean_v = .5 +# kappa_s = 1.5 +# kappa_y = .5 +# eta_s = .1 +# eta_y = .01 +# rho = -.5 +# param = CentTendParam(riskfree=riskfree, lmbd=lmbd, +# mean_v=mean_v, kappa_s=kappa_s, kappa_y=kappa_y, +# eta_s=eta_s, eta_y=eta_y, rho=rho) +# centtend = CentTend(param) +# start = [1, mean_v, mean_v] +# nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 +# nobs = nperiods * nsub +# +# paths_cy = centtend.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0) +# paths = centtend.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0, +# new_innov=False, cython=False) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# self.assertEqual(paths_cy.shape, (nobs, 2*nsim, nvars)) +# npt.assert_array_almost_equal(paths_cy, paths) +# +# paths_new = centtend.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, +# diff=0, new_innov=False) +# +# npt.assert_array_equal(paths_cy, paths_new) +# +# paths = centtend.simulate(start, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim) +# +# self.assertEqual(paths.shape, (nobs, 2*nsim, nvars)) +# +# fun = lambda: centtend.simulate(0, nsub=nsub, ndiscr=ndiscr, +# nobs=nobs, nsim=nsim, diff=0) +# +# self.assertRaises(ValueError, fun) +# +# +# class RealizedSimTestCase(ut.TestCase): +# """Test Realized data simulation.""" +# +# def test_gbm_sim_realized(self): +# """Test simulation of realized values of the GBM model.""" +# +# mean, sigma = 1.5, .2 +# param = GBMparam(mean, sigma) +# gbm = GBM(param) +# start, nperiods, nsub, ndiscr, nsim = 1, 5, 80, 3, 4 +# aggh = 2 +# returns, rvol = gbm.sim_realized(start, nsub=nsub, aggh=aggh, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, diff=0) +# +# self.assertEqual(returns.shape, (nperiods-aggh+1, )) +# self.assertEqual(rvol.shape, (nperiods-aggh+1, )) +# +# data = gbm.sim_realized(start, nsub=nsub, aggh=aggh, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, diff=0, new_innov=False) +# returns_new, rvol_new = data +# +# npt.assert_array_equal(returns, returns_new) +# npt.assert_array_equal(rvol, rvol_new) +# +# def test_vasicek_sim_realized(self): +# """Test simulation of realized values of the Vasicek model.""" +# +# mean, kappa, eta = 1.5, .1, .2 +# param = VasicekParam(mean, kappa, eta) +# vasicek = Vasicek(param) +# start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 +# aggh = 2 +# returns, rvol = vasicek.sim_realized(start, nsub=nsub, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, aggh=aggh, diff=0) +# +# self.assertEqual(returns.shape, (nperiods-aggh+1, )) +# self.assertEqual(rvol.shape, (nperiods-aggh+1, )) +# +# data = vasicek.sim_realized(start, nsub=nsub, aggh=aggh, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, diff=0, new_innov=False) +# returns_new, rvol_new = data +# +# npt.assert_array_equal(returns, returns_new) +# npt.assert_array_equal(rvol, rvol_new) +# +# def test_cir_sim_realized(self): +# """Test simulation of realized values of the CIR model.""" +# +# mean, kappa, eta = 1.5, .1, .2 +# param = CIRparam(mean, kappa, eta) +# cir = CIR(param) +# start, nperiods, nsub, ndiscr, nsim = 1, 5, 2, 3, 4 +# aggh = 2 +# returns, rvol = cir.sim_realized(start, nsub=nsub, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, aggh=aggh, diff=0) +# +# self.assertEqual(returns.shape, (nperiods-aggh+1, )) +# self.assertEqual(rvol.shape, (nperiods-aggh+1, )) +# +# data = cir.sim_realized(start, nsub=nsub, aggh=aggh, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, diff=0, new_innov=False) +# returns_new, rvol_new = data +# +# npt.assert_array_equal(returns, returns_new) +# npt.assert_array_equal(rvol, rvol_new) +# +# def test_heston_sim_realized(self): +# """Test simulation of realized values of the Heston model.""" +# +# riskfree, lmbd, mean_v, kappa, eta, rho = 0., .01, .2, 1.5, .2**.5, -.5 +# param = HestonParam(riskfree=riskfree, lmbd=lmbd, +# mean_v=mean_v, kappa=kappa, +# eta=eta, rho=rho) +# heston = Heston(param) +# start, nperiods, nsub, ndiscr, nsim = [1, mean_v], 5, 2, 3, 4 +# +# self.assertEqual(heston.get_start(), start) +# +# aggh = 2 +# returns, rvol = heston.sim_realized(start, nsub=nsub, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, aggh=aggh, diff=0) +# +# self.assertEqual(returns.shape, (nperiods-aggh+1, )) +# self.assertEqual(rvol.shape, (nperiods-aggh+1, )) +# +# data = heston.sim_realized(start, nsub=nsub, aggh=aggh, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, diff=0, new_innov=False) +# returns_new, rvol_new = data +# +# npt.assert_array_equal(returns, returns_new) +# npt.assert_array_equal(rvol, rvol_new) +# +# def test_heston_sim_realized_pq(self): +# """Test simulation of realized data of Heston model under P and Q.""" +# +# riskfree = .0 +# lmbd = 1.5 +# lmbd_v = .5 +# mean_v = .5 +# kappa = .1 +# eta = .02**.5 +# rho = -.9 +# # 2 * self.kappa * self.mean_v - self.eta**2 > 0 +# param = HestonParam(riskfree=riskfree, lmbd=lmbd, mean_v=mean_v, +# kappa=kappa, eta=eta, rho=rho, lmbd_v=lmbd_v) +# heston = Heston(param) +# +# start_p = [1, param.mean_v] +# +# self.assertEqual(heston.get_start(), start_p) +# +# param.convert_to_q() +# start_q = [1, mean_v * kappa / (kappa - lmbd_v * eta)] +# +# self.assertEqual(heston.get_start(), start_q) +# +# param = HestonParam(riskfree=riskfree, lmbd=lmbd, mean_v=mean_v, +# kappa=kappa, eta=eta, rho=rho, lmbd_v=lmbd_v) +# heston = Heston(param) +# +# aggh = [1, 2] +# nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 +# data = heston.sim_realized_pq(nsub=nsub, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, aggh=aggh, diff=0) +# +# (ret_p, rvar_p), (ret_q, rvar_q) = data +# +# self.assertEqual(ret_p.shape, (nperiods-aggh[0]+1, )) +# self.assertEqual(ret_q.shape, (nperiods-aggh[1]+1, )) +# self.assertEqual(rvar_p.shape, (nperiods-aggh[0]+1, )) +# self.assertEqual(rvar_q.shape, (nperiods-aggh[1]+1, )) +# +# def test_ct_sim_realized(self): +# """Test simulation of realized values of the Central Tendency model.""" +# +# riskfree = .01 +# lmbd = .01 +# mean_v = .5 +# kappa_s = 1.5 +# kappa_y = .5 +# eta_s = .1 +# eta_y = .01 +# rho = -.5 +# param = CentTendParam(riskfree=riskfree, lmbd=lmbd, +# mean_v=mean_v, kappa_s=kappa_s, kappa_y=kappa_y, +# eta_s=eta_s, eta_y=eta_y, rho=rho) +# centtend = CentTend(param) +# start = [1, mean_v, mean_v] +# nperiods, nsub, ndiscr, nsim = 5, 2, 3, 4 +# aggh = 2 +# returns, rvol = centtend.sim_realized(start, nsub=nsub, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, aggh=aggh, diff=0) +# +# self.assertEqual(returns.shape, (nperiods-aggh+1, )) +# self.assertEqual(rvol.shape, (nperiods-aggh+1, )) +# +# data = centtend.sim_realized(start, nsub=nsub, aggh=aggh, +# ndiscr=ndiscr, nperiods=nperiods, +# nsim=nsim, diff=0, new_innov=False) +# returns_new, rvol_new = data +# +# npt.assert_array_equal(returns, returns_new) +# npt.assert_array_equal(rvol, rvol_new) +# +# +# if __name__ == '__main__': +# ut.main() diff --git a/uv.lock b/uv.lock index c8179ec..6829cd8 100644 --- a/uv.lock +++ b/uv.lock @@ -8,20 +8,14 @@ resolution-markers = [ ] [[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "diffusions" +name = "affidiff" source = { editable = "." } dependencies = [ + { name = "matplotlib" }, + { name = "mygmm" }, { name = "numpy" }, { name = "scipy" }, + { name = "seaborn" }, { name = "statsmodels" }, ] @@ -32,14 +26,93 @@ dev = [ [package.metadata] requires-dist = [ + { name = "matplotlib", specifier = ">=3.10.8" }, + { name = "mygmm", specifier = ">=0.1.0" }, { name = "numpy", specifier = ">=2.4.4" }, { name = "scipy", specifier = ">=1.17.1" }, + { name = "seaborn", specifier = ">=0.13.2" }, { name = "statsmodels", specifier = ">=0.14.6" }, ] [package.metadata.requires-dev] dev = [{ name = "pytest", specifier = ">=9.0.3" }] +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "fonttools" +version = "4.62.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f0/2888cdac391807d68d90dcb16ef858ddc1b5309bfc6966195a459dd326e2/fonttools-4.62.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fa1d16210b6b10a826d71bed68dd9ec24a9e218d5a5e2797f37c573e7ec215ca", size = 2864442, upload-time = "2026-03-13T13:53:37.509Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b2/e521803081f8dc35990816b82da6360fa668a21b44da4b53fc9e77efcd62/fonttools-4.62.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:aa69d10ed420d8121118e628ad47d86e4caa79ba37f968597b958f6cceab7eca", size = 2410901, upload-time = "2026-03-13T13:53:40.55Z" }, + { url = "https://files.pythonhosted.org/packages/00/a4/8c3511ff06e53110039358dbbdc1a65d72157a054638387aa2ada300a8b8/fonttools-4.62.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd13b7999d59c5eb1c2b442eb2d0c427cb517a0b7a1f5798fc5c9e003f5ff782", size = 4999608, upload-time = "2026-03-13T13:53:42.798Z" }, + { url = "https://files.pythonhosted.org/packages/28/63/cd0c3b26afe60995a5295f37c246a93d454023726c3261cfbb3559969bb9/fonttools-4.62.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8d337fdd49a79b0d51c4da87bc38169d21c3abbf0c1aa9367eff5c6656fb6dae", size = 4912726, upload-time = "2026-03-13T13:53:45.405Z" }, + { url = "https://files.pythonhosted.org/packages/70/b9/ac677cb07c24c685cf34f64e140617d58789d67a3dd524164b63648c6114/fonttools-4.62.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d241cdc4a67b5431c6d7f115fdf63335222414995e3a1df1a41e1182acd4bcc7", size = 4951422, upload-time = "2026-03-13T13:53:48.326Z" }, + { url = "https://files.pythonhosted.org/packages/e6/10/11c08419a14b85b7ca9a9faca321accccc8842dd9e0b1c8a72908de05945/fonttools-4.62.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c05557a78f8fa514da0f869556eeda40887a8abc77c76ee3f74cf241778afd5a", size = 5060979, upload-time = "2026-03-13T13:53:51.366Z" }, + { url = "https://files.pythonhosted.org/packages/4e/3c/12eea4a4cf054e7ab058ed5ceada43b46809fce2bf319017c4d63ae55bb4/fonttools-4.62.1-cp314-cp314-win32.whl", hash = "sha256:49a445d2f544ce4a69338694cad575ba97b9a75fff02720da0882d1a73f12800", size = 2283733, upload-time = "2026-03-13T13:53:53.606Z" }, + { url = "https://files.pythonhosted.org/packages/6b/67/74b070029043186b5dd13462c958cb7c7f811be0d2e634309d9a1ffb1505/fonttools-4.62.1-cp314-cp314-win_amd64.whl", hash = "sha256:1eecc128c86c552fb963fe846ca4e011b1be053728f798185a1687502f6d398e", size = 2335663, upload-time = "2026-03-13T13:53:56.23Z" }, + { url = "https://files.pythonhosted.org/packages/42/c5/4d2ed3ca6e33617fc5624467da353337f06e7f637707478903c785bd8e20/fonttools-4.62.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1596aeaddf7f78e21e68293c011316a25267b3effdaccaf4d59bc9159d681b82", size = 2947288, upload-time = "2026-03-13T13:53:59.397Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e9/7ab11ddfda48ed0f89b13380e5595ba572619c27077be0b2c447a63ff351/fonttools-4.62.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8f8fca95d3bb3208f59626a4b0ea6e526ee51f5a8ad5d91821c165903e8d9260", size = 2449023, upload-time = "2026-03-13T13:54:01.642Z" }, + { url = "https://files.pythonhosted.org/packages/b2/10/a800fa090b5e8819942e54e19b55fc7c21fe14a08757c3aa3ca8db358939/fonttools-4.62.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee91628c08e76f77b533d65feb3fbe6d9dad699f95be51cf0d022db94089cdc4", size = 5137599, upload-time = "2026-03-13T13:54:04.495Z" }, + { url = "https://files.pythonhosted.org/packages/37/dc/8ccd45033fffd74deb6912fa1ca524643f584b94c87a16036855b498a1ed/fonttools-4.62.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f37df1cac61d906e7b836abe356bc2f34c99d4477467755c216b72aa3dc748b", size = 4920933, upload-time = "2026-03-13T13:54:07.557Z" }, + { url = "https://files.pythonhosted.org/packages/99/eb/e618adefb839598d25ac8136cd577925d6c513dc0d931d93b8af956210f0/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:92bb00a947e666169c99b43753c4305fc95a890a60ef3aeb2a6963e07902cc87", size = 5016232, upload-time = "2026-03-13T13:54:10.611Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5f/9b5c9bfaa8ec82def8d8168c4f13615990d6ce5996fe52bd49bfb5e05134/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bdfe592802ef939a0e33106ea4a318eeb17822c7ee168c290273cbd5fabd746c", size = 5042987, upload-time = "2026-03-13T13:54:13.569Z" }, + { url = "https://files.pythonhosted.org/packages/90/aa/dfbbe24c6a6afc5c203d90cc0343e24bcbb09e76d67c4d6eef8c2558d7ba/fonttools-4.62.1-cp314-cp314t-win32.whl", hash = "sha256:b820fcb92d4655513d8402d5b219f94481c4443d825b4372c75a2072aa4b357a", size = 2348021, upload-time = "2026-03-13T13:54:16.98Z" }, + { url = "https://files.pythonhosted.org/packages/13/6f/ae9c4e4dd417948407b680855c2c7790efb52add6009aaecff1e3bc50e8e/fonttools-4.62.1-cp314-cp314t-win_amd64.whl", hash = "sha256:59b372b4f0e113d3746b88985f1c796e7bf830dd54b28374cd85c2b8acd7583e", size = 2414147, upload-time = "2026-03-13T13:54:19.416Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, +] + [[package]] name = "iniconfig" version = "2.3.0" @@ -49,6 +122,106 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "kiwisolver" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/d7/060f45052f2a01ad5762c8fdecd6d7a752b43400dc29ff75cd47225a40fd/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615", size = 123231, upload-time = "2026-03-09T13:14:41.323Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02", size = 66489, upload-time = "2026-03-09T13:14:42.534Z" }, + { url = "https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e", size = 64063, upload-time = "2026-03-09T13:14:44.759Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac", size = 1475913, upload-time = "2026-03-09T13:14:46.247Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f0/f768ae564a710135630672981231320bc403cf9152b5596ec5289de0f106/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05", size = 1282782, upload-time = "2026-03-09T13:14:48.458Z" }, + { url = "https://files.pythonhosted.org/packages/e2/9f/1de7aad00697325f05238a5f2eafbd487fb637cc27a558b5367a5f37fb7f/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd", size = 1300815, upload-time = "2026-03-09T13:14:50.721Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c2/297f25141d2e468e0ce7f7a7b92e0cf8918143a0cbd3422c1ad627e85a06/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a", size = 1347925, upload-time = "2026-03-09T13:14:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d3/f4c73a02eb41520c47610207b21afa8cdd18fdbf64ffd94674ae21c4812d/kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554", size = 991322, upload-time = "2026-03-09T13:14:54.637Z" }, + { url = "https://files.pythonhosted.org/packages/7b/46/d3f2efef7732fcda98d22bf4ad5d3d71d545167a852ca710a494f4c15343/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581", size = 2232857, upload-time = "2026-03-09T13:14:56.471Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ec/2d9756bf2b6d26ae4349b8d3662fb3993f16d80c1f971c179ce862b9dbae/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303", size = 2329376, upload-time = "2026-03-09T13:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/8f/9f/876a0a0f2260f1bde92e002b3019a5fabc35e0939c7d945e0fa66185eb20/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9", size = 1982549, upload-time = "2026-03-09T13:14:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/ba3624dfac23a64d54ac4179832860cb537c1b0af06024936e82ca4154a0/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79", size = 2494680, upload-time = "2026-03-09T13:15:01.364Z" }, + { url = "https://files.pythonhosted.org/packages/39/b7/97716b190ab98911b20d10bf92eca469121ec483b8ce0edd314f51bc85af/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796", size = 2297905, upload-time = "2026-03-09T13:15:03.925Z" }, + { url = "https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e", size = 75086, upload-time = "2026-03-09T13:15:07.775Z" }, + { url = "https://files.pythonhosted.org/packages/70/15/9b90f7df0e31a003c71649cf66ef61c3c1b862f48c81007fa2383c8bd8d7/kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df", size = 66577, upload-time = "2026-03-09T13:15:09.139Z" }, + { url = "https://files.pythonhosted.org/packages/17/01/7dc8c5443ff42b38e72731643ed7cf1ed9bf01691ae5cdca98501999ed83/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e", size = 125794, upload-time = "2026-03-09T13:15:10.525Z" }, + { url = "https://files.pythonhosted.org/packages/46/8a/b4ebe46ebaac6a303417fab10c2e165c557ddaff558f9699d302b256bc53/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4", size = 67646, upload-time = "2026-03-09T13:15:12.016Z" }, + { url = "https://files.pythonhosted.org/packages/60/35/10a844afc5f19d6f567359bf4789e26661755a2f36200d5d1ed8ad0126e5/kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028", size = 65511, upload-time = "2026-03-09T13:15:13.311Z" }, + { url = "https://files.pythonhosted.org/packages/f8/8a/685b297052dd041dcebce8e8787b58923b6e78acc6115a0dc9189011c44b/kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657", size = 1584858, upload-time = "2026-03-09T13:15:15.103Z" }, + { url = "https://files.pythonhosted.org/packages/9e/80/04865e3d4638ac5bddec28908916df4a3075b8c6cc101786a96803188b96/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920", size = 1392539, upload-time = "2026-03-09T13:15:16.661Z" }, + { url = "https://files.pythonhosted.org/packages/ba/01/77a19cacc0893fa13fafa46d1bba06fb4dc2360b3292baf4b56d8e067b24/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9", size = 1405310, upload-time = "2026-03-09T13:15:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/53/39/bcaf5d0cca50e604cfa9b4e3ae1d64b50ca1ae5b754122396084599ef903/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d", size = 1456244, upload-time = "2026-03-09T13:15:20.444Z" }, + { url = "https://files.pythonhosted.org/packages/d0/7a/72c187abc6975f6978c3e39b7cf67aeb8b3c0a8f9790aa7fd412855e9e1f/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65", size = 1073154, upload-time = "2026-03-09T13:15:22.039Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ca/cf5b25783ebbd59143b4371ed0c8428a278abe68d6d0104b01865b1bbd0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa", size = 2334377, upload-time = "2026-03-09T13:15:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/4a/e5/b1f492adc516796e88751282276745340e2a72dcd0d36cf7173e0daf3210/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0", size = 2425288, upload-time = "2026-03-09T13:15:25.789Z" }, + { url = "https://files.pythonhosted.org/packages/e6/e5/9b21fbe91a61b8f409d74a26498706e97a48008bfcd1864373d32a6ba31c/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9", size = 2063158, upload-time = "2026-03-09T13:15:27.63Z" }, + { url = "https://files.pythonhosted.org/packages/b1/02/83f47986138310f95ea95531f851b2a62227c11cbc3e690ae1374fe49f0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f", size = 2597260, upload-time = "2026-03-09T13:15:29.421Z" }, + { url = "https://files.pythonhosted.org/packages/07/18/43a5f24608d8c313dd189cf838c8e68d75b115567c6279de7796197cfb6a/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646", size = 2394403, upload-time = "2026-03-09T13:15:31.517Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b5/98222136d839b8afabcaa943b09bd05888c2d36355b7e448550211d1fca4/kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681", size = 79687, upload-time = "2026-03-09T13:15:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/99/a2/ca7dc962848040befed12732dff6acae7fb3c4f6fc4272b3f6c9a30b8713/kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57", size = 70032, upload-time = "2026-03-09T13:15:34.411Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/43/9c0ff7a2f11615e516c3b058e1e6e8f9614ddeca53faca06da267c48345d/matplotlib-3.10.8-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b53285e65d4fa4c86399979e956235deb900be5baa7fc1218ea67fbfaeaadd6f", size = 8262481, upload-time = "2025-12-10T22:56:10.885Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ca/e8ae28649fcdf039fda5ef554b40a95f50592a3c47e6f7270c9561c12b07/matplotlib-3.10.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32f8dce744be5569bebe789e46727946041199030db8aeb2954d26013a0eb26b", size = 8151473, upload-time = "2025-12-10T22:56:12.377Z" }, + { url = "https://files.pythonhosted.org/packages/f1/6f/009d129ae70b75e88cbe7e503a12a4c0670e08ed748a902c2568909e9eb5/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf267add95b1c88300d96ca837833d4112756045364f5c734a2276038dae27d", size = 9553896, upload-time = "2025-12-10T22:56:14.432Z" }, + { url = "https://files.pythonhosted.org/packages/f5/26/4221a741eb97967bc1fd5e4c52b9aa5a91b2f4ec05b59f6def4d820f9df9/matplotlib-3.10.8-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2cf5bd12cecf46908f286d7838b2abc6c91cda506c0445b8223a7c19a00df008", size = 9824193, upload-time = "2025-12-10T22:56:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/3abf75f38605772cf48a9daf5821cd4f563472f38b4b828c6fba6fa6d06e/matplotlib-3.10.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:41703cc95688f2516b480f7f339d8851a6035f18e100ee6a32bc0b8536a12a9c", size = 9615444, upload-time = "2025-12-10T22:56:18.155Z" }, + { url = "https://files.pythonhosted.org/packages/93/a5/de89ac80f10b8dc615807ee1133cd99ac74082581196d4d9590bea10690d/matplotlib-3.10.8-cp314-cp314-win_amd64.whl", hash = "sha256:83d282364ea9f3e52363da262ce32a09dfe241e4080dcedda3c0db059d3c1f11", size = 8272719, upload-time = "2025-12-10T22:56:20.366Z" }, + { url = "https://files.pythonhosted.org/packages/69/ce/b006495c19ccc0a137b48083168a37bd056392dee02f87dba0472f2797fe/matplotlib-3.10.8-cp314-cp314-win_arm64.whl", hash = "sha256:2c1998e92cd5999e295a731bcb2911c75f597d937341f3030cc24ef2733d78a8", size = 8144205, upload-time = "2025-12-10T22:56:22.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/d9/b31116a3a855bd313c6fcdb7226926d59b041f26061c6c5b1be66a08c826/matplotlib-3.10.8-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b5a2b97dbdc7d4f353ebf343744f1d1f1cca8aa8bfddb4262fcf4306c3761d50", size = 8305785, upload-time = "2025-12-10T22:56:24.218Z" }, + { url = "https://files.pythonhosted.org/packages/1e/90/6effe8103f0272685767ba5f094f453784057072f49b393e3ea178fe70a5/matplotlib-3.10.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3f5c3e4da343bba819f0234186b9004faba952cc420fbc522dc4e103c1985908", size = 8198361, upload-time = "2025-12-10T22:56:26.787Z" }, + { url = "https://files.pythonhosted.org/packages/d7/65/a73188711bea603615fc0baecca1061429ac16940e2385433cc778a9d8e7/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f62550b9a30afde8c1c3ae450e5eb547d579dd69b25c2fc7a1c67f934c1717a", size = 9561357, upload-time = "2025-12-10T22:56:28.953Z" }, + { url = "https://files.pythonhosted.org/packages/f4/3d/b5c5d5d5be8ce63292567f0e2c43dde9953d3ed86ac2de0a72e93c8f07a1/matplotlib-3.10.8-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:495672de149445ec1b772ff2c9ede9b769e3cb4f0d0aa7fa730d7f59e2d4e1c1", size = 9823610, upload-time = "2025-12-10T22:56:31.455Z" }, + { url = "https://files.pythonhosted.org/packages/4d/4b/e7beb6bbd49f6bae727a12b270a2654d13c397576d25bd6786e47033300f/matplotlib-3.10.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:595ba4d8fe983b88f0eec8c26a241e16d6376fe1979086232f481f8f3f67494c", size = 9614011, upload-time = "2025-12-10T22:56:33.85Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e6/76f2813d31f032e65f6f797e3f2f6e4aab95b65015924b1c51370395c28a/matplotlib-3.10.8-cp314-cp314t-win_amd64.whl", hash = "sha256:25d380fe8b1dc32cf8f0b1b448470a77afb195438bafdf1d858bfb876f3edf7b", size = 8362801, upload-time = "2025-12-10T22:56:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/5d/49/d651878698a0b67f23aa28e17f45a6d6dd3d3f933fa29087fa4ce5947b5a/matplotlib-3.10.8-cp314-cp314t-win_arm64.whl", hash = "sha256:113bb52413ea508ce954a02c10ffd0d565f9c3bc7f2eddc27dfe1731e71c7b5f", size = 8192560, upload-time = "2025-12-10T22:56:38.008Z" }, +] + +[[package]] +name = "mygmm" +version = "0.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numdifftools" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "scipy" }, + { name = "statsmodels" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/e8/e19e116807a06c5e6182e784049e0537dea12386fd9e2a57bccad7668b3e/mygmm-0.1.0.tar.gz", hash = "sha256:06d96e15d710951f9fd34190fde053f40ef11579645133cdda0cebfa4fa1e8f9", size = 23757, upload-time = "2026-04-20T12:30:54.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/58/9ff6516894cce3be9b86edfd2f015410c10f8bd9d1c3f3c779c1e0eff9a2/mygmm-0.1.0-py3-none-any.whl", hash = "sha256:de5354ad120afe4b8f0cb73018531ed3da95d078af677913d1a29a6534d1404b", size = 5992, upload-time = "2026-04-20T12:30:53.882Z" }, +] + +[[package]] +name = "numdifftools" +version = "0.9.42" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/94/7c83677dddc78f93230f4c8a6a5faa06c92699a76eb019386a3aed8a9762/numdifftools-0.9.42.tar.gz", hash = "sha256:866675171f293c4bf2f1e1c5bf9b88a07d5396903e3b3e7fcc3879e2a01cfbc1", size = 79612, upload-time = "2025-12-11T12:06:10.54Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/60/c7504633e9fe53dc823db5d83dc15651c595cf35d668781832b4d2748272/numdifftools-0.9.42-py3-none-any.whl", hash = "sha256:22f926b8de24aa44f740bc26744a74555c1c80413068b1dee2edb3c3d10566f6", size = 94252, upload-time = "2025-12-11T12:06:09.322Z" }, +] + [[package]] name = "numpy" version = "2.4.4" @@ -128,6 +301,39 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/70/ba4b949bdc0490ab78d545459acd7702b211dfccf7eb89bbc1060f52818d/patsy-1.0.2-py2.py3-none-any.whl", hash = "sha256:37bfddbc58fcf0362febb5f54f10743f8b21dd2aa73dec7e7ef59d1b02ae668a", size = 233301, upload-time = "2025-10-20T16:17:36.563Z" }, ] +[[package]] +name = "pillow" +version = "12.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" }, + { url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" }, + { url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" }, + { url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" }, + { url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" }, + { url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" }, + { url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" }, + { url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" }, + { url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" }, + { url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" }, + { url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" }, + { url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" }, + { url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" }, + { url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" }, + { url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" }, + { url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" }, +] + [[package]] name = "pluggy" version = "1.6.0" @@ -146,6 +352,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + [[package]] name = "pytest" version = "9.0.3" @@ -205,6 +420,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" }, ] +[[package]] +name = "seaborn" +version = "0.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy" }, + { name = "pandas" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, +] + [[package]] name = "six" version = "1.17.0" From 344b8d8c21f2a2db067be8b38e389aaf8140818e Mon Sep 17 00:00:00 2001 From: Stanislav Khrapov Date: Mon, 20 Apr 2026 17:09:47 +0200 Subject: [PATCH 2/4] fix: Disable Cython in simulation by default --- src/affidiff/model_generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/affidiff/model_generic.py b/src/affidiff/model_generic.py index ac25057..6697b4e 100644 --- a/src/affidiff/model_generic.py +++ b/src/affidiff/model_generic.py @@ -191,7 +191,7 @@ def update(self, state, error): return new_state def simulate(self, start=None, nsub=80, ndiscr=1, nobs=500, nsim=1, - diff=None, new_innov=True, cython=True): + diff=None, new_innov=True, cython=False): """Simulate observations from the model. Parameters From 3eef50a240b1680e94aa01e4be0d3e5cb561afd2 Mon Sep 17 00:00:00 2001 From: Stanislav Khrapov Date: Mon, 20 Apr 2026 17:16:34 +0200 Subject: [PATCH 3/4] test: Add a smoke test to verify basic functionality --- README.rst | 3 --- tests/smoke_test.py | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 README.rst create mode 100644 tests/smoke_test.py diff --git a/README.rst b/README.rst deleted file mode 100644 index ccbdb7b..0000000 --- a/README.rst +++ /dev/null @@ -1,3 +0,0 @@ -# Affine Diffusions - -Simulation and estimation of Affine Diffusion models. diff --git a/tests/smoke_test.py b/tests/smoke_test.py new file mode 100644 index 0000000..c0e0d31 --- /dev/null +++ b/tests/smoke_test.py @@ -0,0 +1,2 @@ +def test_smoke() -> None: + assert 2 * 2 == 4 \ No newline at end of file From 9dcaa30863d09a67a7413b72f1af27566569fd63 Mon Sep 17 00:00:00 2001 From: Stanislav Khrapov Date: Mon, 20 Apr 2026 17:18:00 +0200 Subject: [PATCH 4/4] remove smoke test --- .github/workflows/workflow.yaml | 5 ----- tests/smoke_test.py | 2 -- 2 files changed, 7 deletions(-) delete mode 100644 tests/smoke_test.py diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index 3fc2209..b01c87c 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -55,10 +55,5 @@ jobs: cache-dependency-glob: "uv.lock" - name: Build run: uv build - # Check that basic features work and we didn't miss to include crucial files - - name: Smoke test (wheel) - run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py - - name: Smoke test (source distribution) - run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py - name: Publish run: uv publish diff --git a/tests/smoke_test.py b/tests/smoke_test.py deleted file mode 100644 index c0e0d31..0000000 --- a/tests/smoke_test.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_smoke() -> None: - assert 2 * 2 == 4 \ No newline at end of file