From 6f74249a4c622682c639534235fe1d633454ff26 Mon Sep 17 00:00:00 2001 From: byd Date: Mon, 9 Jun 2025 17:39:43 -0400 Subject: [PATCH 1/3] Replace np.float_ with np.float64 for NumPy compatibility --- src/probnum/randprocs/_gaussian_process.py | 2 +- src/probnum/randprocs/markov/_markov.py | 2 +- src/probnum/randvars/_constant.py | 6 +- src/probnum/randvars/_normal.py | 24 ++++---- src/probnum/randvars/_random_variable.py | 68 +++++++++++----------- src/probnum/randvars/_scipy_stats.py | 18 +++--- 6 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/probnum/randprocs/_gaussian_process.py b/src/probnum/randprocs/_gaussian_process.py index aea560d4f..07caa3c8e 100644 --- a/src/probnum/randprocs/_gaussian_process.py +++ b/src/probnum/randprocs/_gaussian_process.py @@ -67,7 +67,7 @@ def __init__( super().__init__( input_shape=mean.input_shape, output_shape=mean.output_shape, - dtype=np.dtype(np.float_), + dtype=np.dtype(np.float64), mean=mean, cov=cov, ) diff --git a/src/probnum/randprocs/markov/_markov.py b/src/probnum/randprocs/markov/_markov.py index 7939edd3f..a98cdb67e 100644 --- a/src/probnum/randprocs/markov/_markov.py +++ b/src/probnum/randprocs/markov/_markov.py @@ -30,7 +30,7 @@ def __init__( super().__init__( input_shape=input_shape, output_shape=output_shape, - dtype=np.dtype(np.float_), + dtype=np.dtype(np.float64), mean=functions.LambdaFunction( lambda x: self.__call__(args=x).mean, input_shape=input_shape, diff --git a/src/probnum/randvars/_constant.py b/src/probnum/randvars/_constant.py index c831417d2..5deee4d6d 100644 --- a/src/probnum/randvars/_constant.py +++ b/src/probnum/randvars/_constant.py @@ -65,7 +65,7 @@ def __init__( self._support = support support_floating = self._support.astype( - np.promote_types(self._support.dtype, np.float_) + np.promote_types(self._support.dtype, np.float64) ) if config.matrix_free: @@ -95,8 +95,8 @@ def __init__( parameters={"support": self._support}, sample=self._sample, in_support=lambda x: np.all(x == self._support), - pmf=lambda x: np.float_(1.0 if np.all(x == self._support) else 0.0), - cdf=lambda x: np.float_(1.0 if np.all(x >= self._support) else 0.0), + pmf=lambda x: np.float64(1.0 if np.all(x == self._support) else 0.0), + cdf=lambda x: np.float64(1.0 if np.all(x >= self._support) else 0.0), mode=lambda: self._support, median=lambda: support_floating, mean=lambda: support_floating, diff --git a/src/probnum/randvars/_normal.py b/src/probnum/randvars/_normal.py index cdc428a57..4f0ef12c7 100644 --- a/src/probnum/randvars/_normal.py +++ b/src/probnum/randvars/_normal.py @@ -432,25 +432,25 @@ def _univariate_sample( def _univariate_in_support(x: ValueType) -> bool: return np.isfinite(x) - def _univariate_pdf(self, x: ValueType) -> np.float_: + def _univariate_pdf(self, x: ValueType) -> np.float64: return scipy.stats.norm.pdf(x, loc=self.mean, scale=self.std) - def _univariate_logpdf(self, x: ValueType) -> np.float_: + def _univariate_logpdf(self, x: ValueType) -> np.float64: return scipy.stats.norm.logpdf(x, loc=self.mean, scale=self.std) - def _univariate_cdf(self, x: ValueType) -> np.float_: + def _univariate_cdf(self, x: ValueType) -> np.float64: return scipy.stats.norm.cdf(x, loc=self.mean, scale=self.std) - def _univariate_logcdf(self, x: ValueType) -> np.float_: + def _univariate_logcdf(self, x: ValueType) -> np.float64: return scipy.stats.norm.logcdf(x, loc=self.mean, scale=self.std) def _univariate_quantile(self, p: FloatLike) -> np.floating: return scipy.stats.norm.ppf(p, loc=self.mean, scale=self.std) - def _univariate_entropy(self: ValueType) -> np.float_: + def _univariate_entropy(self: ValueType) -> np.float64: return _utils.as_numpy_scalar( scipy.stats.norm.entropy(loc=self.mean, scale=self.std), - dtype=np.float_, + dtype=np.float64, ) # Multi- and matrixvariate Gaussians @@ -500,28 +500,28 @@ def _arg_todense(x: Union[np.ndarray, linops.LinearOperator]) -> np.ndarray: def _dense_in_support(x: ValueType) -> bool: return np.all(np.isfinite(Normal._arg_todense(x))) - def _dense_pdf(self, x: ValueType) -> np.float_: + def _dense_pdf(self, x: ValueType) -> np.float64: return scipy.stats.multivariate_normal.pdf( Normal._arg_todense(x).reshape(x.shape[: -self.ndim] + (-1,)), mean=self.dense_mean.ravel(), cov=self.dense_cov, ) - def _dense_logpdf(self, x: ValueType) -> np.float_: + def _dense_logpdf(self, x: ValueType) -> np.float64: return scipy.stats.multivariate_normal.logpdf( Normal._arg_todense(x).reshape(x.shape[: -self.ndim] + (-1,)), mean=self.dense_mean.ravel(), cov=self.dense_cov, ) - def _dense_cdf(self, x: ValueType) -> np.float_: + def _dense_cdf(self, x: ValueType) -> np.float64: return scipy.stats.multivariate_normal.cdf( Normal._arg_todense(x).reshape(x.shape[: -self.ndim] + (-1,)), mean=self.dense_mean.ravel(), cov=self.dense_cov, ) - def _dense_logcdf(self, x: ValueType) -> np.float_: + def _dense_logcdf(self, x: ValueType) -> np.float64: return scipy.stats.multivariate_normal.logcdf( Normal._arg_todense(x).reshape(x.shape[: -self.ndim] + (-1,)), mean=self.dense_mean.ravel(), @@ -531,13 +531,13 @@ def _dense_logcdf(self, x: ValueType) -> np.float_: def _dense_var(self) -> np.ndarray: return np.diag(self.dense_cov).reshape(self.shape) - def _dense_entropy(self) -> np.float_: + def _dense_entropy(self) -> np.float64: return _utils.as_numpy_scalar( scipy.stats.multivariate_normal.entropy( mean=self.dense_mean.ravel(), cov=self.dense_cov, ), - dtype=np.float_, + dtype=np.float64, ) # Matrixvariate Gaussian with Kronecker covariance diff --git a/src/probnum/randvars/_random_variable.py b/src/probnum/randvars/_random_variable.py index 6f6180e55..8c0937c01 100644 --- a/src/probnum/randvars/_random_variable.py +++ b/src/probnum/randvars/_random_variable.py @@ -110,8 +110,8 @@ def __init__( parameters: Optional[Dict[str, Any]] = None, sample: Optional[Callable[[np.random.Generator, ShapeType], ValueType]] = None, in_support: Optional[Callable[[ValueType], bool]] = None, - cdf: Optional[Callable[[ValueType], np.float_]] = None, - logcdf: Optional[Callable[[ValueType], np.float_]] = None, + cdf: Optional[Callable[[ValueType], np.float64]] = None, + logcdf: Optional[Callable[[ValueType], np.float64]] = None, quantile: Optional[Callable[[FloatLike], ValueType]] = None, mode: Optional[Callable[[], ValueType]] = None, median: Optional[Callable[[], ValueType]] = None, @@ -119,7 +119,7 @@ def __init__( cov: Optional[Callable[[], ValueType]] = None, var: Optional[Callable[[], ValueType]] = None, std: Optional[Callable[[], ValueType]] = None, - entropy: Optional[Callable[[], np.float_]] = None, + entropy: Optional[Callable[[], np.float64]] = None, as_value_type: Optional[Callable[[Any], ValueType]] = None, ): # pylint: disable=too-many-arguments,too-many-locals @@ -370,7 +370,7 @@ def std(self) -> ValueType: return std @cached_property - def entropy(self) -> np.float_: + def entropy(self) -> np.float64: """Information-theoretic entropy :math:`H(X)` of the random variable.""" if self.__entropy is None: raise NotImplementedError @@ -424,7 +424,7 @@ def sample(self, rng: np.random.Generator, size: ShapeLike = ()) -> ValueType: return self.__sample(rng=rng, size=_utils.as_shape(size)) - def cdf(self, x: ValueType) -> np.float_: + def cdf(self, x: ValueType) -> np.float64: """Cumulative distribution function. Parameters @@ -442,7 +442,7 @@ def cdf(self, x: ValueType) -> np.float_: if self.__logcdf is not None: cdf = np.exp(self.logcdf(self._as_value_type(x))) - assert isinstance(cdf, np.float_) + assert isinstance(cdf, np.float64) return cdf raise NotImplementedError( @@ -450,7 +450,7 @@ def cdf(self, x: ValueType) -> np.float_: f"with type `{type(self).__name__}` is implemented." ) - def logcdf(self, x: ValueType) -> np.float_: + def logcdf(self, x: ValueType) -> np.float64: """Log-cumulative distribution function. Parameters @@ -468,7 +468,7 @@ def logcdf(self, x: ValueType) -> np.float_: if self.__cdf is not None: logcdf = np.log(self.__cdf(x)) - assert isinstance(logcdf, np.float_) + assert isinstance(logcdf, np.float64) return logcdf raise NotImplementedError( @@ -779,7 +779,7 @@ def infer_moment_dtype(value_dtype: DTypeLike) -> np.dtype: value_dtype : Dtype of a value. """ - return np.promote_types(value_dtype, np.float_) + return np.promote_types(value_dtype, np.float64) def _as_value_type(self, x: Any) -> ValueType: if self.__as_value_type is not None: @@ -811,26 +811,26 @@ def _check_property_value( @classmethod def _ensure_numpy_float( cls, name: str, value: Any, force_scalar: bool = False - ) -> Union[np.float_, np.ndarray]: + ) -> Union[np.float64, np.ndarray]: if np.isscalar(value): - if not isinstance(value, np.float_): + if not isinstance(value, np.float64): try: - value = _utils.as_numpy_scalar(value, dtype=np.float_) + value = _utils.as_numpy_scalar(value, dtype=np.float64) except TypeError as err: raise TypeError( f"The function `{name}` specified via the constructor of " f"`{cls.__name__}` must return a scalar value that can be " - f"converted to a `np.float_`, which is not possible for " + f"converted to a `np.float64`, which is not possible for " f"{value} of type {type(value)}." ) from err elif not force_scalar: try: - value = np.asarray(value, dtype=np.float_) + value = np.asarray(value, dtype=np.float64) except TypeError as err: raise TypeError( f"The function `{name}` specified via the constructor of " f"`{cls.__name__}` must return a value that can be converted " - f"to a `np.ndarray` of type `np.float_`, which is not possible " + f"to a `np.ndarray` of type `np.float64`, which is not possible " f"for {value} of type {type(value)}." ) from err else: @@ -840,7 +840,7 @@ def _ensure_numpy_float( f"{type(value)} is not scalar." ) - assert isinstance(value, (np.float_, np.ndarray)) + assert isinstance(value, (np.float64, np.ndarray)) return value @@ -962,10 +962,10 @@ def __init__( parameters: Optional[Dict[str, Any]] = None, sample: Optional[Callable[[np.random.Generator, ShapeLike], ValueType]] = None, in_support: Optional[Callable[[ValueType], bool]] = None, - pmf: Optional[Callable[[ValueType], np.float_]] = None, - logpmf: Optional[Callable[[ValueType], np.float_]] = None, - cdf: Optional[Callable[[ValueType], np.float_]] = None, - logcdf: Optional[Callable[[ValueType], np.float_]] = None, + pmf: Optional[Callable[[ValueType], np.float64]] = None, + logpmf: Optional[Callable[[ValueType], np.float64]] = None, + cdf: Optional[Callable[[ValueType], np.float64]] = None, + logcdf: Optional[Callable[[ValueType], np.float64]] = None, quantile: Optional[Callable[[FloatLike], ValueType]] = None, mode: Optional[Callable[[], ValueType]] = None, median: Optional[Callable[[], ValueType]] = None, @@ -973,7 +973,7 @@ def __init__( cov: Optional[Callable[[], ValueType]] = None, var: Optional[Callable[[], ValueType]] = None, std: Optional[Callable[[], ValueType]] = None, - entropy: Optional[Callable[[], np.float_]] = None, + entropy: Optional[Callable[[], np.float64]] = None, as_value_type: Optional[Callable[[Any], ValueType]] = None, ): # Probability mass function @@ -999,7 +999,7 @@ def __init__( as_value_type=as_value_type, ) - def pmf(self, x: ValueType) -> np.float_: + def pmf(self, x: ValueType) -> np.float64: """Probability mass function. Computes the probability of the random variable being equal to the given @@ -1024,7 +1024,7 @@ def pmf(self, x: ValueType) -> np.float_: if self.__logpmf is not None: pmf = np.exp(self.__logpmf(x)) - assert isinstance(pmf, np.float_) + assert isinstance(pmf, np.float64) return pmf raise NotImplementedError( @@ -1032,7 +1032,7 @@ def pmf(self, x: ValueType) -> np.float_: f"object with type `{type(self).__name__}` is implemented." ) - def logpmf(self, x: ValueType) -> np.float_: + def logpmf(self, x: ValueType) -> np.float64: """Natural logarithm of the probability mass function. Parameters @@ -1050,7 +1050,7 @@ def logpmf(self, x: ValueType) -> np.float_: if self.__pmf is not None: logpmf = np.log(self.__pmf(self._as_value_type(x))) - assert isinstance(logpmf, np.float_) + assert isinstance(logpmf, np.float64) return logpmf raise NotImplementedError( @@ -1176,10 +1176,10 @@ def __init__( parameters: Optional[Dict[str, Any]] = None, sample: Optional[Callable[[np.random.Generator, ShapeLike], ValueType]] = None, in_support: Optional[Callable[[ValueType], bool]] = None, - pdf: Optional[Callable[[ValueType], np.float_]] = None, - logpdf: Optional[Callable[[ValueType], np.float_]] = None, - cdf: Optional[Callable[[ValueType], np.float_]] = None, - logcdf: Optional[Callable[[ValueType], np.float_]] = None, + pdf: Optional[Callable[[ValueType], np.float64]] = None, + logpdf: Optional[Callable[[ValueType], np.float64]] = None, + cdf: Optional[Callable[[ValueType], np.float64]] = None, + logcdf: Optional[Callable[[ValueType], np.float64]] = None, quantile: Optional[Callable[[FloatLike], ValueType]] = None, mode: Optional[Callable[[], ValueType]] = None, median: Optional[Callable[[], ValueType]] = None, @@ -1187,7 +1187,7 @@ def __init__( cov: Optional[Callable[[], ValueType]] = None, var: Optional[Callable[[], ValueType]] = None, std: Optional[Callable[[], ValueType]] = None, - entropy: Optional[Callable[[], np.float_]] = None, + entropy: Optional[Callable[[], np.float64]] = None, as_value_type: Optional[Callable[[Any], ValueType]] = None, ): # Probability density function @@ -1213,7 +1213,7 @@ def __init__( as_value_type=as_value_type, ) - def pdf(self, x: ValueType) -> np.float_: + def pdf(self, x: ValueType) -> np.float64: """Probability density function. The area under the curve defined by the probability density function @@ -1240,7 +1240,7 @@ def pdf(self, x: ValueType) -> np.float_: if self.__logpdf is not None: pdf = np.exp(self.__logpdf(self._as_value_type(x))) - assert isinstance(pdf, np.float_) + assert isinstance(pdf, np.float64) return pdf raise NotImplementedError( @@ -1248,7 +1248,7 @@ def pdf(self, x: ValueType) -> np.float_: f"object with type `{type(self).__name__}` is implemented." ) - def logpdf(self, x: ValueType) -> np.float_: + def logpdf(self, x: ValueType) -> np.float64: """Natural logarithm of the probability density function. Parameters @@ -1266,7 +1266,7 @@ def logpdf(self, x: ValueType) -> np.float_: if self.__pdf is not None: logpdf = np.log(self.__pdf(self._as_value_type(x))) - assert isinstance(logpdf, np.float_) + assert isinstance(logpdf, np.float64) return logpdf raise NotImplementedError( diff --git a/src/probnum/randvars/_scipy_stats.py b/src/probnum/randvars/_scipy_stats.py index a8ae6359d..36b8470b0 100644 --- a/src/probnum/randvars/_scipy_stats.py +++ b/src/probnum/randvars/_scipy_stats.py @@ -74,12 +74,12 @@ def __init__( rv_kwargs["pmf"] = _return_numpy( getattr(scipy_rv, "pmf", None), - dtype=np.float_, + dtype=np.float64, ) rv_kwargs["logpmf"] = _return_numpy( getattr(scipy_rv, "logpmf", None), - dtype=np.float_, + dtype=np.float64, ) super().__init__(**rv_kwargs) @@ -113,12 +113,12 @@ def __init__( rv_kwargs["pdf"] = _return_numpy( getattr(scipy_rv, "pdf", None), - dtype=np.float_, + dtype=np.float64, ) rv_kwargs["logpdf"] = _return_numpy( getattr(scipy_rv, "logpdf", None), - dtype=np.float_, + dtype=np.float64, ) super().__init__(**rv_kwargs) @@ -211,8 +211,8 @@ def _rv_init_kwargs_from_scipy_rv( shape = sample.shape dtype = sample.dtype - median_dtype = np.promote_types(dtype, np.float_) - moments_dtype = np.promote_types(dtype, np.float_) + median_dtype = np.promote_types(dtype, np.float64) + moments_dtype = np.promote_types(dtype, np.float64) # Support of univariate random variables if isinstance(scipy_rv, scipy.stats._distn_infrastructure.rv_frozen): @@ -238,8 +238,8 @@ def sample_from_scipy_rv(rng, size): "dtype": dtype, "sample": _return_numpy(sample_wrapper, dtype), "in_support": in_support, - "cdf": _return_numpy(getattr(scipy_rv, "cdf", None), np.float_), - "logcdf": _return_numpy(getattr(scipy_rv, "logcdf", None), np.float_), + "cdf": _return_numpy(getattr(scipy_rv, "cdf", None), np.float64), + "logcdf": _return_numpy(getattr(scipy_rv, "logcdf", None), np.float64), "quantile": _return_numpy(getattr(scipy_rv, "ppf", None), dtype), "mode": None, # not offered by scipy.stats "median": _return_numpy(getattr(scipy_rv, "median", None), median_dtype), @@ -247,7 +247,7 @@ def sample_from_scipy_rv(rng, size): "cov": _return_numpy(getattr(scipy_rv, "cov", None), moments_dtype), "var": _return_numpy(getattr(scipy_rv, "var", None), moments_dtype), "std": _return_numpy(getattr(scipy_rv, "std", None), moments_dtype), - "entropy": _return_numpy(getattr(scipy_rv, "entropy", None), np.float_), + "entropy": _return_numpy(getattr(scipy_rv, "entropy", None), np.float64), } From c53f6dda1a7c6c88047b8637378b5761176b6cc5 Mon Sep 17 00:00:00 2001 From: byd Date: Mon, 9 Jun 2025 18:19:50 -0400 Subject: [PATCH 2/3] Fix NumPy 2.0 compatibility: replace np.find_common_type with np.result_type - Replace deprecated np.find_common_type calls in SumLinearOperator and ProductLinearOperator - Use functools.reduce with np.result_type to achieve same functionality - Fixes AttributeError when using NumPy 2.0+ --- src/probnum/linops/_arithmetic_fallbacks.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/probnum/linops/_arithmetic_fallbacks.py b/src/probnum/linops/_arithmetic_fallbacks.py index 52f7c73ec..7564bcd72 100644 --- a/src/probnum/linops/_arithmetic_fallbacks.py +++ b/src/probnum/linops/_arithmetic_fallbacks.py @@ -97,9 +97,7 @@ def __init__(self, *summands: LinearOperator): super().__init__( shape=summands[0].shape, - dtype=np.find_common_type( - [summand.dtype for summand in self._summands], [] - ), + dtype=functools.reduce(np.result_type, [summand.dtype for summand in self._summands]), matmul=lambda x: functools.reduce( operator.add, (summand @ x for summand in self._summands) ), @@ -190,7 +188,7 @@ def __init__(self, *factors: LinearOperator): super().__init__( shape=(self._factors[0].shape[0], self._factors[-1].shape[1]), - dtype=np.find_common_type([factor.dtype for factor in self._factors], []), + dtype=functools.reduce(np.result_type, [factor.dtype for factor in self._factors]), matmul=lambda x: functools.reduce( lambda vec, op: op @ vec, reversed(self._factors), x ), From d8b60992e55816baa6d6ea6ea875335503bea2ba Mon Sep 17 00:00:00 2001 From: byd Date: Tue, 10 Jun 2025 11:29:18 -0400 Subject: [PATCH 3/3] Update probnum modifications for linpde-gp integration --- docs/source/development/implementing_a_probnum_method.ipynb | 2 +- .../development/quadopt_example/observation_operators.py | 2 +- .../source/tutorials/linops/linear_operators_quickstart.ipynb | 4 ++-- src/probnum/linops/_linear_operator.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/development/implementing_a_probnum_method.ipynb b/docs/source/development/implementing_a_probnum_method.ipynb index 8f27e9549..605ec1b18 100644 --- a/docs/source/development/implementing_a_probnum_method.ipynb +++ b/docs/source/development/implementing_a_probnum_method.ipynb @@ -728,7 +728,7 @@ "# %load -s function_evaluation quadopt_example/observation_operators\n", "def function_evaluation(\n", " fun: Callable[[FloatLike], FloatLike], action: FloatLike\n", - ") -> np.float_:\n", + ") -> np.float64:\n", " \"\"\"Observe a (noisy) function evaluation of the quadratic objective.\n", "\n", " Parameters\n", diff --git a/docs/source/development/quadopt_example/observation_operators.py b/docs/source/development/quadopt_example/observation_operators.py index a08e25cf4..bb5b7e6ff 100644 --- a/docs/source/development/quadopt_example/observation_operators.py +++ b/docs/source/development/quadopt_example/observation_operators.py @@ -10,7 +10,7 @@ def function_evaluation( fun: Callable[[FloatLike], FloatLike], action: FloatLike -) -> np.float_: +) -> np.float64: """Observe a (noisy) function evaluation of the quadratic objective. Parameters diff --git a/docs/source/tutorials/linops/linear_operators_quickstart.ipynb b/docs/source/tutorials/linops/linear_operators_quickstart.ipynb index 5f533847f..90b2523f4 100644 --- a/docs/source/tutorials/linops/linear_operators_quickstart.ipynb +++ b/docs/source/tutorials/linops/linear_operators_quickstart.ipynb @@ -380,7 +380,7 @@ " return np.roll(v, 1)\n", "\n", "n = 5\n", - "P_op = LambdaLinearOperator(shape=(n, n), dtype=np.float_, matmul=mv)\n", + "P_op = LambdaLinearOperator(shape=(n, n), dtype=np.float64, matmul=mv)\n", "x = np.arange(0., n, 1)\n", "\n", "P_op" @@ -512,7 +512,7 @@ "def mv(v):\n", " return v[:n-1]\n", "\n", - "Pr = LambdaLinearOperator(shape=(n-1, n), dtype=np.float_, matmul=mv)\n", + "Pr = LambdaLinearOperator(shape=(n-1, n), dtype=np.float64, matmul=mv)\n", "\n", "# Apply the operator to the 3D normal random variable\n", "rv_projected = Pr @ rv" diff --git a/src/probnum/linops/_linear_operator.py b/src/probnum/linops/_linear_operator.py index 5a4b3ca81..f0b08fd3f 100644 --- a/src/probnum/linops/_linear_operator.py +++ b/src/probnum/linops/_linear_operator.py @@ -1308,7 +1308,7 @@ class LambdaLinearOperator( # pylint: disable=too-many-instance-attributes ... def mv(v): ... return np.array([2 * v[0] - v[1], 3 * v[1]]) - >>> A = LambdaLinearOperator(shape=(2, 2), dtype=np.float_, matmul=mv) + >>> A = LambdaLinearOperator(shape=(2, 2), dtype=np.float64, matmul=mv) >>> A