code: def param_shift_cv(
      tape: qml.tape.QuantumTape,
      dev,
      argnum=None,
      shifts=None,
      gradient_recipes=None,
      fallback_fn=finite_diff,
      f0=None,
      force_order2=False,
  ) -> (Sequence[qml.tape.QuantumTape], Callable):
      r"""Transform a continuous-variable QNode to compute the parameter-shift gradient of all gate
      parameters with respect to its inputs.
  
      Args:
          tape (QNode or QuantumTape): quantum circuit to differentiate
          dev (pennylane.Device): device the parameter-shift method is to be computed on
          argnum (int or list[int] or None): Trainable parameter indices to differentiate
              with respect to. If not provided, the derivative with respect to all
              trainable indices are returned.
          shifts (list[tuple[int or float]]): List containing tuples of shift values.
              If provided, one tuple of shifts should be given per trainable parameter
              and the tuple should match the number of frequencies for that parameter.
              If unspecified, equidistant shifts are assumed.
          gradient_recipes (tuple(list[list[float]] or None)): List of gradient recipes
              for the parameter-shift method. One gradient recipe must be provided
  
              per trainable parameter.
  
              This is a tuple with one nested list per parameter. For
              parameter :math:`\phi_k`, the nested list contains elements of the form
              :math:`[c_i, a_i, s_i]` where :math:`i` is the index of the
              term, resulting in a gradient recipe of
  
              .. math:: \frac{\partial}{\partial\phi_k}f = \sum_{i} c_i f(a_i \phi_k + s_i).
  
              If ``None``, the default gradient recipe containing the two terms
              :math:`[c_0, a_0, s_0]=[1/2, 1, \pi/2]` and :math:`[c_1, a_1,
              s_1]=[-1/2, 1, -\pi/2]` is assumed for every parameter.
          fallback_fn (None or Callable): a fallback grdient function to use for
              any parameters that do not support the parameter-shift rule.
          f0 (tensor_like[float] or None): Output of the evaluated input tape. If provided,
              and the gradient recipe contains an unshifted term, this value is used,
              saving a quantum evaluation.
          force_order2 (bool): if True, use the order-2 method even if not necessary
  
      Returns:
          qnode (QNode) or tuple[List[QuantumTape], function]:
  
          The transformed circuit as described in :func:`qml.transform <pennylane.transform>`. Executing this circuit
          will provide the Jacobian in the form of a tensor, a tuple, or a nested tuple depending upon the nesting
          structure of measurements in the original circuit.
  
      This transform supports analytic gradients of Gaussian CV operations using
      the parameter-shift rule. This gradient method returns *exact* gradients,
      and can be computed directly on quantum hardware.
  
      Analytic gradients of photonic circuits that satisfy
      the following constraints with regards to measurements are supported:
  
      * Expectation values are restricted to observables that are first- and
        second-order in :math:`\hat{x}` and :math:`\hat{p}` only.
        This includes :class:`~.X`, :class:`~.P`, :class:`~.QuadOperator`,
        :class:`~.PolyXP`, and :class:`~.NumberOperator`.
  
        For second-order observables, the device **must support** :class:`~.PolyXP`.
  
      * Variances are restricted to observables that are first-order
        in :math:`\hat{x}` and :math:`\hat{p}` only. This includes :class:`~.X`, :class:`~.P`,
        :class:`~.QuadOperator`, and *some* parameter values of :class:`~.PolyXP`.
  
        The device **must support** :class:`~.PolyXP`.
  
      .. warning::
  
          Fock state probabilities (tapes that return :func:`~pennylane.probs` or
          expectation values of :class:`~.FockStateProjector`) are not supported.
  
      In addition, the operations must fulfill the following requirements:
  
      * Only Gaussian operations are differentiable.
  
      * Non-differentiable Fock states and Fock operations may *precede* all differentiable Gaussian,
        operations. For example, the following is permissible:
  
        .. code-block:: python
  
            @qml.qnode(dev)
            def circuit(weights):
                # Non-differentiable Fock operations
                qml.FockState(np.array(2, requires_grad=False), wires=0)
                qml.Kerr(np.array(0.654, requires_grad=False), wires=1)
  
                # differentiable Gaussian operations
                qml.Displacement(weights[0], weights[1], wires=0)
                qml.Beamsplitter(weights[2], weights[3], wires=[0, 1])
  
                return qml.expval(qml.NumberOperator(0))
  
      * If a Fock operation succeeds a Gaussian operation, the Fock operation must
        not contribute to any measurements. For example, the following is allowed:
  
        .. code-block:: python
  
            @qml.qnode(dev)
            def circuit(weights):
                qml.Displacement(weights[0], weights[1], wires=0)
                qml.Beamsplitter(weights[2], weights[3], wires=[0, 1])
                qml.Kerr(np.array(0.654, requires_grad=False), wires=1)  # there is no measurement on wire 1
                return qml.expval(qml.NumberOperator(0))
  
      If any of the above constraints are not followed, the tape cannot be differentiated
      via the CV parameter-shift rule. Please use numerical differentiation instead.
  
      **Example**
  
      This transform can be registered directly as the quantum gradient transform
      to use during autodifferentiation:
  
      >>> dev = qml.device("default.gaussian", wires=2)
      >>> @qml.qnode(dev, diff_method="parameter-shift")
      ... def circuit(params):
      ...     qml.Squeezing(params[0], params[1], wires=[0])
      ...     qml.Squeezing(params[2], params[3], wires=[0])
      ...     return qml.expval(qml.NumberOperator(0))
      >>> params = np.array([0.1, 0.2, 0.3, 0.4], requires_grad=True)
      >>> qml.jacobian(circuit)(params)
      array([ 0.87516064,  0.01273285,  0.88334834, -0.01273285])
  
      .. details::
          :title: Usage Details
  
          This gradient transform can be applied directly to :class:`QNode <pennylane.QNode>` objects.
          However, for performance reasons, we recommend providing the gradient transform as the ``diff_method`` argument
          of the QNode decorator, and differentiating with your preferred machine learning framework.
  
          >>> @qml.qnode(dev)
          ... def circuit(params):
          ...     qml.Squeezing(params[0], params[1], wires=[0])
          ...     qml.Squeezing(params[2], params[3], wires=[0])
          ...     return qml.expval(qml.NumberOperator(0))
          >>> params = np.array([0.1, 0.2, 0.3, 0.4], requires_grad=True)
          >>> qml.gradients.param_shift_cv(circuit, dev)(params)
          tensor([[ 0.87516064,  0.01273285,  0.88334834, -0.01273285]], requires_grad=True)
  
          This quantum gradient transform can also be applied to low-level
          :class:`~.QuantumTape` objects. This will result in no implicit quantum
          device evaluation. Instead, the processed tapes, and post-processing
          function, which together define the gradient are directly returned:
  
          >>> r0, phi0, r1, phi1 = [0.4, -0.3, -0.7, 0.2]
          >>> ops = [qml.Squeezing(r0, phi0, wires=0), qml.Squeezing(r1, phi2, wires=0)]
          >>> tape = qml.tape.QuantumTape(ops, [qml.expval(qml.NumberOperator(0))])
          >>> gradient_tapes, fn = qml.gradients.param_shift_cv(tape, dev)
          >>> gradient_tapes
          [<QuantumTape: wires=[0], params=4>,
           <QuantumTape: wires=[0], params=4>,
           <QuantumTape: wires=[0], params=4>,
           <QuantumTape: wires=[0], params=4>]
  
          This can be useful if the underlying circuits representing the gradient
          computation need to be analyzed.
  
          The output tapes can then be evaluated and post-processed to retrieve
          the gradient:
  
          >>> dev = qml.device("default.gaussian", wires=2)
          >>> fn(qml.execute(gradient_tapes, dev, None))
          array([[-0.32487113, -0.4054074 , -0.87049853,  0.4054074 ]])
      """
      if len(tape.measurements) > 1:
          raise ValueError(
              "Computing the gradient of CV circuits that return more than one measurement is not possible."
          )
  
      # perform gradient method validation
      if any(isinstance(m, StateMP) for m in tape.measurements):
          raise ValueError(
              "Computing the gradient of circuits that return the state is not supported."
          )
  
      method = "analytic" if fallback_fn is None else "best"
  
      trainable_params = choose_trainable_params(tape, argnum)
      method_map = _gradient_analysis_and_validation_cv(
          tape, method, trainable_params
      )
  
      if argnum is None and not tape.trainable_params:
          return _no_trainable_grad(tape)
  
      gradient_tapes = []
      shapes = []
      fns = []
  
      def _update(data):
          """Utility function to update the list of gradient tapes,
          the corresponding number of gradient tapes, and the processing functions
          """
          gradient_tapes.extend(data[0])
          shapes.append(len(data[0]))
          fns.append(data[1])
  
      if all(g == "0" for g in method_map.values()):
          return [], lambda _: np.zeros(
              [tape.output_dim, len(tape.trainable_params)]
          )
  
      var_present = any(
          isinstance(m, VarianceMP) for m in tape.measurements
      )
  
      unsupported_params = []
      first_order_params = []
      second_order_params = []
  
      for idx, g in method_map.items():
          if g == "F":
              unsupported_params.append(idx)
  
          elif g == "A":
              first_order_params.append(idx)
  
          elif g == "A2":
              second_order_params.append(idx)
  
      if force_order2:
          # all analytic parameters should be computed using the second-order method
          second_order_params += first_order_params
          first_order_params = []
  
      if "PolyXP" not in dev.observables and (
          second_order_params or var_present
      ):
          warnings.warn(
              f"The device {dev.short_name} does not support "
              "the PolyXP observable. The analytic parameter-shift cannot be used for "
              "second-order observables; falling back to finite-differences.",
              UserWarning,
          )
  
          if var_present:
              unsupported_params += first_order_params
              first_order_params = []
  
          unsupported_params += second_order_params
          second_order_params = []
  
      # If there are unsupported operations, call the fallback gradient function
      if unsupported_params:
          _update(fallback_fn(tape, argnum=unsupported_params))
  
      # collect all the analytic parameters
      argnum = first_order_params + second_order_params
  
      if not argnum:
          # No analytic parameters. Return the existing fallback tapes/fn
          return gradient_tapes, fns[-1]
  
      gradient_recipes = gradient_recipes or [None] * len(argnum)
  
      if var_present:
          _update(
              var_param_shift(
                  tape, dev.wires, argnum, shifts, gradient_recipes, f0
              )
          )
  
      else:
          # Only expectation values were specified
          if first_order_params:
              _update(
                  expval_param_shift(
                      tape,
                      first_order_params,
                      shifts,
                      gradient_recipes,
                      f0,
                  )
              )
  
          if second_order_params:
              _update(
                  second_order_param_shift(
                      tape,
                      dev.wires,
                      second_order_params,
                      shifts,
                      gradient_recipes,
                  )
              )
  
      def processing_fn(results):
          start = 0
          grads = []
  
          for s, f in zip(shapes, fns):
              grads.append(f(results[start : start + s]))
              start += s
  
          # For expval param shift with multiple params
          if isinstance(grads[0], tuple):
              grads = [qml.math.stack(g) for g in grads]
  
          jacobian = sum(grads)
  
          if jacobian.shape != ():
              if jacobian.shape[0] == 1:
                  jacobian = jacobian[0]
              if len(argnum) > 1:
                  jacobian = tuple(j for j in jacobian)
          return jacobian
  
      return gradient_tapes, processing_fn
  
imports: from typing import Sequence, Callable
  import itertools
  from functools import partial
  import warnings
  import numpy
  import pennylane
  from pennylane.measurements import ExpectationMP, ProbabilityMP, StateMP, VarianceMP, MeasurementProcess
  from pennylane import transform
  from pennylane.transforms.tape_expand import expand_invalid_trainable
  from pennylane.gradients.gradient_transform import _contract_qjac_with_cjac, choose_trainable_params, _validate_gradient_methods
  from .finite_difference import finite_diff
  from .general_shift_rules import generate_shifted_tapes, process_shifts
  from .gradient_transform import _no_trainable_grad
  from .parameter_shift import _get_operation_recipe, expval_param_shift
label_desc: Use image node_id 8 for calling a global function with example usage: param_shift_cv(tape, dev, argnum, shifts, gradient_recipes, fallback_fn, f0, force_order2) and returns: gradient_tapes,  processing_fn, _no_trainable_grad, list,  function, gradient_tapes,  fns, jacobian