Source code for pybop.optimisers._cost_interface
from typing import Optional, Union
import numpy as np
from pybop import BaseCost, Inputs, Transformation
[docs]
class CostInterface:
"""
A base class for the optimisers and samplers that provides a common interface between
the optimiser/sampler and the cost evaluation.
"""
def __init__(
self, transformation: Optional[Transformation] = None, invert_cost: bool = False
):
[docs]
self.invert_cost = invert_cost
self.transformation = transformation
[docs]
def _inverts_cost(self, cost):
"""
Returns the true cost if the optimiser is operating in the inverted space
else returns the cost as is.
"""
return [v * (-1 if self.invert_cost else 1) for v in cost]
[docs]
def call_cost(
self,
x: Union[Inputs, list],
cost: Union[BaseCost, callable],
calculate_grad: bool = False,
) -> Union[float, tuple[float, np.ndarray]]:
"""
Provides the interface between the cost and the optimiser.
Applies any transformation to the input parameter values, calls the cost function, inverts
the sign of the cost and gradient if the target is maximisation and reverses the effect of
any transformation on the gradient.
Parameters
----------
x : Inputs or list-like
The input parameters for which the cost and optionally the gradient will be computed.
cost : pybop.BaseCost or callable
The objective to be optimised, which can be either a pybop.Cost or callable function.
calculate_grad : bool, optional, default=False
If True, both cost and gradient will be computed. Otherwise, only the cost is computed.
Returns
-------
float or tuple
- If `calculate_grad` is False, returns the computed cost (float).
- If `calculate_grad` is True, returns a tuple containing the cost (float)
and the gradient (np.ndarray).
"""
model_x = self.transform_values(x)
sign = -1 if self.invert_cost else 1
if calculate_grad:
cost, grad = cost.single_call(model_x, calculate_grad=calculate_grad)
# Compute gradient with respect to the search parameters
if self._transformation is not None:
jac = self.transformation.jacobian(x)
grad = np.matmul(grad, jac)
return cost * sign, grad * sign
return cost(model_x) * sign
@property
@transformation.setter
def transformation(self, transformation: Transformation):
self._transformation = transformation