def METHOD_NAME(objective_fn, args, kwargs, grad_fn=None):
    r"""Compute gradient of the objective function at the given point and return it along with
    the objective function forward pass (if available).
    Args:
        objective_fn (function): the objective function for optimization
        args (tuple): tuple of NumPy arrays containing the current parameters for the
            objection function
        kwargs (dict): keyword arguments for the objective function
        grad_fn (function): optional gradient function of the objective function with respect to
            the variables ``args``. If ``None``, the gradient function is computed automatically.
            Must return the same shape of tuple [array] as the autograd derivative.
    Returns:
        tuple (array): NumPy array containing the gradient :math:`\nabla f(x^{(t)})` and the
        objective function output. If ``grad_fn`` is provided, the objective function
        will not be evaluted and instead ``None`` will be returned.
    """
    g = get_gradient(objective_fn) if grad_fn is None else grad_fn
    grad = g(*args, **kwargs)
    forward = getattr(g, "forward", None)
    num_trainable_args = sum(getattr(arg, "requires_grad", False) for arg in args)
    grad = (grad,) if num_trainable_args == 1 else grad
    return grad, forward