[docs]classAffineWarpFunction(WarpFunction):r""" A warp of form :math:`y \mapsto ay + b`. """
[docs]def__init__(self,a:Union[float,int]=1,b:Union[float,int]=0)->None:""" Initialise self. :param a: The scale of the affine transformation. :param b: The shift of the affine transformation. """super().__init__()self.weight=torch.nn.Parameter(torch.as_tensor([[float(a)]]))self.bias=torch.nn.Parameter(torch.as_tensor([[float(b)]]))
@propertydefa(self)->torch.nn.Parameter:"""Return the weight."""returnself.weight@propertydefb(self)->torch.nn.Parameter:"""Return the bias."""returnself.bias@overridedefforward(self,y:torch.Tensor)->torch.Tensor:returny*self.a+self.b@overridedefinverse(self,x:torch.Tensor)->torch.Tensor:returntorch.div(x-self.b,self.a)@overridedefderiv(self,y:torch.Tensor)->torch.Tensor:returntorch.ones_like(y)*self.a
[docs]@require_controller_input("controller_inputs")classPositiveAffineWarpFunction(AffineWarpFunction):r""" A warp of form :math:`y \mapsto ay + b`, where :math:`ay + b > 0`. .. note:: This warp function needs to be activated before use. See :mod:`vanguard.warps.intermediate`. """
[docs]def__init__(self,a:Union[float,int]=1,b:Union[float,int]=0)->None:""" Initialise self. :param a: The prior for the weight of the function. :param b: The prior for the bias of the function. """train_y=self.controller_inputs["train_y"]lambda_1,lambda_2=self._get_constraint_slopes(train_y)beta_squared=(a*lambda_1+b)/(lambda_2-lambda_1)ifbeta_squared<0:raiseValueError("The supplied a and b values violate the constraints defined by the specified values of"f"lambda_1 and lambda_2, since a*lambda_1 + b < 0, i.e. {a}*{lambda_1} + {b} < 0.")beta=np.sqrt(beta_squared)alpha=np.sqrt(a+beta**2)super().__init__(alpha,beta)self.lambda_1=lambda_1self.lambda_2=lambda_2
@propertydefa(self)->torch.Tensor:"""Return the weight."""returnself.weight**2-self.bias**2@propertydefb(self)->torch.Tensor:"""Return the bias."""return-(self.weight**2*self.lambda_1-self.bias**2*self.lambda_2)@staticmethoddef_get_constraint_slopes(y_values:Union[Tensor,NDArray[np.floating]])->tuple[float,float]:""" Return the two constraint slopes needed for the y_values. :param y_values: A set of values for which :math:`ay + b` must ultimately hold. :returns: The two values needed to establish the same bounds on :math:`a` and :math:`b`. """y_values=torch.as_tensor(y_values)try:negative_contribution=y_values.min().item()non_negative_contribution=y_values.max().item()exceptRuntimeError:ify_values.numel()==0:raiseValueError("Cannot process empty iterable.")fromNoneelse:raiseelse:returnnegative_contribution,non_negative_contribution
[docs]classBoxCoxWarpFunction(WarpFunction):r""" The Box-Cox warp as in :cite:`Rios19`. The transformation is given by: .. math:: y\mapsto\frac{sgn(y)|y|^\lambda - 1}{\lambda}, \lambda\in\mathbb{R}_0^+. """
[docs]def__init__(self,lambda_:Union[int,float]=0)->None:""" Initialise self. :param lambda_: The parameter for the transformation. """super().__init__()self.lambda_=lambda_
[docs]classSinhWarpFunction(WarpFunction):r""" A map of the form :math:`y\mapsto\sinh(y)`. """@overridedefforward(self,y:torch.Tensor)->torch.Tensor:returntorch.sinh(y)@overridedefinverse(self,x:torch.Tensor)->torch.Tensor:returntorch.asinh(x)@overridedefderiv(self,y:torch.Tensor)->torch.Tensor:returntorch.cosh(y)
[docs]classArcSinhWarpFunction(WarpFunction):r""" A map of the form :math:`y\mapsto\sinh^{-1}(y)`. """@overridedefforward(self,y:torch.Tensor)->torch.Tensor:returntorch.asinh(y)@overridedefinverse(self,x:torch.Tensor)->torch.Tensor:returntorch.sinh(x)@overridedefderiv(self,y:torch.Tensor)->torch.Tensor:return1/torch.sqrt(y**2+1)
[docs]classLogitWarpFunction(WarpFunction):r""" A map of the form :math:`y\mapsto\log\frac{y}{1-y}`. """@overridedefforward(self,y:torch.Tensor)->torch.Tensor:returntorch.logit(y)@overridedefinverse(self,x:torch.Tensor)->torch.Tensor:returntorch.sigmoid(x)@overridedefderiv(self,y:torch.Tensor)->torch.Tensor:return(1-2*y)/(y*(1-y))
[docs]classSoftPlusWarpFunction(WarpFunction):r""" A map of the form :math:`y\mapsto\log(e^y - 1)`. """@overridedefforward(self,y:torch.Tensor)->torch.Tensor:returntorch.log(torch.exp(y)-1)@overridedefinverse(self,x:torch.Tensor)->torch.Tensor:returntorch.log(torch.exp(x)+1)@overridedefderiv(self,y:torch.Tensor)->torch.Tensor:returntorch.sigmoid(y)