code: def flatten_func_grad(func):
      r
      @wraps(func)
      def new_func(*args, **kwargs):
          val, grad = func(*args, **kwargs)
          return val, flatten(grad, returns_shapes=False)
  
      return new_func
docs: r"""
      Decorator to flatten structured gradients and return objective.
  
      Examples
      --------
      >>> def cost(w, lambda_):
      ...     sq_norm = w.T.dot(w)
      ...     return .5 * lambda_ * sq_norm, [lambda_ * w, .5 * sq_norm]
      >>> val, grad = cost(np.array([.5, .1, -.2]), .25)
  
      >>> np.isclose(val, 0.0375)
      True
  
      >>> len(grad)
      2
      >>> grad_w, grad_lambda = grad
      >>> np.shape(grad_w)
      (3,)
      >>> np.shape(grad_lambda)
      ()
      >>> grad_w
      array([ 0.125,  0.025, -0.05 ])
      >>> np.isclose(grad_lambda, 0.15)
      True
  
      >>> cost_new = flatten_func_grad(cost)
      >>> val_new, grad_new = cost_new(np.array([.5, .1, -.2]), .25)
      >>> val == val_new
      True
      >>> grad_new
      array([ 0.125,  0.025, -0.05 ,  0.15 ])