def __new__(cls, name, *args, **kwargs): if name is _Unpickling: return object.__new__(cls) # for pickle try: model = Model.get_context() except TypeError: raise TypeError( "No model on context stack, which is needed to " "instantiate distributions. Add variable inside " "a 'with model:' block, or use the '.dist' syntax " "for a standalone distribution." ) if not isinstance(name, string_types): raise TypeError(f"Name needs to be a string but got: {name}") data = kwargs.pop("observed", None) cls.data = data if isinstance(data, ObservedRV) or isinstance(data, FreeRV): raise TypeError("observed needs to be data but got: {}".format(type(data))) total_size = kwargs.pop("total_size", None) dims = kwargs.pop("dims", None) has_shape = "shape" in kwargs shape = kwargs.pop("shape", None) if dims is not None: if shape is not None: raise ValueError("Specify only one of 'dims' or 'shape'") if isinstance(dims, string_types): dims = (dims,) shape = model.shape_from_dims(dims) # failsafe against 0-shapes if shape is not None and any(np.atleast_1d(shape) <= 0): raise ValueError( f"Distribution initialized with invalid shape {shape}. This is not allowed." ) # Some distributions do not accept shape=None if has_shape or shape is not None: dist = cls.dist(*args, **kwargs, shape=shape) else: dist = cls.dist(*args, **kwargs) return model.Var(name, dist, data, total_size, dims=dims)
def __new__( cls, name: str, *args, rng=None, dims: Optional[Dims] = None, initval=None, observed=None, total_size=None, transform=UNSET, **kwargs, ) -> RandomVariable: """Adds a RandomVariable corresponding to a PyMC3 distribution to the current model. Note that all remaining kwargs must be compatible with ``.dist()`` Parameters ---------- cls : type A PyMC3 distribution. name : str Name for the new model variable. rng : optional Random number generator to use with the RandomVariable. dims : tuple, optional A tuple of dimension names known to the model. initval : optional Test value to be attached to the output RV. Must match its shape exactly. observed : optional Observed data to be passed when registering the random variable in the model. See ``Model.register_rv``. total_size : float, optional See ``Model.register_rv``. transform : optional See ``Model.register_rv``. **kwargs Keyword arguments that will be forwarded to ``.dist()``. Most prominently: ``shape`` and ``size`` Returns ------- rv : RandomVariable The created RV, registered in the Model. """ try: from pymc3.model import Model model = Model.get_context() except TypeError: raise TypeError("No model on context stack, which is needed to " "instantiate distributions. Add variable inside " "a 'with model:' block, or use the '.dist' syntax " "for a standalone distribution.") if "testval" in kwargs: initval = kwargs.pop("testval") warnings.warn( "The `testval` argument is deprecated; use `initval`.", DeprecationWarning, stacklevel=2, ) if not isinstance(name, string_types): raise TypeError(f"Name needs to be a string but got: {name}") if rng is None: rng = model.next_rng() if dims is not None and "shape" in kwargs: raise ValueError( f"Passing both `dims` ({dims}) and `shape` ({kwargs['shape']}) is not supported!" ) if dims is not None and "size" in kwargs: raise ValueError( f"Passing both `dims` ({dims}) and `size` ({kwargs['size']}) is not supported!" ) dims = convert_dims(dims) # Create the RV without specifying initval, because the initval may have a shape # that only matches after replicating with a size implied by dims (see below). rv_out = cls.dist(*args, rng=rng, initval=None, **kwargs) ndim_actual = rv_out.ndim resize_shape = None # `dims` are only available with this API, because `.dist()` can be used # without a modelcontext and dims are not tracked at the Aesara level. if dims is not None: ndim_resize, resize_shape, dims = resize_from_dims( dims, ndim_actual, model) elif observed is not None: ndim_resize, resize_shape, observed = resize_from_observed( observed, ndim_actual) if resize_shape: # A batch size was specified through `dims`, or implied by `observed`. rv_out = change_rv_size(rv_var=rv_out, new_size=resize_shape, expand=True) if initval is not None: # Assigning the testval earlier causes trouble because the RV may not be created with the final shape already. rv_out.tag.test_value = initval return model.register_rv(rv_out, name, observed, total_size, dims=dims, transform=transform)