Skip to content

Commit

Permalink
Remove class attribures. Related to #55
Browse files Browse the repository at this point in the history
  • Loading branch information
Retiefasaurus committed Nov 24, 2023
1 parent ef4e2f2 commit 46d9867
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 103 deletions.
1 change: 1 addition & 0 deletions grainlearning/dynamic_systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class DynamicSystem:
:param estimated_params_cv: Estimated parameter coefficient of variation as the second moment of the distribution (:math:`x_\sigma = \sqrt{\sum_i w_i * (x_i - x_\mu)^2} / x_\mu`), defaults to None, optional
"""


def __init__(
self,
obs_data: np.ndarray,
Expand Down
44 changes: 23 additions & 21 deletions grainlearning/inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
This module contains various methods for performing statistical and Bayesian inference
"""
from typing import Type

import numpy as np
from scipy.stats import multivariate_normal
from grainlearning.dynamic_systems import DynamicSystem
from scipy.stats import multivariate_normal


class SMC:
Expand Down Expand Up @@ -43,39 +44,40 @@ class SMC:
with the maxima of the observations, defaults to True
:param cov_matrices: Covariance matrices of shape (num_steps, num_obs, num_obs),
defaults to None, Optional
:param likelihoods: Likelihood distributions of shape (num_steps, num_samples)
:param posteriors: Posterior distributions of shape (num_steps, num_samples)
:param ess: Time evolution of the effective sample size
"""

#: Target effective sample size
ess_target: float

#: True if the covariance matrix is scaled with the maximum of the observations, defaults to True
scale_cov_with_max: bool = True

#: Covariance matrices of shape (num_steps, num_obs, num_obs)
cov_matrices: np.array

#: Likelihood distributions of shape (num_steps, num_samples)
likelihoods: np.array

#: Posterior distributions of shape (num_steps, num_samples)
posteriors: np.array

#: Time evolution of the effective sample size
ess: np.array

def __init__(
self,
ess_target: float,
scale_cov_with_max: bool = True,
cov_matrices: np.array = None,
):
"""Initialize the SMC class"""
"""Initialize the SMC class
Parameters
----------
ess_target : float
Target effective sample size
scale_cov_with_max : bool, optional
True if the covariance matrix is scaled with the maximum of the observations, by default True
cov_matrices : np.array, optional
Covariance matrices of shape (num_steps, num_obs, num_obs), by default None
"""
self.ess_target = ess_target

self.scale_cov_with_max = scale_cov_with_max

self.cov_matrices = cov_matrices

self.likelihoods = None

self.posteriors = None

self.ess = None

@classmethod
def from_dict(cls: Type["SMC"], obj: dict):
"""Initialize the class using a dictionary style
Expand Down Expand Up @@ -197,4 +199,4 @@ def compute_effective_sample_size(self):
ess = 1.0 / np.sum(self.posteriors ** 2, axis=1)
ess /= num_samples
ess = ess.reshape(num_steps, 1)
self.ess = ess
self.ess = ess
65 changes: 32 additions & 33 deletions grainlearning/iterative_bayesian_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
This module contains various Bayesian filtering classes by mixing the inference and sampling methods
from the :mod:`.inference` and :mod:`.sampling` modules.
"""
from typing import Type, List
from pickle import load
from typing import List, Type

import numpy as np
from scipy import optimize
from grainlearning.dynamic_systems import DynamicSystem, IODynamicSystem
from grainlearning.inference import SMC
from grainlearning.sampling import GaussianMixtureModel, generate_params_qmc
from grainlearning.tools import voronoi_vols
from scipy import optimize


class IterativeBayesianFilter:
Expand Down Expand Up @@ -73,45 +74,37 @@ class IterativeBayesianFilter:
:param ess_tol: Tolerance for the target effective sample size to converge, defaults to 1.0e-2
:param proposal: A proposal distribution to sample the state-parameter space, defaults to None
:param proposal_data_file: Pickle that stores the previously trained proposal distribution, defaults to None
:param param_data_list: List of the parameter samples of shape (num_samples, num_params) generated in all iterations
:param sigma_list: List of sigma values optimized to satisfy the target effective sample size in all iterations
:param posterior: The posterior distribution of model states at the last time step
"""

#: The inference class quantify the evolution of the posterior distribution of model states over time
inference = Type["SMC"]

#: The sampling class generates new samples from the proposal density
sampling = Type["GaussianMixtureModel"]

#: List of the parameter samples of shape (num_samples, num_params) generated in all iterations
param_data_list: List = []

#: List of sigma values optimized to satisfy the target effective sample size in all iterations
sigma_list: List = []

#: This a tolerance to which the optimization algorithm converges.
ess_tol: float = 1.0e-2

#: The non-informative distribution to draw the initial samples
initial_sampling: str = "halton"

#: The current proposal distribution
proposal: np.ndarray = None

#: The next proposal distribution
posterior: np.ndarray = None

#: The name of the file that stores the current proposal distribution
proposal_data_file: str = None

def __init__(
self,
inference: Type["SMC"],
sampling: Type["GaussianMixtureModel"],
inference: Type["SMC"] = None,
sampling: Type["GaussianMixtureModel"] = None,
ess_tol: float = 1.0e-2,
initial_sampling: str = 'halton',
proposal: np.ndarray = None,
proposal_data_file: str = None,
):
"""Initialize the Iterative Bayesian Filter."""
"""Initialize the Iterative Bayesian Filter class
Parameters
----------
inference : Type["SMC"], optional
The inference class quantify the evolution of the posterior distribution of model states over time, by default None
sampling : Type["GaussianMixtureModel"], optional
The sampling class generates new samples from the proposal density, by default None
ess_tol : float, optional
This a tolerance to which the optimization algorithm converges, by default 1.0e-2
initial_sampling : str, optional
The non-informative distribution to draw the initial samples, by default 'halton'
proposal : np.ndarray, optional
The current proposal distribution, by default None
proposal_data_file : str, optional
_description_, by default None
"""

self.inference = inference

Expand All @@ -125,6 +118,12 @@ def __init__(

self.proposal_data_file = proposal_data_file

self.param_data_list = []

self.sigma_list = []

self.posterior = None

@classmethod
def from_dict(cls: Type["IterativeBayesianFilter"], obj: dict):
"""Initialize the class using a dictionary style
Expand Down Expand Up @@ -238,4 +237,4 @@ def save_proposal_to_file(self, system: Type["IODynamicSystem"]):
:param system: Dynamic system class
"""
self.sampling.save_gmm_to_file(f'{system.sim_data_dir}/iter{system.curr_iter-1}/{self.proposal_data_file}')
self.sampling.save_gmm_to_file(f'{system.sim_data_dir}/iter{system.curr_iter-1}/{self.proposal_data_file}')
89 changes: 40 additions & 49 deletions grainlearning/sampling.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"""
This module contains various methods to sample the state-parameter space of a dynamic system.
"""
from typing import Type
from pickle import dump, load
from typing import Type

import numpy as np
from sklearn.mixture import BayesianGaussianMixture
from scipy.stats.qmc import Sobol, Halton, LatinHypercube
from grainlearning.dynamic_systems import DynamicSystem

from scipy.stats.qmc import Halton, LatinHypercube, Sobol
from sklearn.mixture import BayesianGaussianMixture

# from grainlearning.tools import regenerate_params_with_gmm, unweighted_resample#

Expand Down Expand Up @@ -85,61 +85,52 @@ class GaussianMixtureModel:
This can speed up convergence when fit is called several times on similar problems. See the Glossary.
:param expand_factor: factor used when converting the ensemble from weighted to unweighted, defaults to 10, optional
:param slice_sampling: flag to use slice sampling, defaults to False, optional
:param gmm: The class of the Gaussian Mixture Model
:param max_params: Current maximum values of the parameters
"""
#: Maximum number of components
max_num_components: int = 0

#: The dirichlet concentration of each component on the weight distribution (Dirichlet), default to None.
weight_concentration_prior: float = 0.0

#: String describing the type of covariance parameters to use.
covariance_type: str = "full"

#: number of initialization to perform, defaults to 1.
n_init: int = 1

#: tolerance threshold, defaults to 1.0e-3.
tol: float = 1.0e-3

#: maximum number of EM iterations to perform, defaults to 100
max_iter: int = 100

#: random seed given to the method chosen to initialize the weights, the means and the covariances.
random_state: int

#: The method used to initialize the weights, the means and the covariances.
init_params: str = "kmeans"

#: flag to use warm start, defaults to False.
warm_start: bool = False

#: the factor used when converting and populating the ensemble from weighted to unweighted, defaults to 10.
expand_factor: int = 10

#: flag to use slice sampling, defaults to False.
slice_sampling: False

#: The class of the Gaussian Mixture Model
gmm: Type["BayesianGaussianMixture"]

#: Current maximum values of the parameters
max_params = None


def __init__(
self,
max_num_components,
weight_concentration_prior: float = None,
covariance_type: str = "tied",
max_num_components=0,
weight_concentration_prior: float = 0.2,
covariance_type: str = "full",
n_init: int = 1,
tol: float = 1.0e-5,
tol: float = 1.0e-3,
max_iter: int = 100,
random_state: int = None,
init_params: str = "kmeans",
warm_start: bool = False,
expand_factor: int = 10,
slice_sampling: bool = False,
):
""" Initialize the Gaussian Mixture Model class"""
"""Initialize the Gaussian mixture model.
Parameters
----------
max_num_components : _type_
Maximum number of components
weight_concentration_prior : float, optional
The dirichlet concentration of each component on the weight distribution (Dirichlet), by default None
covariance_type : str, optional
String describing the type of covariance parameters to use, by default "tied"
n_init : int, optional
number of initialization to perform, by default 1
tol : float, optional
Tolerance threshold, defaults to 1.0e-3, by default 1.0e-5
max_iter : int, optional
Maximum number of EM iterations to perform, by default 100
random_state : int, optional
Random seed given to the method chosen to initialize the weights, the means and the covariances, by default None
init_params : str, optional
The method used to initialize the weights, the means and the covariances, by default "kmeans"
warm_start : bool, optional
Flag to use warm start, defaults to False., by default False
expand_factor : int, optional
The factor used when converting and populating the ensemble from weighted to unweighted, by default 10
slice_sampling : bool, optional
Flag to use slice sampling, by default False
"""
self.max_num_components = max_num_components

if weight_concentration_prior is None:
Expand Down Expand Up @@ -169,7 +160,7 @@ def __init__(

self.expanded_normalized_params = None

self.gmm = Type["BayesianGaussianMixture"]
self.gmm = None

@classmethod
def from_dict(cls: Type["GaussianMixtureModel"], obj: dict):
Expand Down Expand Up @@ -370,4 +361,4 @@ def generate_params_qmc(system: Type["DynamicSystem"], num_samples: int, method:
mean + (param_table[sim_i][param_i] - 0.5) * 2 * std
)

return np.array(param_table, ndmin=2)
return np.array(param_table, ndmin=2)

0 comments on commit 46d9867

Please sign in to comment.