diff --git a/pymc/data.py b/pymc/data.py index 4b3538a34..507f547e5 100644 --- a/pymc/data.py +++ b/pymc/data.py @@ -14,7 +14,6 @@ import io import urllib.request -import warnings from collections.abc import Sequence from copy import copy @@ -40,10 +39,8 @@ from pymc.vartypes import isgenerator __all__ = [ - "ConstantData", "Data", "Minibatch", - "MutableData", "get_data", ] BASE_URL = "https://raw.githubusercontent.com/pymc-devs/pymc-examples/main/examples/data/{filename}" @@ -218,66 +215,6 @@ def determine_coords( return coords, new_dims -def ConstantData( - name: str, - value, - *, - dims: Sequence[str] | None = None, - coords: dict[str, Sequence | np.ndarray] | None = None, - infer_dims_and_coords=False, - **kwargs, -) -> TensorConstant: - """Alias for ``pm.Data``. - - Registers the ``value`` as a :class:`~pytensor.tensor.TensorConstant` with the model. - For more information, please reference :class:`pymc.Data`. - """ - warnings.warn( - "ConstantData is deprecated. All Data variables are now mutable. Use Data instead.", - FutureWarning, - ) - - var = Data( - name, - value, - dims=dims, - coords=coords, - infer_dims_and_coords=infer_dims_and_coords, - **kwargs, - ) - return cast(TensorConstant, var) - - -def MutableData( - name: str, - value, - *, - dims: Sequence[str] | None = None, - coords: dict[str, Sequence | np.ndarray] | None = None, - infer_dims_and_coords=False, - **kwargs, -) -> SharedVariable: - """Alias for ``pm.Data``. - - Registers the ``value`` as a :class:`~pytensor.compile.sharedvalue.SharedVariable` - with the model. For more information, please reference :class:`pymc.Data`. - """ - warnings.warn( - "MutableData is deprecated. All Data variables are now mutable. Use Data instead.", - FutureWarning, - ) - - var = Data( - name, - value, - dims=dims, - coords=coords, - infer_dims_and_coords=infer_dims_and_coords, - **kwargs, - ) - return cast(SharedVariable, var) - - def Data( name: str, value, @@ -285,7 +222,6 @@ def Data( dims: Sequence[str] | None = None, coords: dict[str, Sequence | np.ndarray] | None = None, infer_dims_and_coords=False, - mutable: bool | None = None, **kwargs, ) -> SharedVariable | TensorConstant: """Create a data container that registers a data variable with the model. @@ -380,11 +316,6 @@ def Data( "Pass them directly to `observed` if you want to trigger auto-imputation" ) - if mutable is not None: - warnings.warn( - "Data is now always mutable. Specifying the `mutable` kwarg will raise an error in a future release", - FutureWarning, - ) x = pytensor.shared(arr, name, **kwargs) if isinstance(dims, str): diff --git a/pymc/distributions/custom.py b/pymc/distributions/custom.py index 86aba1204..476d5bc41 100644 --- a/pymc/distributions/custom.py +++ b/pymc/distributions/custom.py @@ -13,7 +13,6 @@ # limitations under the License. import functools import re -import warnings from collections.abc import Callable, Sequence @@ -715,13 +714,6 @@ def __new__( ) dist_params = cls.parse_dist_params(dist_params) cls.check_valid_dist_random(dist, random, dist_params) - moment = kwargs.pop("moment", None) - if moment is not None: - warnings.warn( - "`moment` argument is deprecated. Use `support_point` instead.", - FutureWarning, - ) - support_point = moment if dist is not None: kwargs.setdefault("class_name", f"CustomDist_{name}") return _CustomSymbolicDist( diff --git a/pymc/distributions/dist_math.py b/pymc/distributions/dist_math.py index 3f675406f..55efcb3b3 100644 --- a/pymc/distributions/dist_math.py +++ b/pymc/distributions/dist_math.py @@ -18,8 +18,6 @@ @author: johnsalvatier """ -import warnings - from collections.abc import Iterable from functools import partial @@ -419,12 +417,3 @@ def log_i0(x): + 11025.0 / (98304.0 * x**4.0) ), ) - - -def incomplete_beta(a, b, value): - warnings.warn( - "incomplete_beta has been deprecated. Use pytensor.tensor.betainc instead.", - FutureWarning, - stacklevel=2, - ) - return pt.betainc(a, b, value) diff --git a/pymc/distributions/distribution.py b/pymc/distributions/distribution.py index 3f080b7e5..f8712c51e 100644 --- a/pymc/distributions/distribution.py +++ b/pymc/distributions/distribution.py @@ -60,7 +60,7 @@ convert_observed_data, floatX, ) -from pymc.util import UNSET, _add_future_warning_tag +from pymc.util import UNSET from pymc.vartypes import continuous_types, string_types __all__ = [ @@ -571,10 +571,7 @@ def dist( ndim_supp = cls.rv_op(*dist_params, **kwargs).owner.op.ndim_supp create_size = find_size(shape=shape, size=size, ndim_supp=ndim_supp) - rv_out = cls.rv_op(*dist_params, size=create_size, **kwargs) - - _add_future_warning_tag(rv_out) - return rv_out + return cls.rv_op(*dist_params, size=create_size, **kwargs) @node_rewriter([SymbolicRandomVariable]) diff --git a/pymc/distributions/shape_utils.py b/pymc/distributions/shape_utils.py index 6f54aba2d..8ef378b76 100644 --- a/pymc/distributions/shape_utils.py +++ b/pymc/distributions/shape_utils.py @@ -43,7 +43,6 @@ from pymc.exceptions import ShapeError from pymc.pytensorf import PotentialShapeType -from pymc.util import _add_future_warning_tag def to_tuple(shape): @@ -264,7 +263,6 @@ def change_dist_size( op = dist.owner.op new_dist = _change_dist_size(op, dist, new_size=new_size, expand=expand) - _add_future_warning_tag(new_dist) new_dist.name = dist.name for k, v in dist.tag.__dict__.items(): diff --git a/pymc/distributions/timeseries.py b/pymc/distributions/timeseries.py index 87347add1..f18e1f4c2 100644 --- a/pymc/distributions/timeseries.py +++ b/pymc/distributions/timeseries.py @@ -286,13 +286,6 @@ class GaussianRandomWalk(PredefinedRandomWalk): @classmethod def get_dists(cls, mu=0.0, sigma=1.0, *, init_dist=None, **kwargs): - if "init" in kwargs: - warnings.warn( - "init parameter is now called init_dist. Using init will raise an error in a future release.", - FutureWarning, - ) - init_dist = kwargs.pop("init") - if init_dist is None: warnings.warn( "Initial distribution not specified, defaulting to `Normal.dist(0, 100)`." @@ -340,14 +333,6 @@ class MvGaussianRandomWalk(PredefinedRandomWalk): @classmethod def get_dists(cls, mu, *, cov=None, tau=None, chol=None, lower=True, init_dist=None, **kwargs): - if "init" in kwargs: - warnings.warn( - "init parameter is now called init_dist. Using init will raise an error " - "in a future release.", - FutureWarning, - ) - init_dist = kwargs.pop("init") - if init_dist is None: warnings.warn( "Initial distribution not specified, defaulting to `MvNormal.dist(0, I*100)`." @@ -396,14 +381,6 @@ class MvStudentTRandomWalk(PredefinedRandomWalk): def get_dists( cls, *, nu, mu, scale=None, tau=None, chol=None, lower=True, init_dist=None, **kwargs ): - if "init" in kwargs: - warnings.warn( - "init parameter is now called init_dist. Using init will raise an error " - "in a future release.", - FutureWarning, - ) - init_dist = kwargs.pop("init") - if init_dist is None: warnings.warn( "Initial distribution not specified, defaulting to `MvNormal.dist(0, I*100)`." @@ -588,13 +565,6 @@ def dist( sigma = pt.as_tensor_variable(sigma) rhos = pt.atleast_1d(pt.as_tensor_variable(rho)) - if "init" in kwargs: - warnings.warn( - "init parameter is now called init_dist. Using init will raise an error in a future release.", - FutureWarning, - ) - init_dist = kwargs.pop("init") - ar_order = cls._get_ar_order(rhos=rhos, constant=constant, ar_order=ar_order) steps = get_support_shape_1d( support_shape=steps, shape=kwargs.get("shape", None), support_shape_offset=ar_order diff --git a/pymc/distributions/transforms.py b/pymc/distributions/transforms.py index ebdaf3c3e..b1e02fd1f 100644 --- a/pymc/distributions/transforms.py +++ b/pymc/distributions/transforms.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import warnings from functools import singledispatch @@ -48,22 +47,6 @@ ] -def __getattr__(name): - if name in ("univariate_ordered", "multivariate_ordered"): - warnings.warn(f"{name} has been deprecated, use ordered instead.", FutureWarning) - return ordered - - if name in ("univariate_sum_to_1", "multivariate_sum_to_1"): - warnings.warn(f"{name} has been deprecated, use sum_to_1 instead.", FutureWarning) - return sum_to_1 - - if name == "RVTransform": - warnings.warn("RVTransform has been renamed to Transform", FutureWarning) - return Transform - - raise AttributeError(f"module {__name__} has no attribute {name}") - - @singledispatch def _default_transform(op: Op, rv: TensorVariable): """Return default transform for a given Distribution `Op`.""" @@ -100,9 +83,7 @@ class Ordered(Transform): name = "ordered" - def __init__(self, ndim_supp=None, positive=False, ascending=True): - if ndim_supp is not None: - warnings.warn("ndim_supp argument is deprecated and has no effect", FutureWarning) + def __init__(self, positive=False, ascending=True): self.positive = positive self.ascending = ascending @@ -142,10 +123,6 @@ class SumTo1(Transform): name = "sumto1" - def __init__(self, ndim_supp=None): - if ndim_supp is not None: - warnings.warn("ndim_supp argument is deprecated and has no effect", FutureWarning) - def backward(self, value, *inputs): remaining = 1 - pt.sum(value[..., :], axis=-1, keepdims=True) return pt.concatenate([value[..., :], remaining], axis=-1) diff --git a/pymc/initial_point.py b/pymc/initial_point.py index c276a5c49..df9419c74 100644 --- a/pymc/initial_point.py +++ b/pymc/initial_point.py @@ -240,12 +240,6 @@ def make_initial_point_expression( strategy = default_strategy if isinstance(strategy, str): - if strategy == "moment": - strategy = "support_point" - warnings.warn( - "The 'moment' strategy is deprecated. Use 'support_point' instead.", - FutureWarning, - ) if strategy == "support_point": try: value = support_point(variable) diff --git a/pymc/logprob/abstract.py b/pymc/logprob/abstract.py index 5c7f28e66..564dfa1fa 100644 --- a/pymc/logprob/abstract.py +++ b/pymc/logprob/abstract.py @@ -35,7 +35,6 @@ # SOFTWARE. import abc -import warnings from collections.abc import Sequence from functools import singledispatch @@ -48,17 +47,6 @@ from pytensor.tensor.random.op import RandomVariable -def __getattr__(name): - if name == "MeasurableVariable": - warnings.warn( - f"{name} has been deprecated in favor of MeasurableOp. Importing will fail in a future release.", - FutureWarning, - ) - return MeasurableOp - - raise AttributeError(f"module {__name__} has no attribute {name}") - - @singledispatch def _logprob( op: Op, diff --git a/pymc/logprob/basic.py b/pymc/logprob/basic.py index 6fd4a5489..85d74aab3 100644 --- a/pymc/logprob/basic.py +++ b/pymc/logprob/basic.py @@ -98,23 +98,7 @@ def _warn_rvs_in_inferred_graph(graph: TensorVariable | Sequence[TensorVariable] ) -def _deprecate_warn_missing_rvs(warn_rvs, kwargs): - if "warn_missing_rvs" in kwargs: - warnings.warn( - "Argument `warn_missing_rvs` was renamed to `warn_rvs` and will be removed in a future release", - FutureWarning, - ) - if warn_rvs is None: - warn_rvs = kwargs.pop("warn_missing_rvs") - else: - raise ValueError("Can't set both warn_rvs and warn_missing_rvs") - else: - if warn_rvs is None: - warn_rvs = True - return warn_rvs, kwargs - - -def logp(rv: TensorVariable, value: TensorLike, warn_rvs=None, **kwargs) -> TensorVariable: +def logp(rv: TensorVariable, value: TensorLike, warn_rvs=True, **kwargs) -> TensorVariable: """Create a graph for the log-probability of a random variable. Parameters @@ -200,8 +184,6 @@ def normal_logp(value, mu, sigma): pm.CustomDist("x", mu, sigma, logp=normal_logp) """ - warn_rvs, kwargs = _deprecate_warn_missing_rvs(warn_rvs, kwargs) - value = pt.as_tensor_variable(value, dtype=rv.dtype) try: return _logprob_helper(rv, value, **kwargs) @@ -216,7 +198,7 @@ def normal_logp(value, mu, sigma): return expr -def logcdf(rv: TensorVariable, value: TensorLike, warn_rvs=None, **kwargs) -> TensorVariable: +def logcdf(rv: TensorVariable, value: TensorLike, warn_rvs=True, **kwargs) -> TensorVariable: """Create a graph for the log-CDF of a random variable. Parameters @@ -301,7 +283,6 @@ def normal_logcdf(value, mu, sigma): pm.CustomDist("x", mu, sigma, logcdf=normal_logcdf) """ - warn_rvs, kwargs = _deprecate_warn_missing_rvs(warn_rvs, kwargs) value = pt.as_tensor_variable(value, dtype=rv.dtype) try: return _logcdf_helper(rv, value, **kwargs) @@ -317,7 +298,7 @@ def normal_logcdf(value, mu, sigma): return expr -def icdf(rv: TensorVariable, value: TensorLike, warn_rvs=None, **kwargs) -> TensorVariable: +def icdf(rv: TensorVariable, value: TensorLike, warn_rvs=True, **kwargs) -> TensorVariable: """Create a graph for the inverse CDF of a random variable. Parameters @@ -384,7 +365,6 @@ def icdf(rv: TensorVariable, value: TensorLike, warn_rvs=None, **kwargs) -> Tens print(exp_rv_icdf_fn(value=0.9, mu=0.0)) # 3.60222448 """ - warn_rvs, kwargs = _deprecate_warn_missing_rvs(warn_rvs, kwargs) value = pt.as_tensor_variable(value, dtype="floatX") try: return _icdf_helper(rv, value, **kwargs) @@ -409,7 +389,7 @@ def icdf(rv: TensorVariable, value: TensorLike, warn_rvs=None, **kwargs) -> Tens def conditional_logp( rv_values: dict[TensorVariable, TensorVariable], - warn_rvs=None, + warn_rvs=True, ir_rewriter: GraphRewriter | None = None, extra_rewrites: GraphRewriter | NodeRewriter | None = None, **kwargs, @@ -474,8 +454,6 @@ def conditional_logp( from the respective `RandomVariable`. """ - warn_rvs, kwargs = _deprecate_warn_missing_rvs(warn_rvs, kwargs) - fgraph = construct_ir_fgraph(rv_values, ir_rewriter=ir_rewriter) if extra_rewrites is not None: @@ -614,21 +592,3 @@ def transformed_conditional_logp( raise ValueError(RVS_IN_JOINT_LOGP_GRAPH_MSG % rvs_in_logp_expressions) return logp_terms_list - - -def factorized_joint_logprob(*args, **kwargs): - warnings.warn( - "`factorized_joint_logprob` was renamed to `conditional_logp`. " - "The function will be removed in a future release", - FutureWarning, - ) - return conditional_logp(*args, **kwargs) - - -def joint_logp(*args, **kwargs): - warnings.warn( - "`joint_logp` was renamed to `transformed_conditional_logp`. " - "The function will be removed in a future release", - FutureWarning, - ) - return transformed_conditional_logp(*args, **kwargs) diff --git a/pymc/math.py b/pymc/math.py index 1845dd511..13655f534 100644 --- a/pymc/math.py +++ b/pymc/math.py @@ -181,6 +181,8 @@ "zeros_like", ] +from pymc.util import UNSET + def kronecker(*Ks): r"""Return the Kronecker product of arguments. @@ -279,16 +281,6 @@ def logdiffexp(a, b): return a + pt.log1mexp(b - a) -def logdiffexp_numpy(a, b): - """Return log(exp(a) - exp(b)).""" - warnings.warn( - "pymc.math.logdiffexp_numpy is being deprecated.", - FutureWarning, - stacklevel=2, - ) - return a + log1mexp_numpy(b - a, negative_input=True) - - invlogit = sigmoid @@ -302,7 +294,7 @@ def logit(p): return pt.log(p / (floatX(1) - p)) -def log1mexp(x, *, negative_input=False): +def log1mexp(x, *, negative_input=UNSET): r"""Return log(1 - exp(-x)). This function is numerically more stable than the naive approach. @@ -316,50 +308,20 @@ def log1mexp(x, *, negative_input=False): "Accurately computing `\log(1-\exp(- \mid a \mid))` Assessed by the Rmpfr package" """ - if not negative_input: - warnings.warn( - "pymc.math.log1mexp will expect a negative input in a future " - "version of PyMC.\n To suppress this warning set `negative_input=True`", - FutureWarning, - stacklevel=2, - ) - x = -x + if negative_input is not UNSET: + if not negative_input: + raise ValueError( + "log1mexp with negative_input=False is no longer supported. Negate the input yourself before calling the function." + ) + else: + warnings.warn( + "log1mexp with negative_input=True is now the default behavior. Specifying will fail in a future release of PyMC. Simply omit it", + FutureWarning, + ) return pt.log1mexp(x) -def log1mexp_numpy(x, *, negative_input=False): - """Return log(1 - exp(x)). - - This function is numerically more stable than the naive approach. - - For details, see - https://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf - """ - warnings.warn( - "pymc.math.log1mexp_numpy is being deprecated.", - FutureWarning, - stacklevel=2, - ) - x = np.asarray(x, dtype="float") - - if not negative_input: - warnings.warn( - "pymc.math.log1mexp_numpy will expect a negative input in a future " - "version of PyMC.\n To suppress this warning set `negative_input=True`", - FutureWarning, - stacklevel=2, - ) - x = -x - - out = np.empty_like(x) - mask = x < -0.6931471805599453 # log(1/2) - out[mask] = np.log1p(-np.exp(x[mask])) - mask = ~mask - out[mask] = np.log(-np.expm1(x[mask])) - return out - - def flatten_list(tensors): return pt.concatenate([var.ravel() for var in tensors]) diff --git a/pymc/model/core.py b/pymc/model/core.py index 469001e80..c88d4d4c6 100644 --- a/pymc/model/core.py +++ b/pymc/model/core.py @@ -68,7 +68,6 @@ UNSET, VarName, WithMemoization, - _add_future_warning_tag, _UnsetType, get_transformed_name, get_value_vars_from_user_vars, @@ -450,19 +449,12 @@ def __init__( coords=None, check_bounds=True, *, - coords_mutable=None, model: _UnsetType | None | Model = UNSET, ): self.name = self._validate_name(name) self.check_bounds = check_bounds self._parent = model if not isinstance(model, _UnsetType) else MODEL_MANAGER.parent_context - if coords_mutable is not None: - warnings.warn( - "All coords are now mutable by default. coords_mutable will be removed in a future release.", - FutureWarning, - ) - if self.parent is not None: self.named_vars = treedict(parent=self.parent.named_vars) self.named_vars_to_dims = treedict(parent=self.parent.named_vars_to_dims) @@ -492,9 +484,6 @@ def __init__( self._coords = {} self._dim_lengths = {} self.add_coords(coords) - if coords_mutable is not None: - for name, values in coords_mutable.items(): - self.add_coord(name, values, mutable=True) from pymc.printing import str_for_model @@ -921,7 +910,6 @@ def add_coord( self, name: str, values: Sequence | np.ndarray | None = None, - mutable: bool | None = None, *, length: int | Variable | None = None, ): @@ -935,19 +923,10 @@ def add_coord( values : optional, array_like Coordinate values or ``None`` (for auto-numbering). If ``None`` is passed, a ``length`` must be specified. - mutable : bool - Whether the created dimension should be resizable. - Default is False. length : optional, scalar A scalar of the dimensions length. Defaults to ``pytensor.tensor.constant(len(values))``. """ - if mutable is not None: - warnings.warn( - "Coords are now always mutable. Specifying `mutable` will raise an error in a future release", - FutureWarning, - ) - if name in {"draw", "chain", "__sample__"}: raise ValueError( "Dimensions can not be named `draw`, `chain` or `__sample__`, " @@ -1223,7 +1202,6 @@ def register_rv( """ name = self.name_for(name) rv_var.name = name - _add_future_warning_tag(rv_var) # Associate previously unknown dimension names with # the length of the corresponding RV dimension. @@ -1435,9 +1413,6 @@ def create_value_var( rv_var, *rv_var.owner.inputs ).tag.test_value - _add_future_warning_tag(value_var) - rv_var.tag.value_var = value_var - self.rvs_to_transforms[rv_var] = transform self.rvs_to_values[rv_var] = value_var self.values_to_rvs[value_var] = rv_var @@ -1701,23 +1676,6 @@ def profile( return f.profile - def update_start_vals(self, a: dict[str, np.ndarray], b: dict[str, np.ndarray]): - r"""Update point `a` with `b`, without overwriting existing keys. - - Values specified for transformed variables in `a` will be recomputed - conditional on the values of `b` and stored in `b`. - - Parameters - ---------- - a : dict - - b : dict - """ - raise FutureWarning( - "The `Model.update_start_vals` method was removed." - " To change initial values you may set the items of `Model.initial_values` directly." - ) - def eval_rv_shapes(self) -> dict[str, tuple[int, ...]]: """Evaluate shapes of untransformed AND transformed free variables. diff --git a/pymc/plots/__init__.py b/pymc/plots/__init__.py index 49068d536..f1c63ce58 100644 --- a/pymc/plots/__init__.py +++ b/pymc/plots/__init__.py @@ -19,9 +19,7 @@ See https://arviz-devs.github.io/arviz/ for details on plots. """ -import functools import sys -import warnings import arviz as az @@ -32,39 +30,4 @@ setattr(sys.modules[__name__], attr, obj) -def alias_deprecation(func, alias: str): - original = func.__name__ - - @functools.wraps(func) - def wrapped(*args, **kwargs): - raise FutureWarning( - f"The function `{alias}` from PyMC was an alias for `{original}` from ArviZ. " - "It was removed in PyMC 4.0. " - f"Switch to `pymc.{original}` or `arviz.{original}`." - ) - - return wrapped - - -# Aliases of ArviZ functions -autocorrplot = alias_deprecation(az.plot_autocorr, alias="autocorrplot") -forestplot = alias_deprecation(az.plot_forest, alias="forestplot") -kdeplot = alias_deprecation(az.plot_kde, alias="kdeplot") -energyplot = alias_deprecation(az.plot_energy, alias="energyplot") -densityplot = alias_deprecation(az.plot_density, alias="densityplot") -pairplot = alias_deprecation(az.plot_pair, alias="pairplot") -traceplot = alias_deprecation(az.plot_trace, alias="traceplot") -compareplot = alias_deprecation(az.plot_compare, alias="compareplot") - - -__all__ = ( - *az.plots.__all__, - "autocorrplot", - "compareplot", - "forestplot", - "kdeplot", - "traceplot", - "energyplot", - "densityplot", - "pairplot", -) +__all__ = az.plots.__all__ diff --git a/pymc/pytensorf.py b/pymc/pytensorf.py index 78eb3f7bb..9608966a1 100644 --- a/pymc/pytensorf.py +++ b/pymc/pytensorf.py @@ -13,7 +13,7 @@ # limitations under the License. import warnings -from collections.abc import Callable, Generator, Iterable, Sequence +from collections.abc import Iterable, Sequence from typing import cast import numpy as np @@ -33,7 +33,6 @@ clone_get_equiv, equal_computations, graph_inputs, - walk, ) from pytensor.graph.fg import FunctionGraph, Output from pytensor.scalar.basic import Cast @@ -55,11 +54,9 @@ PotentialShapeType = int | np.ndarray | Sequence[int | Variable] | TensorVariable - __all__ = [ "CallableTensor", "compile", - "compile_pymc", "cont_inputs", "convert_data", "convert_observed_data", @@ -173,38 +170,6 @@ def extract_obs_data(x: TensorVariable) -> np.ndarray: raise TypeError(f"Data cannot be extracted from {x}") -def walk_model( - graphs: Iterable[TensorVariable], - stop_at_vars: set[TensorVariable] | None = None, - expand_fn: Callable[[TensorVariable], Iterable[TensorVariable]] = lambda var: [], -) -> Generator[TensorVariable, None, None]: - """Walk model graphs and yield their nodes. - - Parameters - ---------- - graphs - The graphs to walk. - stop_at_vars - A list of variables at which the walk will terminate. - expand_fn - A function that returns the next variable(s) to be traversed. - """ - warnings.warn("walk_model will be removed in a future relase of PyMC", FutureWarning) - - if stop_at_vars is None: - stop_at_vars = set() - - def expand(var): - new_vars = expand_fn(var) - - if var.owner and var not in stop_at_vars: - new_vars.extend(reversed(var.owner.inputs)) - - return new_vars - - yield from walk(graphs, expand, bfs=False) - - def replace_vars_in_graphs( graphs: Iterable[Variable], replacements: dict[Variable, Variable], @@ -954,14 +919,6 @@ def compile( return pytensor_function -def compile_pymc(*args, **kwargs): - warnings.warn( - "compile_pymc was renamed to compile. Old name will be removed in a future release of PyMC", - FutureWarning, - ) - return compile(*args, **kwargs) - - def constant_fold( xs: Sequence[TensorVariable], raise_not_constant: bool = True ) -> tuple[np.ndarray | Variable, ...]: diff --git a/pymc/sampling/mcmc.py b/pymc/sampling/mcmc.py index f2dfa6e9c..76695d760 100644 --- a/pymc/sampling/mcmc.py +++ b/pymc/sampling/mcmc.py @@ -755,11 +755,9 @@ def joined_blas_limiter(): ) if random_seed == -1: - warnings.warn( - "Setting random_seed = -1 is deprecated. Pass `None` to not specify a seed.", - FutureWarning, + raise ValueError( + "Setting random_seed = -1 is not allowed. Pass `None` to not specify a seed." ) - random_seed = None elif isinstance(random_seed, tuple | list): warnings.warn( "A list or tuple of random_seed no longer specifies the specific random_seed of each chain. " diff --git a/pymc/testing.py b/pymc/testing.py index a5fdc2832..b016c25ad 100644 --- a/pymc/testing.py +++ b/pymc/testing.py @@ -13,7 +13,6 @@ # limitations under the License. import functools as ft import itertools as it -import warnings from collections.abc import Callable, Sequence from typing import Any @@ -665,14 +664,6 @@ def check_selfconsistency_discrete_logcdf( ) -def assert_moment_is_expected(model, expected, check_finite_logp=True): - warnings.warn( - "assert_moment_is_expected is deprecated. Use assert_support_point_is_expected instead.", - FutureWarning, - ) - assert_support_point_is_expected(model, expected, check_finite_logp=check_finite_logp) - - def assert_support_point_is_expected(model, expected, check_finite_logp=True): fn = make_initial_point_fn( model=model, diff --git a/pymc/util.py b/pymc/util.py index 224ce0fa9..ad9256add 100644 --- a/pymc/util.py +++ b/pymc/util.py @@ -14,7 +14,6 @@ import functools import re -import warnings from collections import namedtuple from collections.abc import Iterable, Sequence @@ -29,7 +28,6 @@ from cachetools import LRUCache, cachedmethod from pytensor import Variable from pytensor.compile import SharedVariable -from pytensor.graph.utils import ValidatingScratchpad from rich.box import SIMPLE_HEAD from rich.console import Console from rich.progress import ( @@ -60,19 +58,6 @@ ] -def __getattr__(name): - if name == "dataset_to_point_list": - warnings.warn( - f"{name} has been moved to backends.arviz. Importing from util will fail in a future release.", - FutureWarning, - ) - from pymc.backends.arviz import dataset_to_point_list - - return dataset_to_point_list - - raise AttributeError(f"module {__name__} has no attribute {name}") - - VarName = NewType("VarName", str) default_progress_theme = Theme( @@ -540,34 +525,6 @@ def get_value_vars_from_user_vars(vars: Variable | Sequence[Variable], model) -> return value_vars -class _FutureWarningValidatingScratchpad(ValidatingScratchpad): - def __getattribute__(self, name): - for deprecated_names, alternative in ( - (("value_var", "observations"), "model.rvs_to_values[rv]"), - (("transform",), "model.rvs_to_transforms[rv]"), - ): - if name in deprecated_names: - try: - super().__getattribute__(name) - except AttributeError: - pass - else: - warnings.warn( - f"The tag attribute {name} is deprecated. Use {alternative} instead", - FutureWarning, - ) - return super().__getattribute__(name) - - -def _add_future_warning_tag(var) -> None: - old_tag = var.tag - if not isinstance(old_tag, _FutureWarningValidatingScratchpad): - new_tag = _FutureWarningValidatingScratchpad("test_value", var.type.filter) - for k, v in old_tag.__dict__.items(): - new_tag.__dict__.setdefault(k, v) - var.tag = new_tag - - def makeiter(a): if isinstance(a, tuple | list): return a diff --git a/tests/distributions/test_custom.py b/tests/distributions/test_custom.py index dba68c26e..7e05b2d02 100644 --- a/tests/distributions/test_custom.py +++ b/tests/distributions/test_custom.py @@ -196,15 +196,6 @@ def test_custom_dist_default_support_point_univariate(self, support_point, size, assert isinstance(x.owner.op, CustomDistRV) assert_support_point_is_expected(model, expected, check_finite_logp=False) - def test_custom_dist_moment_future_warning(self): - moment = lambda rv, size, *rv_inputs: 5 * pt.ones(size, dtype=rv.dtype) # noqa: E731 - with Model() as model: - with pytest.warns( - FutureWarning, match="`moment` argument is deprecated. Use `support_point` instead." - ): - x = CustomDist("x", moment=moment, size=()) - assert_support_point_is_expected(model, 5, check_finite_logp=False) - @pytest.mark.parametrize("size", [(), (2,), (3, 2)], ids=str) def test_custom_dist_custom_support_point_univariate(self, size): def density_support_point(rv, size, mu): diff --git a/tests/distributions/test_dist_math.py b/tests/distributions/test_dist_math.py index 39b9cfdd0..ff213954a 100644 --- a/tests/distributions/test_dist_math.py +++ b/tests/distributions/test_dist_math.py @@ -30,7 +30,6 @@ clipped_beta_rvs, factln, i0e, - incomplete_beta, multigammaln, ) from pymc.logprob.utils import ParameterValueError @@ -176,9 +175,3 @@ def ref_multigammaln(a, b): for x in xvals: if np.all(x > 0.5 * (p - 1)): check_vals(multigammaln_, ref_multigammaln, x, p) - - -def test_incomplete_beta_deprecation(): - with pytest.warns(FutureWarning, match="incomplete_beta has been deprecated"): - res = incomplete_beta(3, 5, 0.5).eval() - assert np.isclose(res, pt.betainc(3, 5, 0.5).eval()) diff --git a/tests/distributions/test_distribution.py b/tests/distributions/test_distribution.py index 405946544..f84fb8f86 100644 --- a/tests/distributions/test_distribution.py +++ b/tests/distributions/test_distribution.py @@ -52,7 +52,6 @@ check_logcdf, check_logp, ) -from pymc.util import _FutureWarningValidatingScratchpad class TestBugfixes: @@ -239,43 +238,6 @@ def rv_op(cls, size=None, rng=None): assert resized_rv.type.shape == (5,) -def test_tag_future_warning_dist(): - # Test no unexpected warnings - with warnings.catch_warnings(): - warnings.simplefilter("error") - - x = pm.Normal.dist() - assert isinstance(x.tag, _FutureWarningValidatingScratchpad) - - x.tag.banana = "banana" - assert x.tag.banana == "banana" - - # Check we didn't break test_value filtering - x.tag.test_value = np.array(1) - assert x.tag.test_value == 1 - with pytest.raises(TypeError, match="Wrong number of dimensions"): - x.tag.test_value = np.array([1, 1]) - assert x.tag.test_value == 1 - - # No warning if deprecated attribute is not present - with pytest.raises(AttributeError): - x.tag.value_var - - # Warning if present - x.tag.value_var = "1" - with pytest.warns(FutureWarning, match="Use model.rvs_to_values"): - value_var = x.tag.value_var - assert value_var == "1" - - # Check that PyMC method that copies tag contents does not erase special tag - new_x = change_dist_size(x, new_size=5) - assert new_x.tag is not x.tag - assert isinstance(new_x.tag, _FutureWarningValidatingScratchpad) - with pytest.warns(FutureWarning, match="Use model.rvs_to_values"): - value_var = new_x.tag.value_var - assert value_var == "1" - - def test_distribution_op_registered(): """Test that returned Ops are registered as virtual subclasses of the respective PyMC distributions.""" assert isinstance(Normal.dist().owner.op, Normal) diff --git a/tests/distributions/test_timeseries.py b/tests/distributions/test_timeseries.py index 197296a5a..e9d3e7615 100644 --- a/tests/distributions/test_timeseries.py +++ b/tests/distributions/test_timeseries.py @@ -461,26 +461,6 @@ def test_mvstudentt(self, param): assert isinstance(init_dist.owner.op, Dirichlet) assert isinstance(innovation_dist.owner.op, MvStudentT) - @pytest.mark.parametrize( - "distribution, init_dist, build_kwargs", - [ - (GaussianRandomWalk, Normal.dist(), {}), - ( - MvGaussianRandomWalk, - Dirichlet.dist(np.ones(3)), - {"mu": np.zeros(3), "tau": np.eye(3)}, - ), - ( - MvStudentTRandomWalk, - Dirichlet.dist(np.ones(3)), - {"nu": 4, "mu": np.zeros(3), "tau": np.eye(3)}, - ), - ], - ) - def test_init_deprecated_arg(self, distribution, init_dist, build_kwargs): - with pytest.warns(FutureWarning, match="init parameter is now called init_dist"): - distribution.dist(init=init_dist, steps=10, **build_kwargs) - class TestAR: def test_order1_logp(self): @@ -713,10 +693,6 @@ def test_support_point(self, size, expected): AR("x", rho=[0, 0], init_dist=init_dist, steps=5, size=size) assert_support_point_is_expected(model, expected, check_finite_logp=False) - def test_init_deprecated_arg(self): - with pytest.warns(FutureWarning, match="init parameter is now called init_dist"): - AR.dist(rho=[1, 2, 3], init=Normal.dist(), shape=(10,)) - def test_change_dist_size(self): base_dist = AR.dist(rho=[0.5, 0.5], init_dist=pm.Normal.dist(size=(2,)), shape=(3, 10)) diff --git a/tests/distributions/test_transform.py b/tests/distributions/test_transform.py index e28052bab..26bc8b1bf 100644 --- a/tests/distributions/test_transform.py +++ b/tests/distributions/test_transform.py @@ -151,9 +151,6 @@ def test_sum_to_1(): check_vector_transform(tr.sum_to_1, Simplex(2)) check_vector_transform(tr.sum_to_1, Simplex(4)) - with pytest.warns(FutureWarning, match="ndim_supp argument is deprecated"): - tr.SumTo1(2) - check_jacobian_det( tr.sum_to_1, Vector(Unit, 2), @@ -161,13 +158,6 @@ def test_sum_to_1(): floatX(np.array([0, 0])), lambda x: x[:-1], ) - check_jacobian_det( - tr.multivariate_sum_to_1, - Vector(Unit, 2), - pt.vector, - floatX(np.array([0, 0])), - lambda x: x[:-1], - ) def test_log(): @@ -271,9 +261,6 @@ def test_circular(): def test_ordered(): check_vector_transform(tr.ordered, SortedVector(6)) - with pytest.warns(FutureWarning, match="ndim_supp argument is deprecated"): - tr.Ordered(1) - check_jacobian_det( tr.ordered, Vector(R, 2), pt.vector, floatX(np.array([0, 0])), elemwise=False ) @@ -678,23 +665,3 @@ def log_jac_det(self, value, *inputs): match="are not allowed to broadcast together. There is a bug in the implementation of either one", ): m.logp(jacobian=jacobian_val) - - -def test_deprecated_ndim_supp_transforms(): - with pytest.warns(FutureWarning, match="deprecated"): - tr.Ordered(ndim_supp=1) - - with pytest.warns(FutureWarning, match="deprecated"): - assert tr.univariate_ordered == tr.ordered - - with pytest.warns(FutureWarning, match="deprecated"): - assert tr.multivariate_ordered == tr.ordered - - with pytest.warns(FutureWarning, match="deprecated"): - tr.SumTo1(ndim_supp=1) - - with pytest.warns(FutureWarning, match="deprecated"): - assert tr.univariate_sum_to_1 == tr.sum_to_1 - - with pytest.warns(FutureWarning, match="deprecated"): - assert tr.multivariate_sum_to_1 == tr.sum_to_1 diff --git a/tests/logprob/test_basic.py b/tests/logprob/test_basic.py index f6014d78a..1bd103ce1 100644 --- a/tests/logprob/test_basic.py +++ b/tests/logprob/test_basic.py @@ -201,7 +201,7 @@ def test_persist_inputs(): assert y_vv_2 in ancestors([logp_2_combined]) -def test_warn_random_found_factorized_joint_logprob(): +def test_warn_rvs_conditional_logp(): x_rv = pt.random.normal(name="x") y_rv = pt.random.normal(x_rv, 1, name="y") @@ -369,7 +369,7 @@ def test_probability_inference_fails(func, func_name): (icdf, "ppf", 0.7), ], ) -def test_warn_random_found_probability_inference(func, scipy_func, test_value): +def test_warn_rvs_probability_derivation(func, scipy_func, test_value): # Fail if unexpected warning is issued with warnings.catch_warnings(): warnings.simplefilter("error") diff --git a/tests/model/test_core.py b/tests/model/test_core.py index b26a9d96b..a12046c31 100644 --- a/tests/model/test_core.py +++ b/tests/model/test_core.py @@ -56,7 +56,6 @@ from pymc.logprob.basic import transformed_conditional_logp from pymc.logprob.transforms import IntervalTransform from pymc.model import Point, ValueGradFunction, modelcontext -from pymc.util import _FutureWarningValidatingScratchpad from pymc.variational.minibatch_rv import MinibatchRandomVariable from tests.models import simple_model @@ -1648,55 +1647,6 @@ def test_deterministic(self): ) -def test_tag_future_warning_model(): - # Test no unexpected warnings - with warnings.catch_warnings(): - warnings.simplefilter("error") - - model = pm.Model() - - x = pt.random.normal() - x.tag.something_else = "5" - x.tag.test_value = 0 - assert not isinstance(x.tag, _FutureWarningValidatingScratchpad) - - # Test that model changes the tag type, but copies existing contents - x = model.register_rv(x, name="x", transform=log) - assert isinstance(x.tag, _FutureWarningValidatingScratchpad) - assert x.tag.something_else == "5" - assert x.tag.test_value == 0 - - # Test expected warnings - with pytest.warns(FutureWarning, match="model.rvs_to_values"): - x_value = x.tag.value_var - - assert isinstance(x_value.tag, _FutureWarningValidatingScratchpad) - with pytest.warns(FutureWarning, match="model.rvs_to_transforms"): - transform = x_value.tag.transform - assert transform is log - - with pytest.raises(AttributeError): - x.tag.observations - - # Cloning a node will keep the same tag type and contents - y = x.owner.clone().default_output() - assert y is not x - assert y.tag is not x.tag - assert isinstance(y.tag, _FutureWarningValidatingScratchpad) - y = model.register_rv(y, name="y", observed=5) - assert isinstance(y.tag, _FutureWarningValidatingScratchpad) - - # Test expected warnings - with pytest.warns(FutureWarning, match="model.rvs_to_values"): - y_value = y.tag.value_var - with pytest.warns(FutureWarning, match="model.rvs_to_values"): - y_obs = y.tag.observations - assert y_value is y_obs - assert y_value.eval() == 5 - - assert isinstance(y_value.tag, _FutureWarningValidatingScratchpad) - - class TestModelDebug: @pytest.mark.parametrize("fn", ("logp", "dlogp", "random")) def test_no_problems(self, fn, capfd): diff --git a/tests/model/test_fgraph.py b/tests/model/test_fgraph.py index 178eb3968..a3f04e3ce 100644 --- a/tests/model/test_fgraph.py +++ b/tests/model/test_fgraph.py @@ -108,7 +108,7 @@ def test_data(inline_views): with pm.Model(coords={"test_dim": range(3)}) as m_old: x = pm.Data("x", [0.0, 1.0, 2.0], dims=("test_dim",)) y = pm.Data("y", [10.0, 11.0, 12.0], dims=("test_dim",)) - sigma = pm.MutableData("sigma", [1.0], shape=(1,)) + sigma = pm.Data("sigma", [1.0], shape=(1,)) b0 = pm.Data("b0", np.zeros((1,)), shape=((1,))) b1 = pm.Normal("b1", 1.0, sigma=1e-8) mu = pm.Deterministic("mu", b0 + b1 * x, dims=("test_dim",)) diff --git a/tests/model/transform/test_conditioning.py b/tests/model/transform/test_conditioning.py index 828fac737..fa9ce7124 100644 --- a/tests/model/transform/test_conditioning.py +++ b/tests/model/transform/test_conditioning.py @@ -29,6 +29,7 @@ observe, remove_value_transforms, ) +from pymc.model.transform.optimization import freeze_dims_and_data from pymc.variational.minibatch_rv import create_minibatch_rv @@ -176,10 +177,13 @@ def test_do_posterior_predictive(): def test_do_constant(mutable): rng = np.random.default_rng(seed=122) with pm.Model() as m: - x = pm.Data("x", 0, mutable=mutable) + x = pm.Data("x", 0) y = pm.Normal("y", x, 1e-3) - do_m = do(m, {x: 105}) + if not mutable: + m = freeze_dims_and_data(m, data=["x"]) + + do_m = do(m, {m["x"]: 105}) assert pm.draw(do_m["y"], random_seed=rng) > 100 diff --git a/tests/test_initial_point.py b/tests/test_initial_point.py index bda39bd1f..e13ed5279 100644 --- a/tests/test_initial_point.py +++ b/tests/test_initial_point.py @@ -294,15 +294,6 @@ class MyNormalDistribution(pm.Normal): assert np.isclose(res["x"], np.pi) - def test_future_warning_moment(self): - with pm.Model() as m: - pm.Normal("x", initval="moment") - with pytest.warns( - FutureWarning, - match="The 'moment' strategy is deprecated. Use 'support_point' instead.", - ): - ip = m.initial_point(random_seed=42) - def test_pickling_issue_5090(): with pm.Model() as model: diff --git a/tests/test_math.py b/tests/test_math.py index 3f811fc2b..eeee1f164 100644 --- a/tests/test_math.py +++ b/tests/test_math.py @@ -15,7 +15,6 @@ import warnings import numpy as np -import numpy.testing as npt import pytensor import pytensor.tensor as pt import pytest @@ -29,10 +28,8 @@ kron_solve_lower, kronecker, log1mexp, - log1mexp_numpy, logdet, logdiffexp, - logdiffexp_numpy, probit, ) from pymc.pytensorf import floatX @@ -126,70 +123,22 @@ def test_probit(): np.testing.assert_allclose(invprobit(probit(p)).eval(), p, atol=1e-5) -def test_log1mexp(): - vals = np.array([-1, 0, 1e-20, 1e-4, 10, 100, 1e20]) - vals_ = vals.copy() - # import mpmath - # mpmath.mp.dps = 1000 - # [float(mpmath.log(1 - mpmath.exp(-x))) for x in vals] - expected = np.array( - [ - np.nan, - -np.inf, - -46.051701859880914, - -9.210390371559516, - -4.540096037048921e-05, - -3.720075976020836e-44, - 0.0, - ] - ) - actual = pt.log1mexp(-vals).eval() - npt.assert_allclose(actual, expected) - - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "divide by zero encountered in log", RuntimeWarning) - warnings.filterwarnings("ignore", "invalid value encountered in log", RuntimeWarning) - with pytest.warns(FutureWarning, match="deprecated"): - actual_ = log1mexp_numpy(-vals, negative_input=True) - npt.assert_allclose(actual_, expected) - # Check that input was not changed in place - npt.assert_allclose(vals, vals_) - - -@pytest.mark.filterwarnings("error") -def test_log1mexp_numpy_no_warning(): - """Assert RuntimeWarning is not raised for very small numbers""" - with pytest.warns(FutureWarning, match="deprecated"): - log1mexp_numpy(-1e-25, negative_input=True) - - -def test_log1mexp_numpy_integer_input(): - with pytest.warns(FutureWarning, match="deprecated"): - assert np.isclose(log1mexp_numpy(-2, negative_input=True), pt.log1mexp(-2).eval()) - - @pytest.mark.filterwarnings("error") def test_log1mexp_deprecation_warnings(): - with pytest.warns(FutureWarning, match="deprecated"): - with pytest.warns( - FutureWarning, - match="pymc.math.log1mexp_numpy will expect a negative input", - ): - res_pos = log1mexp_numpy(2) - - res_neg = log1mexp_numpy(-2, negative_input=True) + with pytest.raises( + ValueError, + match="log1mexp with negative_input=False is no longer supported", + ): + log1mexp(2, negative_input=False).eval() - with pytest.warns( - FutureWarning, - match="pymc.math.log1mexp will expect a negative input", - ): - res_pos_at = log1mexp(2).eval() + with pytest.warns(FutureWarning): + res_1 = log1mexp(-2, negative_input=True).eval() - res_neg_at = log1mexp(-2, negative_input=True).eval() + res_2 = log1mexp(-2).eval() + res_ref = pt.log1mexp(-2).eval() - assert np.isclose(res_pos, res_neg) - assert np.isclose(res_pos_at, res_neg) - assert np.isclose(res_neg_at, res_neg) + assert np.isclose(res_ref, res_1) + assert np.isclose(res_ref, res_2) def test_logdiffexp(): @@ -197,8 +146,6 @@ def test_logdiffexp(): with warnings.catch_warnings(): warnings.filterwarnings("ignore", "divide by zero encountered in log", RuntimeWarning) b = np.log([0, 1, 2, 3]) - with pytest.warns(FutureWarning, match="deprecated"): - assert np.allclose(logdiffexp_numpy(a, b), 0) assert np.allclose(logdiffexp(a, b).eval(), 0) diff --git a/tests/test_pytensorf.py b/tests/test_pytensorf.py index 34360397a..580c29344 100644 --- a/tests/test_pytensorf.py +++ b/tests/test_pytensorf.py @@ -25,7 +25,6 @@ from pytensor.compile import UnusedInputError from pytensor.compile.builders import OpFromGraph from pytensor.graph.basic import Variable, equal_computations -from pytensor.tensor.random.basic import normal, uniform from pytensor.tensor.subtensor import AdvancedIncSubtensor import pymc as pm @@ -46,7 +45,6 @@ replace_rng_nodes, replace_vars_in_graphs, reseed_rngs, - walk_model, ) from pymc.vartypes import int_types @@ -283,42 +281,7 @@ def test_pandas_to_array_pandas_index(): np.testing.assert_array_equal(result, expected) -def test_walk_model(): - a = pt.vector("a") - b = uniform(0.0, a, name="b") - c = pt.log(b) - c.name = "c" - d = pt.vector("d") - e = normal(c, d, name="e") - - test_graph = pt.exp(e + 1) - - with pytest.warns(FutureWarning): - res = list(walk_model((test_graph,))) - assert a in res - assert b in res - assert c in res - assert d in res - assert e in res - - with pytest.warns(FutureWarning): - res = list(walk_model((test_graph,), stop_at_vars={c})) - assert a not in res - assert b not in res - assert c in res - assert d in res - assert e in res - - with pytest.warns(FutureWarning): - res = list(walk_model((test_graph,), stop_at_vars={b})) - assert a not in res - assert b in res - assert c in res - assert d in res - assert e in res - - -class TestCompilePyMC: +class TestCompile: def test_check_bounds_flag(self): """Test that CheckParameterValue Ops are replaced or removed when using compile_pymc""" logp = pt.ones(3)