Example #1
0
    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
Example #2
0
    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)