def parameter_expression_grad( param_expr: ParameterExpression, param: ParameterExpression) -> Union[ParameterExpression, float]: """Get the derivative of a parameter expression w.r.t. the given parameter. Args: param_expr: The Parameter Expression for which we compute the derivative param: Parameter w.r.t. which we want to take the derivative Returns: ParameterExpression representing the gradient of param_expr w.r.t. param """ if not isinstance(param_expr, ParameterExpression): return 0.0 if param not in param_expr._parameter_symbols: return 0.0 import sympy as sy expr = param_expr._symbol_expr keys = param_expr._parameter_symbols[param] expr_grad = sy.N(0) if not isinstance(keys, IterableAbc): keys = [keys] if HAS_SYMENGINE: expr_grad = 0 for key in keys: expr_grad += symengine.Derivative(expr, key) else: expr_grad = sy.N(0) for key in keys: expr_grad += sy.Derivative(expr, key).doit() # generate the new dictionary of symbols # this needs to be done since in the derivative some symbols might disappear (e.g. # when deriving linear expression) parameter_symbols = {} for parameter, symbol in param_expr._parameter_symbols.items(): if symbol in expr_grad.free_symbols: parameter_symbols[parameter] = symbol if len(parameter_symbols) > 0: return ParameterExpression(parameter_symbols, expr=expr_grad) return float(expr_grad) # if no free symbols left, convert to float
def gradient(self, param) -> Union["ParameterExpression", complex]: """Get the derivative of a parameter expression w.r.t. a specified parameter expression. Args: param (Parameter): Parameter w.r.t. which we want to take the derivative Returns: ParameterExpression representing the gradient of param_expr w.r.t. param or complex or float number """ # Check if the parameter is contained in the parameter expression if param not in self._parameter_symbols.keys(): # If it is not contained then return 0 return 0.0 # Compute the gradient of the parameter expression w.r.t. param key = self._parameter_symbols[param] if _optionals.HAS_SYMENGINE: import symengine expr_grad = symengine.Derivative(self._symbol_expr, key) else: # TODO enable nth derivative from sympy import Derivative expr_grad = Derivative(self._symbol_expr, key).doit() # generate the new dictionary of symbols # this needs to be done since in the derivative some symbols might disappear (e.g. # when deriving linear expression) parameter_symbols = {} for parameter, symbol in self._parameter_symbols.items(): if symbol in expr_grad.free_symbols: parameter_symbols[parameter] = symbol # If the gradient corresponds to a parameter expression then return the new expression. if len(parameter_symbols) > 0: return ParameterExpression(parameter_symbols, expr=expr_grad) # If no free symbols left, return a complex or float gradient expr_grad_cplx = complex(expr_grad) if expr_grad_cplx.imag != 0: return expr_grad_cplx else: return float(expr_grad)