class_docstr: Optimizer with adaptive learning rate, via calculation
  of the diagonal or block-diagonal approximation to the Fubini-Study metric tensor.
  A quantum generalization of natural gradient descent.
  
  The QNG optimizer uses a step- and parameter-dependent learning rate,
  with the learning rate dependent on the pseudo-inverse
  of the Fubini-Study metric tensor :math:`g`:
  
  .. math::
      x^{(t+1)} = x^{(t)} - \eta g(f(x^{(t)}))^{-1} \nabla f(x^{(t)}),
  
  where :math:`f(x^{(t)}) = \langle 0 | U(x^{(t)})^\dagger \hat{B} U(x^{(t)}) | 0 \rangle`
  is an expectation value of some observable measured on the variational
  quantum circuit :math:`U(x^{(t)})`.
  
  Consider a quantum node represented by the variational quantum circuit
  
  .. math::
  
      U(\mathbf{\theta}) = W(\theta_{i+1}, \dots, \theta_{N})X(\theta_{i})
      V(\theta_1, \dots, \theta_{i-1}),
  
  where all parametrized gates can be written of the form :math:`X(\theta_{i}) = e^{i\theta_i K_i}`.
  That is, the gate :math:`K_i` is the *generator* of the parametrized operation :math:`X(\theta_i)`
  corresponding to the :math:`i`-th parameter.
  
  For each parametric layer :math:`\ell` in the variational quantum circuit
  containing :math:`n` parameters, the :math:`n\times n` block-diagonal submatrix
  of the Fubini-Study tensor :math:`g_{ij}^{(\ell)}` is calculated directly on the
  quantum device in a single evaluation:
  
  .. math::
  
      g_{ij}^{(\ell)} = \langle \psi_\ell | K_i K_j | \psi_\ell \rangle
      - \langle \psi_\ell | K_i | \psi_\ell\rangle
      \langle \psi_\ell |K_j | \psi_\ell\rangle
  
  where :math:`|\psi_\ell\rangle =  V(\theta_1, \dots, \theta_{i-1})|0\rangle`
  (that is, :math:`|\psi_\ell\rangle` is the quantum state prior to the application
  of parameterized layer :math:`\ell`).
  
  Combining the quantum natural gradient optimizer with the analytic parameter-shift
  rule to optimize a variational circuit with :math:`d` parameters and :math:`L` layers,
  a total of :math:`2d+L` quantum evaluations are required per optimization step.
  
  For more details, see:
  
      James Stokes, Josh Izaac, Nathan Killoran, Giuseppe Carleo.
      "Quantum Natural Gradient."
      `Quantum 4, 269 <https://doi.org/10.22331/q-2020-05-25-269>`_, 2020.
  
  .. note::
  
      The QNG optimizer supports using a single :class:`~.QNode` as the objective function. Alternatively,
      the metric tensor can directly be provided to the :func:`step` method of the optimizer,
      using the ``metric_tensor_fn`` keyword argument.
  
      For the following cases, providing ``metric_tensor_fn`` may be useful:
  
      * For hybrid classical-quantum models, the "mixed geometry" of the model
        makes it unclear which metric should be used for which parameter.
        For example, parameters of quantum nodes are better suited to
        one metric (such as the QNG), whereas others (e.g., parameters of classical nodes)
        are likely better suited to another metric.
  
      * For multi-QNode models, we don't know what geometry is appropriate
        if a parameter is shared amongst several QNodes.
  
  **Examples:**
  
  For VQE/VQE-like problems, the objective function for the optimizer can be
  realized as :class:`~.QNode` that returns the expectation value of a Hamiltonian.
  
  >>> dev = qml.device("default.qubit", wires=(0, 1, "aux"))
  >>> @qml.qnode(dev)
  ... def circuit(params):
  ...     qml.RX(params[0], wires=0)
  ...     qml.RY(params[1], wires=0)
  ...     return qml.expval(qml.PauliX(0) + qml.PauliX(1))
  
  Once constructed, the cost function can be passed directly to the
  optimizer's ``step`` function:
  
  >>> eta = 0.01
  >>> init_params = np.array([0.011, 0.012])
  >>> opt = qml.QNGOptimizer(eta)
  >>> theta_new = opt.step(circuit, init_params)
  >>> theta_new
  tensor([ 0.01100528, -0.02799954], requires_grad=True)
  
  An alternative function to calculate the metric tensor of the QNode
  can be provided to :meth:`~.step`
  via the ``metric_tensor_fn`` keyword argument.  For example, we can provide a function
  to calculate the metric tensor via the adjoint method.
  
  >>> adj_metric_tensor = qml.adjoint_metric_tensor(circuit, circuit.device)
  >>> opt.step(circuit, init_params, metric_tensor_fn=adj_metric_tensor)
  tensor([ 0.01100528, -0.02799954], requires_grad=True)
  
  .. seealso::
  
      See the :ref:`quantum natural gradient example <quantum_natural_gradient>`
      for more details on Fubini-Study metric tensor and this optimization class.
  
  Keyword Args:
      stepsize=0.01 (float): the user-defined hyperparameter :math:`\eta`
      approx (str): Which approximation of the metric tensor to compute.
  
          - If ``None``, the full metric tensor is computed
  
          - If ``"block-diag"``, the block-diagonal approximation is computed, reducing
            the number of evaluated circuits significantly.
  
          - If ``"diag"``, only the diagonal approximation is computed, slightly
            reducing the classical overhead but not the quantum resources
            (compared to ``"block-diag"``).
  
      lam=0 (float): metric tensor regularization :math:`G_{ij}+\lambda I`
          to be applied at each optimization step
code: def __init__(self, stepsize=0.01, approx="block-diag", lam=0):
      super().__init__(stepsize)
  
      self.approx = approx
  
      self.metric_tensor = None
      self.lam = lam
  
file_path: pennylane/pennylane/optimize/qng.py
imports: from pennylane import numpy
  import pennylane
  from pennylane.utils import _flatten, unflatten
  from .gradient_descent import GradientDescentOptimizer
label_desc: Use image node_id 1 to create a new QNGOptimizer object from inherited base classes: GradientDescentOptimizer with example: obj = QNGOptimizer(stepsize, approx, lam)