Files
2026-07-13 13:30:25 +08:00

89 lines
2.5 KiB
Python
Executable File

import numpy as np
from prml.nn.array.broadcast import broadcast_to
from prml.nn.math.log import log
from prml.nn.math.square import square
from prml.nn.random.random import RandomVariable
from prml.nn.tensor.constant import Constant
from prml.nn.tensor.tensor import Tensor
class Cauchy(RandomVariable):
"""
Cauchy distribution aka Lorentz distribution
p(x|x0(loc), scale)
= 1 / [pi*scale * {1 + (x - x0)^2 / scale^2}]
Parameters
----------
loc : tensor_like
location parameter
scale : tensor_like
scale parameter
data : tensor_like
realization
p : RandomVariable
original distribution of a model
"""
def __init__(self, loc, scale, data=None, p=None):
super().__init__(data, p)
self.loc, self.scale = self._check_input(loc, scale)
def _check_input(self, loc, scale):
loc = self._convert2tensor(loc)
scale = self._convert2tensor(scale)
if loc.shape != scale.shape:
shape = np.broadcast(loc.value, scale.value).shape
if loc.shape != shape:
loc = broadcast_to(loc, shape)
if scale.shape != shape:
scale = broadcast_to(scale, shape)
return loc, scale
@property
def loc(self):
return self.parameter["loc"]
@loc.setter
def loc(self, loc):
self.parameter["loc"] = loc
@property
def scale(self):
return self.parameter["scale"]
@scale.setter
def scale(self, scale):
try:
ispositive = (scale.value > 0).all()
except AttributeError:
ispositive = (scale.value > 0)
if not ispositive:
raise ValueError("value of scale must be positive")
self.parameter["scale"] = scale
def forward(self):
self.eps = np.random.standard_cauchy(size=self.loc.shape)
self.output = self.scale.value * self.eps + self.loc.value
if isinstance(self.loc, Constant):
return Constant(self.output)
return Tensor(self.output, function=self)
def backward(self, delta):
dloc = delta
dscale = delta * self.eps
self.loc.backward(dloc)
self.scale.backward(dscale)
def _pdf(self, x):
return (
1 / (np.pi * self.scale * (1 + square((x - self.loc) / self.scale)))
)
def _log_pdf(self, x):
return (
-np.log(np.pi)
- log(self.scale)
- log(1 + square((x - self.loc) / self.scale))
)