def m2(self): """matrix: Second moment.""" if self._m2 is None: self._m2 = B.cholsolve(B.chol(self.prec), self.prec + B.outer(self.lam)) self._m2 = B.cholsolve(B.chol(self.prec), B.transpose(self._m2)) return self._m2
def pinv(a: AbstractMatrix): """Compute the left pseudo-inverse. Args: a (matrix): Matrix to compute left pseudo-inverse of. Returns: matrix: Left pseudo-inverse of `a`. """ return B.cholsolve(B.chol(B.matmul(a, a, tr_a=True)), B.transpose(a))
def from_normal(cls, dist): """Construct from a normal distribution. Args: dist (distribution): Normal distribution to construct from. Returns: :class:`.NaturalNormal`: Normal distribution parametrised by the natural parameters of `dist`. """ return cls(B.cholsolve(B.chol(dist.var), dist.mean), B.pd_inv(dist.var))
def sample(self, state: B.RandomState, num: int = 1): """Sample. Args: state (random state): Random state. num (int): Number of samples. Returns: tuple[random state, tensor]: Random state and sample. """ state, noise = Normal(self.prec).sample(state, num) sample = B.cholsolve(B.chol(self.prec), B.add(noise, self.lam)) # Remove the matrix type if there is no structure. This eases working with # JITs, which aren't happy with matrix types. if not structured(sample): sample = B.dense(sample) return state, sample
def mean(self): """column vector: Mean.""" if self._mean is None: self._mean = B.cholsolve(B.chol(self.prec), self.lam) return self._mean