diff --git a/Makefile b/Makefile index 2fe924d..21c9057 100644 --- a/Makefile +++ b/Makefile @@ -1,38 +1,43 @@ +#!/usr/bin/make -f +SHELL = /bin/sh +.DELETE_ON_ERROR: + +# boilerplate variables, do not edit +MAKEFILE_PATH := $(abspath $(firstword $(MAKEFILE_LIST))) +MAKEFILE_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) + +# required values, set to defaults here if not given in config.mk +PACKAGE_DIR ?= src +TEST_DIR ?= tests +STUB_DIR ?= stubs +LINTING_LINELENGTH ?= 120 +PYTHON ?= python +CODECOV_TOKEN ?= ${CODECOV_TOKEN} + CURRENT_SIGN_SETTING := $(shell git config commit.gpgSign) -PACKAGE_DIRECTORY=bayesian_hmm -TEST_DIRECTORY=tests -LINTING_LINELENGTH=120 -STUB_DIRECTORY=stubs - -.PHONY: help clean-pyc clean-build isort-test isort darglint-test black-test black stubs mypy-test pytest test format tox - -help: - @echo " help: Print this help" - @echo " clean-pyc: Remove python artifacts." - @echo " clean-build: Remove build artifacts." - @echo " isort-test: Test whether import statements are sorted." - @echo " isort: Sort import statements." - @echo " darglint-test: Test whether docstrings are valid." - @echo " black-test: Test whether black formatting is adhered to." - @echo " black: Apply black formatting." - @echo " stubs: Run stub generation." - @echo " mypy-test: Test whether mypy type annotations are sufficient." - @echo " pytest: Run pytest suite." - @echo " test: Run all tests." - @echo " format: Apply all formatting tools." - @echo " profile: Run cProfile on the MCMC example and print longest running functions." - @echo " tox: Run tox testing." - @echo " release: Build and upload to PyPI." +# use regex to go through this Makefile and print help lines +# help lines is any comment starting with double '#' (see next comment). Prints alphabetical order. +## help : print this help. +.PHONY: help +help: Makefile + @echo "\nBayesian Hidden Markov Models." + @echo "\n Generic commands" + @sed -n 's/^## / /p' $< | sort + +## clean: Remove python artifacts. +.PHONY: clean-pyc clean-build clean clean-pyc: - find . -regex '^./\($(PACKAGE_DIRECTORY)\|$(TEST_DIRECTORY)\)/.*\.py[co]' -delete - find . -regex '^./\($(PACKAGE_DIRECTORY)\|$(TEST_DIRECTORY)\)/.*__pycache__' -delete + find . -regex '^./\($(PACKAGE_DIR)\|$(TEST_DIR)\)/.*\.py[co]' -delete + find . -regex '^./\($(PACKAGE_DIR)\|$(TEST_DIR)\)/.*__pycache__' -delete clean-build: rm --force --recursive build/ rm --force --recursive dist/ rm --force --recursive *.egg-info +clean: clean-pyc clean-build + isort-test: clean-pyc isort \ --recursive \ @@ -40,7 +45,7 @@ isort-test: clean-pyc --line-width $(LINTING_LINELENGTH) \ --multi-line 3 \ --trailing-comma \ - $(PACKAGE_DIRECTORY) $(TEST_DIRECTORY) + $(PACKAGE_DIR) $(TEST_DIR) isort: clean-pyc isort \ @@ -48,48 +53,54 @@ isort: clean-pyc --line-width $(LINTING_LINELENGTH) \ --multi-line 3 \ --trailing-comma \ - $(PACKAGE_DIRECTORY) $(TEST_DIRECTORY) + $(PACKAGE_DIR) $(TEST_DIR) darglint-test: - darglint --docstring-style google --strictness full $(PACKAGE_DIRECTORY) $(TEST_DIRECTORY) + darglint --docstring-style google --strictness full $(PACKAGE_DIR) $(TEST_DIR) black-test: black \ --check \ - --include "^/($(PACKAGE_DIRECTORY)/|$(TEST_DIRECTORY)/).*\.pyi?" \ + --include "^/($(PACKAGE_DIR)/|$(TEST_DIR)/).*\.pyi?" \ --line-length $(LINTING_LINELENGTH) \ . black: black \ - --include "^/($(PACKAGE_DIRECTORY)/|$(TEST_DIRECTORY)/).*\.pyi?" \ + --include "^/($(PACKAGE_DIR)/|$(TEST_DIR)/).*\.pyi?" \ --line-length $(LINTING_LINELENGTH) \ . - +## stubs: Run stub generation. stubs: clean-pyc - stubgen -o $(STUB_DIRECTORY) $(PACKAGE_DIRECTORY) + stubgen -o $(STUB_DIR) $(PACKAGE_DIR) mypy-test: - mypy $(PACKAGE_DIRECTORY) + mypy $(PACKAGE_DIR) pytest: python -m pytest \ --verbose \ --color=yes \ - --cov=$(PACKAGE_DIRECTORY) \ - --cov-report term-missing + --cov=$(PACKAGE_DIR) \ + --cov-report term-missing \ + --cov-report xml -test: clean-pyc isort-test darglint-test black-test mypy-test pytest +## test: Run all tests. +test: clean-pyc isort-test darglint-test black-test pytest +## format: Apply all formatting tools. format: clean-pyc isort black stubs +## profile: Run cProfile on the MCMC example and print longest running functions. profile: - python -m cProfile -o .profile.txt "$(TEST_DIRECTORY)/example.py" + python -m cProfile -o .profile.txt "$(TEST_DIR)/example.py" python -c "import pstats; s = pstats.Stats('.profile.txt'); print(s.strip_dirs().sort_stats('cumtime').print_stats(20))" +## tox: Run tox testing. tox: tox +## release: Build and upload to PyPI. release: clean-pyc clean-build test git config commit.gpgSign true bumpversion $(bump) diff --git a/README.md b/README.md index 217a582..9ac46ff 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,14 @@ including efficient beam sampling for the latent sequence resampling steps, and multithreading when possible for parameter resampling. +## Warning + +We now recommend using `PyMC` for Bayesian hidden Markov models. You can find some experimental +scripts in the `experiments` directory for doing this. Because `PyMC` is better maintained, you +can expect better support, and more flexibility in model specification. It may lack some +idiosyncratic sampling optimizations, but is probably a better choice for most users. + + ## Installation The current version is development only, and installation is only recommended for diff --git a/experiments/truncated_dirichlet-pymc.py b/experiments/truncated_dirichlet-pymc.py new file mode 100644 index 0000000..55fd5ee --- /dev/null +++ b/experiments/truncated_dirichlet-pymc.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +"""Use PyMC 4.0 to demonstrate a truncated Dirichlet Process implementation. + +This script has leans heavily on this fantastic tutorial: https://www.pymc.io/projects/examples/en/latest/mixture_models/dp_mix.html +Refer there for any questions. + +PyMC is a well-developed and managed package, and we strongly suggest that users consider using this. For most practical applications, +a truncated Dirichlet Procees BHMM is almost surely sufficient, and PyMC 4 contains numerous optimizations for sampling etc. that +make it a very good choice. + +This script could be made more efficient in PyMC4: you can use StickBreakingWeights directly, for example. However, it was not clear +how to resolve categorical priors; see here: https://discourse.pymc.io/t/using-a-categorical-prior-for-a-mixture-model/5394/6 +""" + +# weird import with numpy is required for theano tensor in pymc 4.0 +import pymc as pm +import numpy +import numpy.distutils +numpy.distutils.__config__.blas_opt_info = numpy.distutils.__config__.blas_ilp64_opt_info +import theano.tensor as tt + + +# create some fake data with integers in range(N) +chains = [ + [0, 1, 2, 3], + [0, 1, 2, 3, 0, 1, 2, 2, 0, 1, 3, 0] +] + +# Define meta-parameters of BHMM +K = 8 # number of latent states +N = len(set(s for chain in chains for s in chain)) # number of observed states + +with pm.Model(coords={"states": range(K), "observations": range(N), "obs_id": range(N)}) as model: + alpha = pm.Gamma("alpha", 2.0, 2.0) + gamma = pm.Gamma("gamma", 3.0, 3.0) + beta_emission = pm.Gamma("beta_emission", 1.0, 1.0) + + # transition matrix: each row is a Dirichlet rv + w_transition = pm.StickBreakingWeights("beta_transition", alpha=alpha, K=K, dims="states") # only in PyMC 4 + pi = [pm.Dirichlet(f"pi_{state}", gamma * w_transition, dims="states") for state in range(K)] + + # emission matrix: another Dirichlet distribution + emissions = [pm.Dirichlet(f"emission_{state}", [beta_emission for _ in range(N)], dims="observations") for state in range(K)] + + # now, create latent state chain + # states = [pm.Categorical("s0", p = [1 / N for _ in range(N)])] + # for t in range(1, T): + # # get transitions from expanding out, since PyMC cannot index by random variables + # # prob = pm.Deterministic(f"prob_{t}", [row * state for row, state in zip(pi, states[t-1])]) + # # states.append(pm.Categorical(f"s{t}", p=prob)) + # # states.append(pm.Categorical(f"s{t}", p=pi[states[t-1]])) + # states.append(pm.Categorical(f"s{t}", p=pi[states[t-1].eval()])) + + # now, tie observations to latent states + # emissions = [pm.Categorical(f"e{t}", p=emissions[states[t].eval()], observed=chain) for t in range(T)] + + # now, create latent state chain + chain_states = [None for _ in chains] + chain_emissions = [None for _ in chains] + for i, chain in enumerate(chains): + chain_states[i] = [pm.Categorical(f"s_{i}_0", p = [1 / N for _ in range(N)])] + for t in range(1, len(chain)): + chain_states[i].append(pm.Categorical(f"s_{i}_{t}", p=pi[chain_states[i][t-1]])) + + # now, tie observations to latent states + chain_emissions[i] = [pm.Categorical(f"e_{i}_{t}", p=emissions[chain_states[i][t]], observed=chain[t]) for t in range(len(chain))] + + # time for fitting + trace = pm.sample(500, tune=100, cores=1) diff --git a/experiments/truncated_dirichlet-pymc3.py b/experiments/truncated_dirichlet-pymc3.py new file mode 100644 index 0000000..89d83e6 --- /dev/null +++ b/experiments/truncated_dirichlet-pymc3.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +"""Use PyMC3 to demonstrate a truncated Dirichlet Process implementation. + +This script has leans heavily on this fantastic tutorial: https://www.pymc.io/projects/examples/en/latest/mixture_models/dp_mix.html +Refer there for any questions. + +PyMC is a well-developed and managed package, and we strongly suggest that users consider using this. For most practical applications, +a truncated Dirichlet Procees BHMM is almost surely sufficient, and PyMC 4 contains numerous optimizations for sampling etc. that +make it a very good choice. + +This script could be made more efficient in PyMC4: you can use StickBreakingWeights directly, for example. However, it was not clear +how to resolve categorical priors; see here: https://discourse.pymc.io/t/using-a-categorical-prior-for-a-mixture-model/5394/6 +""" + +import pymc3 as pm +import theano.tensor as tt + + +def stick_breaking(beta): + portion_remaining = tt.concatenate([[1], tt.extra_ops.cumprod(1 - beta)[:-1]]) + return beta * portion_remaining + +# create some fake data (real data may need to be made equal length, or use a more sophisticated model specification) +chains = [ + [0, 1, 2, 3], + [0, 1, 2, 3, 0, 1, 2, 2, 0, 1, 3, 0] +] + +# Define meta-parameters of BHMM +K = 6 # number of latent states +N = len(set(s for chain in chains for s in chain)) # number of observed states + +model = pm.Model(coords={"states": range(K), "observations": range(N), "obs_id": range(N)}) + +with model: + alpha = pm.Gamma("alpha", 1.0, 1.0) + gamma = pm.Gamma("gamma", 1.0, 1.0) + + # transition matrix: each row is a Dirichlet rv + beta_transition = pm.Beta("beta_transition", 3.0, alpha, dims="states") + w_transition = pm.Deterministic("w_transition", stick_breaking(beta_transition), dims="states") + pi = [pm.Dirichlet(f"pi_{state}", gamma * w_transition, dims="states") for state in range(K)] + # pi = tt.real(pi) + + # emission matrix: another Dirichlet distribution + beta_emission = pm.Gamma("beta_emission", 1.0, 1.0) + emissions = [pm.Dirichlet(f"emission_{state}", [beta_emission for _ in range(N)], dims="observations") for state in range(K)] + # emissions = tt.real([tt.real(e) for e in emissions]) + + # now, create latent state chain + chain_states = [None for _ in chains] + chain_emissions = [None for _ in chains] + for i, chain in enumerate(chains): + chain_states[i] = [pm.Categorical(f"s_{i}_0", p = [1 / N for _ in range(N)])] + for t in range(1, len(chain)): + chain_states[i].append(pm.Categorical(f"s_{i}_{t}", p=tt.real(pi)[chain_states[i][t-1]])) + # now, tie observations to latent states + chain_emissions[i] = [pm.Categorical(f"e_{i}_{t}", p=tt.real(emissions)[chain_states[i][t]], observed=chain[t]) for t in range(len(chain))] + + # time for fitting + trace = pm.sample(500, tune=100) + diff --git a/requirements.txt b/requirements.txt index 06243b2..77a6c39 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,44 +1,27 @@ -atomicwrites==1.3.0 -attrs==19.1.0 -bleach==3.1.0 -certifi==2019.9.11 -chardet==3.0.4 -coverage==4.5.4 -darglint==1.1.0 -docutils==0.15.2 -filelock==3.0.12 -idna==2.8 -importlib-metadata==0.20 -isort==4.3.21 -more-itertools==7.2.0 -mpmath==1.1.0 -mypy==0.720 -mypy-extensions==0.4.1 -numpy==1.18.1 -packaging==19.1 -pkginfo==1.5.0.1 -pluggy==0.13.1 -py==1.8.0 -Pygments==2.4.2 -pyparsing==2.4.2 -pytest==5.1.2 -pytest-cov==2.7.1 -readme-renderer==24.0 -requests==2.22.0 -requests-toolbelt==0.9.1 -scipy==1.4.1 -six==1.12.0 -sympy==1.4 -terminaltables==3.1.0 -toml==0.10.0 -tox==3.14.3 -tox-travis==0.12 -tqdm==4.35.0 -twine==1.14.0 -typed-ast==1.4.0 -typing-extensions==3.7.4 -urllib3==1.25.3 -virtualenv==16.7.9 -wcwidth==0.1.7 -webencodings==0.5.1 -zipp==0.6.0 +attrs==22.1.0 +coverage==6.4.4 +darglint==1.8.1 +distlib==0.3.5 +filelock==3.8.0 +iniconfig==1.1.1 +mpmath==1.2.1 +mypy==0.971 +mypy-extensions==0.4.3 +numpy==1.23.2 +packaging==21.3 +platformdirs==2.5.2 +pluggy==1.0.0 +py==1.11.0 +pyparsing==3.0.9 +pytest==7.1.2 +pytest-cov==3.0.0 +scipy==1.9.0 +six==1.16.0 +sympy==1.10.1 +terminaltables==3.1.10 +toml==0.10.2 +tomli==2.0.1 +tox==3.25.1 +tqdm==4.64.0 +typing_extensions==4.3.0 +virtualenv==20.16.3 diff --git a/setup.py b/setup.py index b0915a6..4d75e0b 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,8 @@ name="bayesian_hmm", version="0.1.0", license="MIT", - packages=setuptools.find_packages(exclude=["tests"]), + package_dir={"": "src"}, + packages=setuptools.find_packages(where="src"), author="James Ross", author_email="jamespatross@gmail.com", description="A non-parametric Bayesian approach to hidden Markov models", diff --git a/bayesian_hmm/__init__.py b/src/bayesian_hmm/__init__.py similarity index 100% rename from bayesian_hmm/__init__.py rename to src/bayesian_hmm/__init__.py diff --git a/bayesian_hmm/chain.py b/src/bayesian_hmm/chain.py similarity index 100% rename from bayesian_hmm/chain.py rename to src/bayesian_hmm/chain.py diff --git a/bayesian_hmm/hdphmm.py b/src/bayesian_hmm/hdphmm.py similarity index 100% rename from bayesian_hmm/hdphmm.py rename to src/bayesian_hmm/hdphmm.py diff --git a/bayesian_hmm/utils.py b/src/bayesian_hmm/utils.py similarity index 100% rename from bayesian_hmm/utils.py rename to src/bayesian_hmm/utils.py diff --git a/bayesian_hmm/variables/__init__.py b/src/bayesian_hmm/variables/__init__.py similarity index 100% rename from bayesian_hmm/variables/__init__.py rename to src/bayesian_hmm/variables/__init__.py diff --git a/bayesian_hmm/variables/auxiliary_variable.py b/src/bayesian_hmm/variables/auxiliary_variable.py similarity index 97% rename from bayesian_hmm/variables/auxiliary_variable.py rename to src/bayesian_hmm/variables/auxiliary_variable.py index 0ebbebf..29da9de 100644 --- a/bayesian_hmm/variables/auxiliary_variable.py +++ b/src/bayesian_hmm/variables/auxiliary_variable.py @@ -91,9 +91,10 @@ def single_variable_resample(scale: float, count: int, exact: bool) -> int: An auxiliary variable, sampled with conditional distribution. Raises: - err: If an error is raised while computing the approximate log likelihood that is not recognised, it is + RecursionError: If an error is raised while computing the approximate log likelihood that is not recognised, it is + passed on to the user. + OverflowError: If an error is raised while computing the approximate log likelihood that is not recognised, it is passed on to the user. - """ # TODO: check if we can simplify this if count <= 0: diff --git a/bayesian_hmm/variables/dirichlet_distribution_family.py b/src/bayesian_hmm/variables/dirichlet_distribution_family.py similarity index 100% rename from bayesian_hmm/variables/dirichlet_distribution_family.py rename to src/bayesian_hmm/variables/dirichlet_distribution_family.py diff --git a/bayesian_hmm/variables/dirichlet_process_family.py b/src/bayesian_hmm/variables/dirichlet_process_family.py similarity index 100% rename from bayesian_hmm/variables/dirichlet_process_family.py rename to src/bayesian_hmm/variables/dirichlet_process_family.py diff --git a/bayesian_hmm/variables/hierarchical_dirichlet_distribution.py b/src/bayesian_hmm/variables/hierarchical_dirichlet_distribution.py similarity index 100% rename from bayesian_hmm/variables/hierarchical_dirichlet_distribution.py rename to src/bayesian_hmm/variables/hierarchical_dirichlet_distribution.py diff --git a/bayesian_hmm/variables/hierarchical_dirichlet_process.py b/src/bayesian_hmm/variables/hierarchical_dirichlet_process.py similarity index 100% rename from bayesian_hmm/variables/hierarchical_dirichlet_process.py rename to src/bayesian_hmm/variables/hierarchical_dirichlet_process.py diff --git a/bayesian_hmm/variables/hyperparameter.py b/src/bayesian_hmm/variables/hyperparameter.py similarity index 100% rename from bayesian_hmm/variables/hyperparameter.py rename to src/bayesian_hmm/variables/hyperparameter.py diff --git a/bayesian_hmm/variables/states.py b/src/bayesian_hmm/variables/states.py similarity index 100% rename from bayesian_hmm/variables/states.py rename to src/bayesian_hmm/variables/states.py diff --git a/bayesian_hmm/variables/stick_breaking_process.py b/src/bayesian_hmm/variables/stick_breaking_process.py similarity index 100% rename from bayesian_hmm/variables/stick_breaking_process.py rename to src/bayesian_hmm/variables/stick_breaking_process.py diff --git a/bayesian_hmm/variables/variable.py b/src/bayesian_hmm/variables/variable.py similarity index 100% rename from bayesian_hmm/variables/variable.py rename to src/bayesian_hmm/variables/variable.py diff --git a/stubs/bayesian_hmm/__init__.pyi b/stubs/bayesian_hmm/__init__.pyi index 5521944..579182a 100644 --- a/stubs/bayesian_hmm/__init__.pyi +++ b/stubs/bayesian_hmm/__init__.pyi @@ -1,7 +1,3 @@ -# Stubs for bayesian_hmm (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - -from .chain import Chain -from .hdphmm import HDPHMM -from .variables import AggregateState, DirichletDistributionFamily, DirichletProcessFamily, HierarchicalDirichletProcess, MissingState, StartingState, State, StickBreakingProcess, Variable, hyperparameter +from .chain import Chain as Chain +from .hdphmm import HDPHMM as HDPHMM +from .variables import AggregateState as AggregateState, DirichletDistributionFamily as DirichletDistributionFamily, DirichletProcessFamily as DirichletProcessFamily, HierarchicalDirichletProcess as HierarchicalDirichletProcess, MissingState as MissingState, StartingState as StartingState, State as State, StickBreakingProcess as StickBreakingProcess, Variable as Variable, hyperparameter as hyperparameter diff --git a/stubs/bayesian_hmm/chain.pyi b/stubs/bayesian_hmm/chain.pyi index cd14820..06f9647 100644 --- a/stubs/bayesian_hmm/chain.pyi +++ b/stubs/bayesian_hmm/chain.pyi @@ -1,22 +1,18 @@ -# Stubs for bayesian_hmm.chain (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import numpy import typing -from . import variables -from typing import Any +from . import variables as variables +from _typeshed import Incomplete -Numeric: Any -DictStrNum: Any +Numeric: Incomplete +DictStrNum: Incomplete InitDict = DictStrNum -DictStrDictStrNum: Any +DictStrDictStrNum: Incomplete NestedInitDict = DictStrDictStrNum class Chain: - emission_sequence: Any = ... - latent_sequence: Any = ... - T: Any = ... + emission_sequence: Incomplete + latent_sequence: Incomplete + T: Incomplete def __init__(self, sequence: typing.Sequence[variables.State]) -> None: ... def __len__(self) -> int: ... @property diff --git a/stubs/bayesian_hmm/hdphmm.pyi b/stubs/bayesian_hmm/hdphmm.pyi index 476d6b6..3d4b5ef 100644 --- a/stubs/bayesian_hmm/hdphmm.pyi +++ b/stubs/bayesian_hmm/hdphmm.pyi @@ -1,28 +1,24 @@ -# Stubs for bayesian_hmm.hdphmm (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import numpy import typing -from . import variables -from .chain import Chain, resample_latent_sequence -from .variables import hyperparameter -from typing import Any +from . import utils as utils, variables as variables +from .chain import Chain as Chain, resample_latent_sequence as resample_latent_sequence +from .variables import hyperparameter as hyperparameter +from _typeshed import Incomplete class HDPHMM: - chains: Any = ... - sticky: Any = ... - alpha: Any = ... - gamma: Any = ... - kappa: Any = ... - beta_emission: Any = ... - transition_model: Any - emission_model: Any - emission_counts: Any = ... - transition_counts: Any = ... - emissions: Any = ... - states: Any = ... - def __init__(self, emission_sequences: typing.Iterable[typing.Sequence[variables.State]], emissions: typing.Optional[typing.Set[variables.State]]=..., sticky: bool=..., alpha: hyperparameter.Hyperparameter=..., gamma: hyperparameter.Hyperparameter=..., kappa: variables.Hyperparameter=..., beta_emission: variables.Hyperparameter=...) -> None: ... + chains: Incomplete + sticky: Incomplete + alpha: Incomplete + gamma: Incomplete + kappa: Incomplete + beta_emission: Incomplete + transition_model: Incomplete + emission_model: Incomplete + emission_counts: Incomplete + transition_counts: Incomplete + emissions: Incomplete + states: Incomplete + def __init__(self, emission_sequences: typing.Iterable[typing.Sequence[variables.State]], emissions: typing.Optional[typing.Set[variables.State]] = ..., sticky: bool = ..., alpha: hyperparameter.Hyperparameter = ..., gamma: hyperparameter.Hyperparameter = ..., kappa: variables.Hyperparameter = ..., beta_emission: variables.Hyperparameter = ...) -> None: ... @property def initialised(self) -> bool: ... @initialised.setter @@ -35,12 +31,12 @@ class HDPHMM: def n(self) -> int: ... def to_array(self) -> numpy.array: ... def state_generator(self) -> typing.Generator[variables.State, None, None]: ... - def initialise(self, k: int=...) -> None: ... + def initialise(self, k: int = ...) -> None: ... def update_states(self) -> None: ... def update_counts(self) -> None: ... - def print_probabilities(self, digits: int=...) -> typing.Tuple[str, str]: ... + def print_probabilities(self, digits: int = ...) -> typing.Tuple[str, str]: ... def chain_log_likelihoods(self) -> typing.List[float]: ... def log_likelihood(self) -> float: ... - def resample_chains(self, ncores: int=...) -> Any: ... + def resample_chains(self, ncores: int = ...): ... def maximise_hyperparameters(self) -> None: ... - def mcmc(self, n: int=..., burn_in: int=..., save_every: int=..., ncores: int=..., verbose: Any=...) -> typing.Dict[str, typing.List[typing.Any]]: ... + def mcmc(self, n: int = ..., burn_in: int = ..., save_every: int = ..., ncores: int = ..., verbose: bool = ...) -> typing.Dict[str, typing.List[typing.Any]]: ... diff --git a/stubs/bayesian_hmm/utils.pyi b/stubs/bayesian_hmm/utils.pyi index 69b1408..854cd1b 100644 --- a/stubs/bayesian_hmm/utils.pyi +++ b/stubs/bayesian_hmm/utils.pyi @@ -1,14 +1,10 @@ -# Stubs for bayesian_hmm.utils (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import typing -from typing import Any +from _typeshed import Incomplete -NumericIterableType: Any -IteratorOutputType: Any +NumericIterableType: Incomplete +IteratorOutputType: Incomplete -def label_generator(labels: typing.Sequence[str]=...) -> typing.Generator[str, None, None]: ... -def dirichlet_process_generator(alpha: typing.Union[int, float]=..., output_generator: typing.Optional[typing.Iterator[IteratorOutputType]]=...) -> typing.Iterator[IteratorOutputType]: ... -def max_dict(d: typing.Dict[str, typing.Union[int, float]], eps: float=...) -> typing.Dict[str, float]: ... -def shrink_probabilities(d: NumericIterableType, eps: float=...) -> NumericIterableType: ... +def label_generator(labels: typing.Sequence[str] = ...) -> typing.Generator[str, None, None]: ... +def dirichlet_process_generator(alpha: typing.Union[int, float] = ..., output_generator: typing.Optional[typing.Iterator[IteratorOutputType]] = ...) -> typing.Iterator[IteratorOutputType]: ... +def max_dict(d: typing.Dict[str, typing.Union[int, float]], eps: float = ...) -> typing.Dict[str, float]: ... +def shrink_probabilities(d: NumericIterableType, eps: float = ...) -> NumericIterableType: ... diff --git a/stubs/bayesian_hmm/variables/__init__.pyi b/stubs/bayesian_hmm/variables/__init__.pyi index 6ee30db..b32b10a 100644 --- a/stubs/bayesian_hmm/variables/__init__.pyi +++ b/stubs/bayesian_hmm/variables/__init__.pyi @@ -1,13 +1,10 @@ -# Stubs for bayesian_hmm.variables (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - -from .auxiliary_variable import AuxiliaryVariable -from .dirichlet_distribution_family import DirichletDistributionFamily -from .dirichlet_process_family import DirichletProcessFamily -from .hierarchical_dirichlet_distribution import HierarchicalDirichletDistribution -from .hierarchical_dirichlet_process import HierarchicalDirichletProcess -from .hyperparameter import Hyperparameter -from .states import AggregateState, MissingState, StartingState, State -from .stick_breaking_process import StickBreakingProcess -from .variable import Variable +from . import hyperparameter as hyperparameter +from .auxiliary_variable import AuxiliaryVariable as AuxiliaryVariable +from .dirichlet_distribution_family import DirichletDistributionFamily as DirichletDistributionFamily +from .dirichlet_process_family import DirichletProcessFamily as DirichletProcessFamily +from .hierarchical_dirichlet_distribution import HierarchicalDirichletDistribution as HierarchicalDirichletDistribution +from .hierarchical_dirichlet_process import HierarchicalDirichletProcess as HierarchicalDirichletProcess +from .hyperparameter import Hyperparameter as Hyperparameter +from .states import AggregateState as AggregateState, MissingState as MissingState, StartingState as StartingState, State as State +from .stick_breaking_process import StickBreakingProcess as StickBreakingProcess +from .variable import Variable as Variable diff --git a/stubs/bayesian_hmm/variables/auxiliary_variable.pyi b/stubs/bayesian_hmm/variables/auxiliary_variable.pyi index f86be90..016e767 100644 --- a/stubs/bayesian_hmm/variables/auxiliary_variable.pyi +++ b/stubs/bayesian_hmm/variables/auxiliary_variable.pyi @@ -1,20 +1,16 @@ -# Stubs for bayesian_hmm.variables.auxiliary_variable (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import typing -from . import hyperparameter, states, stick_breaking_process, variable -from typing import Any +from . import hyperparameter as hyperparameter, states as states, stick_breaking_process as stick_breaking_process, variable as variable +from _typeshed import Incomplete class AuxiliaryVariable(variable.Variable): - alpha: Any = ... - beta: Any = ... - value: Any = ... + alpha: Incomplete + beta: Incomplete + value: Incomplete def __init__(self, alpha: hyperparameter.Hyperparameter, beta: stick_breaking_process.StickBreakingProcess) -> None: ... @staticmethod def single_variable_log_likelihood(scale: float, value: int, count: int, exact: bool) -> float: ... @staticmethod def single_variable_resample(scale: float, count: int, exact: bool) -> int: ... - def log_likelihood(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]], exact: bool=...) -> float: ... - def resample(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]], exact: bool=...) -> typing.Dict[states.State, typing.Dict[states.State, int]]: ... + def log_likelihood(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]], exact: bool = ...) -> float: ... + def resample(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]], exact: bool = ...) -> typing.Dict[states.State, typing.Dict[states.State, int]]: ... def value_aggregated(self) -> typing.Dict[states.State, int]: ... diff --git a/stubs/bayesian_hmm/variables/dirichlet_distribution_family.pyi b/stubs/bayesian_hmm/variables/dirichlet_distribution_family.pyi index 7073a96..7fab93d 100644 --- a/stubs/bayesian_hmm/variables/dirichlet_distribution_family.pyi +++ b/stubs/bayesian_hmm/variables/dirichlet_distribution_family.pyi @@ -1,14 +1,11 @@ -# Stubs for bayesian_hmm.variables.dirichlet_distribution_family (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import typing -from . import hyperparameter, states, variable -from typing import Any +from . import hyperparameter as hyperparameter, states as states, variable as variable +from .. import utils as utils +from _typeshed import Incomplete class DirichletDistributionFamily(variable.Variable): - value: Any = ... - def __init__(self, beta: typing.Union[hyperparameter.Hyperparameter, typing.Dict[states.State, hyperparameter.Hyperparameter]]) -> None: ... + value: Incomplete + def __init__(self, beta: typing.Union[hyperparameter.Hyperparameter, typing.Dict[states.State, hyperparameter.Hyperparameter]]): ... @property def states_inner(self) -> typing.Set[states.State]: ... @property @@ -16,5 +13,5 @@ class DirichletDistributionFamily(variable.Variable): def posterior_parameters(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]]) -> typing.Dict[states.State, typing.Dict[states.State, float]]: ... def log_likelihood(self) -> float: ... def resample(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]]) -> typing.Dict[states.State, typing.Dict[states.State, float]]: ... - def add_state(self, state: states.State, inner: bool=..., outer: bool=...) -> None: ... - def remove_state(self, state: states.State, inner: bool=..., outer: bool=...) -> None: ... + def add_state(self, state: states.State, inner: bool = ..., outer: bool = ...) -> None: ... + def remove_state(self, state: states.State, inner: bool = ..., outer: bool = ...) -> None: ... diff --git a/stubs/bayesian_hmm/variables/dirichlet_process_family.pyi b/stubs/bayesian_hmm/variables/dirichlet_process_family.pyi index 27f70df..02e83f6 100644 --- a/stubs/bayesian_hmm/variables/dirichlet_process_family.pyi +++ b/stubs/bayesian_hmm/variables/dirichlet_process_family.pyi @@ -1,16 +1,13 @@ -# Stubs for bayesian_hmm.variables.dirichlet_process_family (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import typing -from . import hyperparameter, states, stick_breaking_process, variable -from typing import Any +from . import hyperparameter as hyperparameter, states as states, stick_breaking_process as stick_breaking_process, variable as variable +from .. import utils as utils +from _typeshed import Incomplete class DirichletProcessFamily(variable.Variable): - beta: Any = ... - gamma: Any = ... - kappa: Any = ... - value: Any + beta: Incomplete + gamma: Incomplete + kappa: Incomplete + value: Incomplete def __init__(self, beta: stick_breaking_process.StickBreakingProcess, gamma: hyperparameter.Hyperparameter, kappa: hyperparameter.Hyperparameter) -> None: ... @property def sticky(self) -> bool: ... @@ -21,5 +18,5 @@ class DirichletProcessFamily(variable.Variable): def posterior_parameters(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]]) -> typing.Dict[states.State, typing.Dict[states.State, float]]: ... def log_likelihood(self) -> float: ... def resample(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]]) -> typing.Dict[states.State, typing.Dict[states.State, float]]: ... - def add_state(self, state: states.State, inner: bool=..., outer: bool=...) -> None: ... - def remove_state(self, state: states.State, inner: bool=..., outer: bool=...) -> None: ... + def add_state(self, state: states.State, inner: bool = ..., outer: bool = ...) -> None: ... + def remove_state(self, state: states.State, inner: bool = ..., outer: bool = ...) -> None: ... diff --git a/stubs/bayesian_hmm/variables/hierarchical_dirichlet_distribution.pyi b/stubs/bayesian_hmm/variables/hierarchical_dirichlet_distribution.pyi index a17b661..5dc4c98 100644 --- a/stubs/bayesian_hmm/variables/hierarchical_dirichlet_distribution.pyi +++ b/stubs/bayesian_hmm/variables/hierarchical_dirichlet_distribution.pyi @@ -1,16 +1,12 @@ -# Stubs for bayesian_hmm.variables.hierarchical_dirichlet_distribution (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import typing -from . import hyperparameter, states, variable -from typing import Any +from . import dirichlet_distribution_family as dirichlet_distribution_family, hyperparameter as hyperparameter, states as states, variable as variable +from _typeshed import Incomplete class HierarchicalDirichletDistribution(variable.Variable): - beta: Any = ... - pi: Any = ... + beta: Incomplete + pi: Incomplete def __init__(self, beta: hyperparameter.Hyperparameter) -> None: ... def log_likelihood(self) -> float: ... def resample(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]]) -> None: ... - def add_state(self, state: states.State, inner: bool=..., outer: bool=...) -> None: ... - def remove_state(self, state: states.State, inner: bool=..., outer: bool=...) -> None: ... + def add_state(self, state: states.State, inner: bool = ..., outer: bool = ...) -> None: ... + def remove_state(self, state: states.State, inner: bool = ..., outer: bool = ...) -> None: ... diff --git a/stubs/bayesian_hmm/variables/hierarchical_dirichlet_process.pyi b/stubs/bayesian_hmm/variables/hierarchical_dirichlet_process.pyi index cbbb77c..c5f8380 100644 --- a/stubs/bayesian_hmm/variables/hierarchical_dirichlet_process.pyi +++ b/stubs/bayesian_hmm/variables/hierarchical_dirichlet_process.pyi @@ -1,19 +1,15 @@ -# Stubs for bayesian_hmm.variables.hierarchical_dirichlet_process (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import typing -from . import hyperparameter, states, variable -from typing import Any +from . import auxiliary_variable as auxiliary_variable, dirichlet_process_family as dirichlet_process_family, hyperparameter as hyperparameter, states as states, stick_breaking_process as stick_breaking_process, variable as variable +from _typeshed import Incomplete class HierarchicalDirichletProcess(variable.Variable): - sticky: Any = ... - alpha: Any = ... - gamma: Any = ... - kappa: Any = ... - beta: Any - auxiliary_variable: Any - pi: Any + sticky: Incomplete + alpha: Incomplete + gamma: Incomplete + kappa: Incomplete + beta: Incomplete + auxiliary_variable: Incomplete + pi: Incomplete def __init__(self, sticky: bool, alpha: hyperparameter.Hyperparameter, gamma: hyperparameter.Hyperparameter, kappa: hyperparameter.Hyperparameter) -> None: ... def log_likelihood(self) -> float: ... def resample(self, counts: typing.Dict[states.State, typing.Dict[states.State, int]]) -> None: ... diff --git a/stubs/bayesian_hmm/variables/hyperparameter.pyi b/stubs/bayesian_hmm/variables/hyperparameter.pyi index a0dff78..9bc383d 100644 --- a/stubs/bayesian_hmm/variables/hyperparameter.pyi +++ b/stubs/bayesian_hmm/variables/hyperparameter.pyi @@ -1,25 +1,21 @@ -# Stubs for bayesian_hmm.variables.hyperparameter (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import typing -from . import variable -from typing import Any +from . import variable as variable +from _typeshed import Incomplete class Hyperparameter(variable.Variable): - prior: Any = ... - prior_log_likelihood: Any = ... - value: Any = ... + prior: Incomplete + prior_log_likelihood: Incomplete + value: Incomplete def __init__(self, prior: typing.Callable[[], typing.Union[float, int]], log_likelihood: typing.Callable[[typing.Union[float, int]], float]) -> None: ... def log_likelihood(self) -> float: ... - def resample(self, posterior_log_likelihood: typing.Optional[typing.Callable[[typing.Union[float, int]], float]]=..., force: bool=...) -> typing.Union[float, int]: ... + def resample(self, posterior_log_likelihood: typing.Optional[typing.Callable[[typing.Union[float, int]], float]] = ..., force: bool = ...) -> typing.Union[float, int]: ... class Gamma(Hyperparameter): - def __init__(self, shape: float=..., scale: float=...) -> None: ... + def __init__(self, shape: float = ..., scale: float = ...): ... class Beta(Hyperparameter): - def __init__(self, shape: float=..., scale: float=...) -> None: ... + def __init__(self, shape: float = ..., scale: float = ...): ... class Dummy(Hyperparameter): - def __init__(self, value: typing.Union[int, float]=...) -> None: ... - def resample(self, posterior_log_likelihood: typing.Optional[typing.Callable[[typing.Union[float, int]], float]]=..., force: bool=...) -> typing.Union[float, int]: ... + def __init__(self, value: typing.Union[int, float] = ...): ... + def resample(self, posterior_log_likelihood: typing.Optional[typing.Callable[[typing.Union[float, int]], float]] = ..., force: bool = ...) -> typing.Union[float, int]: ... diff --git a/stubs/bayesian_hmm/variables/states.pyi b/stubs/bayesian_hmm/variables/states.pyi index 334fc2f..dfa9d70 100644 --- a/stubs/bayesian_hmm/variables/states.pyi +++ b/stubs/bayesian_hmm/variables/states.pyi @@ -1,23 +1,22 @@ -# Stubs for bayesian_hmm.variables.states (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import collections -from typing import Any +from _typeshed import Incomplete class State: - ___slots__: Any = ... - value: Any = ... - def __init__(self, value: collections.abc.Hashable) -> Any: ... + ___slots__: Incomplete + value: Incomplete + def __init__(self, value: collections.abc.Hashable) -> None: ... @property def special(self) -> bool: ... def __hash__(self) -> int: ... - def __eq__(self, other: Any) -> bool: ... - def __lt__(self, other: Any) -> bool: ... + def __eq__(self, other) -> bool: ... + def __lt__(self, other) -> bool: ... + def __ge__(self, other): ... + def __gt__(self, other): ... + def __le__(self, other): ... class SpecialState(State): - def __init__(self, value: str) -> Any: ... - def __eq__(self, other: Any) -> bool: ... + def __init__(self, value: str) -> None: ... + def __eq__(self, other) -> bool: ... def __hash__(self) -> int: ... class StartingState(SpecialState): diff --git a/stubs/bayesian_hmm/variables/stick_breaking_process.pyi b/stubs/bayesian_hmm/variables/stick_breaking_process.pyi index 3af8b0a..52f3df6 100644 --- a/stubs/bayesian_hmm/variables/stick_breaking_process.pyi +++ b/stubs/bayesian_hmm/variables/stick_breaking_process.pyi @@ -1,16 +1,12 @@ -# Stubs for bayesian_hmm.variables.stick_breaking_process (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import typing -from . import auxiliary_variable, hyperparameter, states, variable -from typing import Any +from . import auxiliary_variable as auxiliary_variable, hyperparameter as hyperparameter, states as states, variable as variable +from _typeshed import Incomplete class StickBreakingProcess(variable.Variable): - alpha: Any = ... - value: Any = ... + alpha: Incomplete + value: Incomplete def __init__(self, alpha: hyperparameter.Hyperparameter) -> None: ... def log_likelihood(self) -> float: ... - def resample(self, auxiliary: auxiliary_variable.AuxiliaryVariable) -> typing.Dict[states.State, float]: ... + def resample(self, auxiliary: auxiliary_variable.AuxiliaryVariable) -> typing.Dict['states.State', float]: ... def add_state(self, state: states.State) -> None: ... def remove_state(self, state: states.State) -> None: ... diff --git a/stubs/bayesian_hmm/variables/variable.pyi b/stubs/bayesian_hmm/variables/variable.pyi index a4042b4..c4705aa 100644 --- a/stubs/bayesian_hmm/variables/variable.pyi +++ b/stubs/bayesian_hmm/variables/variable.pyi @@ -1,9 +1,5 @@ -# Stubs for bayesian_hmm.variables.variable (Python 3) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - import abc class Variable(metaclass=abc.ABCMeta): @abc.abstractmethod - def __init__(self) -> None: ... + def __init__(self): ... diff --git a/tox.ini b/tox.ini index 4a124bc..aec0e22 100644 --- a/tox.ini +++ b/tox.ini @@ -2,7 +2,7 @@ [tox] envlist = - python3.6, python3.7, python3.8 + py36, py37, py38, py39, py310 linting [testenv]