code: def vjp(func: Callable, *primals):
      flattened_primals, ret_idxs = _flatten_containers(primals)
      unique_keys = list(
          {
              ivy.index_nest(ret_idxs, i)
              for i in ivy.nested_argwhere(
                  ret_idxs, lambda x: isinstance(x, str)
              )
          }
      )
  
      def grad_fn(*x_in):
          ret, idxs = _flatten_containers(
              ivy.to_native(
                  func(
                      *ivy.to_ivy(
                          _rebuild_flattened_containers(x_in, ret_idxs),
                          nested=True,
                      )
                  ),
                  nested=True,
                  include_derived=True,
              )
          )
  
          # replave the idxs with the unique keys
          func_ret_idxs = torch.tensor(
              ivy.nested_map(
                  lambda x: (
                      unique_keys.index(x)
                      if isinstance(x, str)
                      else -1
                      if x is None
                      else x
                  ),
                  idxs,
              )
          )
  
          return (ret, func_ret_idxs)
  
      primals_out, _vjpfun, func_ret_idxs = ivy.outputs_to_ivy_arrays(
          torch.func.vjp
      )(
          grad_fn,
          *ivy.to_native(flattened_primals, nested=True),
          has_aux=True,
      )
  
      func_ret_idxs = ivy.nested_map(
          lambda x: unique_keys[x]
          if x >= 0 and x < len(unique_keys)
          else None,
          func_ret_idxs.tolist(),
      )
      primals_out = _rebuild_flattened_containers(
          primals_out, func_ret_idxs
      )
  
      def vjpfun(*x_in):
          ivy.assertions.check_isinstance(x_in, tuple)
          return _rebuild_flattened_containers(
              ivy.to_ivy(
                  _vjpfun(
                      ivy.to_native(
                          _flatten_containers(x_in)[0], nested=True
                      )
                  ),
                  nested=True,
                  include_derived=True,
              ),
              ret_idxs,
          )
  
      return (primals_out, vjpfun)
  
file_path: ivy/ivy/functional/backends/torch/experimental/gradients.py
imports: import torch
  from typing import Callable
  import ivy
  from ivy.func_wrapper import inputs_to_native_arrays
  from ivy.functional.ivy.gradients import _flatten_containers, _rebuild_flattened_containers
label_desc: Use image node_id 2 for calling a global function with example usage: vjp(func) and returns: primals_out,  vjpfun, ret,  func_ret_idxs, _rebuild_flattened_containers