We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Investigate alternate matrix pseudo-inverse functions
The QGT optimizer makes use of the matrix pseudo-inverse, via the `scipy.linalg.pinv` function. However, there are several alternative functions we could also use:

* https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinv.html
* https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinv2.html
* https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinvh.html

In the case of commuting generators, the block diag metric tensor will be symmetric, so `pinvh`  might be more efficient/stable. This is something worth investigating.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pennylane/optimize/qng.py`
Content:
```
1 # Copyright 2018 Xanadu Quantum Technologies Inc.
2 
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Quantum natural gradient optimizer"""
15 #pylint: disable=too-many-branches
16 import autograd.numpy as np
17 from scipy import linalg
18 
19 from pennylane.utils import _flatten, unflatten
20 
21 from .gradient_descent import GradientDescentOptimizer
22 
23 
24 class QNGOptimizer(GradientDescentOptimizer):
25     r"""Optimizer with adaptive learning rate, via calculation
26     of the diagonal or block-diagonal approximation to the Fubini-Study metric tensor.
27     A quantum generalization of natural gradient descent.
28 
29     The QNG optimizer uses a step- and parameter-dependent learning rate,
30     with the learning rate dependent on the pseudo-inverse
31     of the Fubini-Study metric tensor :math:`g`:
32 
33     .. math::
34         x^{(t+1)} = x^{(t)} - \eta g(f(x^{(t)}))^{-1} \nabla f(x^{(t)}),
35 
36     where :math:`f(x^{(t)}) = \langle 0 | U(x^{(t)})^\dagger \hat{B} U(x^{(t)}) | 0 \rangle`
37     is an expectation value of some observable measured on the variational
38     quantum circuit :math:`U(x^{(t)})`.
39 
40     Consider a quantum node represented by the variational quantum circuit
41 
42     .. math::
43 
44         U(\mathbf{\theta}) = W(\theta_{i+1}, \dots, \theta_{N})X(\theta_{i})
45         V(\theta_1, \dots, \theta_{i-1}),
46 
47     where all parametrized gates can be written of the form :math:`X(\theta_{i}) = e^{i\theta_i K_i}`.
48     That is, the gate :math:`K_i` is the *generator* of the parametrized operation :math:`X(\theta_i)`
49     corresponding to the :math:`i`-th parameter.
50 
51     For each parametric layer :math:`\ell` in the variational quantum circuit
52     containing :math:`n` parameters, the :math:`n\times n` block-diagonal submatrix
53     of the Fubini-Study tensor :math:`g_{ij}^{(\ell)}` is calculated directly on the
54     quantum device in a single evaluation:
55 
56     .. math::
57 
58         g_{ij}^{(\ell)} = \langle \psi_\ell | K_i K_j | \psi_\ell \rangle
59         - \langle \psi_\ell | K_i | \psi_\ell\rangle
60         \langle \psi_\ell |K_j | \psi_\ell\rangle
61 
62     where :math:`|\psi_\ell\rangle =  V(\theta_1, \dots, \theta_{i-1})|0\rangle`
63     (that is, :math:`|\psi_\ell\rangle` is the quantum state prior to the application
64     of parameterized layer :math:`\ell`).
65 
66     Combining the quantum natural gradient optimizer with the analytic parameter-shift
67     rule to optimize a variational circuit with :math:`d` parameters and :math:`L` layers,
68     a total of :math:`2d+L` quantum evaluations are required per optimization step.
69 
70     For more details, see:
71 
72         James Stokes, Josh Izaac, Nathan Killoran, Giuseppe Carleo.
73         "Quantum Natural Gradient." `arXiv:1909.02108 <https://arxiv.org/abs/1909.02108>`_, 2019.
74 
75     .. note::
76 
77         The QNG optimizer **only supports single QNodes** as objective functions.
78 
79         In particular:
80 
81         * For hybrid classical-quantum models, the "mixed geometry" of the model
82           makes it unclear which metric should be used for which parameter.
83           For example, parameters of quantum nodes are better suited to
84           one metric (such as the QNG), whereas others (e.g., parameters of classical nodes)
85           are likely better suited to another metric.
86 
87         * For multi-QNode models, we don't know what geometry is appropriate
88           if a parameter is shared amongst several QNodes.
89 
90     .. seealso::
91 
92         See the :ref:`quantum natural gradient example <quantum_natural_gradient>`
93         for more details on Fubini-Study metric tensor and this optimization class.
94 
95     Args:
96         stepsize (float): the user-defined hyperparameter :math:`\eta`
97         diag_approx (bool): If ``True``, forces a diagonal approximation
98             where the calculated metric tensor only contains diagonal
99             elements :math:`G_{ii}`. In some cases, this may reduce the
100             time taken per optimization step.
101         tol (float): tolerance used when finding the inverse of the
102             quantum gradient tensor
103     """
104     def __init__(self, stepsize=0.01, diag_approx=False):
105         super().__init__(stepsize)
106         self.diag_approx = diag_approx
107         self.metric_tensor_inv = None
108 
109     def step(self, qnode, x, recompute_tensor=True):
110         """Update x with one step of the optimizer.
111 
112         Args:
113             qnode (QNode): the QNode for optimization
114             x (array): NumPy array containing the current values of the variables to be updated
115             recompute_tensor (bool): Whether or not the metric tensor should
116                 be recomputed. If not, the metric tensor from the previous
117                 optimization step is used.
118 
119         Returns:
120             array: the new variable values :math:`x^{(t+1)}`
121         """
122         # pylint: disable=arguments-differ
123         if not hasattr(qnode, "metric_tensor"):
124             raise ValueError("Objective function must be encoded as a single QNode")
125 
126         if recompute_tensor or self.metric_tensor is None:
127             # pseudo-inverse metric tensor
128             metric_tensor = qnode.metric_tensor(x, diag_approx=self.diag_approx)
129             self.metric_tensor_inv = linalg.pinv(metric_tensor)
130 
131         g = self.compute_grad(qnode, x)
132         x_out = self.apply_grad(g, x)
133         return x_out
134 
135     def apply_grad(self, grad, x):
136         r"""Update the variables x to take a single optimization step. Flattens and unflattens
137         the inputs to maintain nested iterables as the parameters of the optimization.
138 
139         Args:
140             grad (array): The gradient of the objective
141                 function at point :math:`x^{(t)}`: :math:`\nabla f(x^{(t)})`
142             x (array): the current value of the variables :math:`x^{(t)}`
143 
144         Returns:
145             array: the new values :math:`x^{(t+1)}`
146         """
147         grad_flat = np.array(list(_flatten(grad)))
148         x_flat = np.array(list(_flatten(x)))
149         x_new_flat = x_flat - self._stepsize * self.metric_tensor_inv @ grad_flat
150         return unflatten(x_new_flat, x)
151
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pennylane/optimize/qng.py b/pennylane/optimize/qng.py
--- a/pennylane/optimize/qng.py
+++ b/pennylane/optimize/qng.py
@@ -126,7 +126,7 @@
         if recompute_tensor or self.metric_tensor is None:
             # pseudo-inverse metric tensor
             metric_tensor = qnode.metric_tensor(x, diag_approx=self.diag_approx)
-            self.metric_tensor_inv = linalg.pinv(metric_tensor)
+            self.metric_tensor_inv = linalg.pinvh(metric_tensor)
 
         g = self.compute_grad(qnode, x)
         x_out = self.apply_grad(g, x)

{"golden_diff": "diff --git a/pennylane/optimize/qng.py b/pennylane/optimize/qng.py\n--- a/pennylane/optimize/qng.py\n+++ b/pennylane/optimize/qng.py\n@@ -126,7 +126,7 @@\n         if recompute_tensor or self.metric_tensor is None:\r\n             # pseudo-inverse metric tensor\r\n             metric_tensor = qnode.metric_tensor(x, diag_approx=self.diag_approx)\r\n-            self.metric_tensor_inv = linalg.pinv(metric_tensor)\r\n+            self.metric_tensor_inv = linalg.pinvh(metric_tensor)\r\n \r\n         g = self.compute_grad(qnode, x)\r\n         x_out = self.apply_grad(g, x)\n", "issue": "Investigate alternate matrix pseudo-inverse functions\nThe QGT optimizer makes use of the matrix pseudo-inverse, via the `scipy.linalg.pinv` function. However, there are several alternative functions we could also use:\r\n\r\n* https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinv.html\r\n* https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinv2.html\r\n* https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinvh.html\r\n\r\nIn the case of commuting generators, the block diag metric tensor will be symmetric, so `pinvh`  might be more efficient/stable. This is something worth investigating.\r\n\n", "before_files": [{"content": "# Copyright 2018 Xanadu Quantum Technologies Inc.\r\n\r\n# Licensed under the Apache License, Version 2.0 (the \"License\");\r\n# you may not use this file except in compliance with the License.\r\n# You may obtain a copy of the License at\r\n\r\n#     http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n# Unless required by applicable law or agreed to in writing, software\r\n# distributed under the License is distributed on an \"AS IS\" BASIS,\r\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n# See the License for the specific language governing permissions and\r\n# limitations under the License.\r\n\"\"\"Quantum natural gradient optimizer\"\"\"\r\n#pylint: disable=too-many-branches\r\nimport autograd.numpy as np\r\nfrom scipy import linalg\r\n\r\nfrom pennylane.utils import _flatten, unflatten\r\n\r\nfrom .gradient_descent import GradientDescentOptimizer\r\n\r\n\r\nclass QNGOptimizer(GradientDescentOptimizer):\r\n    r\"\"\"Optimizer with adaptive learning rate, via calculation\r\n    of the diagonal or block-diagonal approximation to the Fubini-Study metric tensor.\r\n    A quantum generalization of natural gradient descent.\r\n\r\n    The QNG optimizer uses a step- and parameter-dependent learning rate,\r\n    with the learning rate dependent on the pseudo-inverse\r\n    of the Fubini-Study metric tensor :math:`g`:\r\n\r\n    .. math::\r\n        x^{(t+1)} = x^{(t)} - \\eta g(f(x^{(t)}))^{-1} \\nabla f(x^{(t)}),\r\n\r\n    where :math:`f(x^{(t)}) = \\langle 0 | U(x^{(t)})^\\dagger \\hat{B} U(x^{(t)}) | 0 \\rangle`\r\n    is an expectation value of some observable measured on the variational\r\n    quantum circuit :math:`U(x^{(t)})`.\r\n\r\n    Consider a quantum node represented by the variational quantum circuit\r\n\r\n    .. math::\r\n\r\n        U(\\mathbf{\\theta}) = W(\\theta_{i+1}, \\dots, \\theta_{N})X(\\theta_{i})\r\n        V(\\theta_1, \\dots, \\theta_{i-1}),\r\n\r\n    where all parametrized gates can be written of the form :math:`X(\\theta_{i}) = e^{i\\theta_i K_i}`.\r\n    That is, the gate :math:`K_i` is the *generator* of the parametrized operation :math:`X(\\theta_i)`\r\n    corresponding to the :math:`i`-th parameter.\r\n\r\n    For each parametric layer :math:`\\ell` in the variational quantum circuit\r\n    containing :math:`n` parameters, the :math:`n\\times n` block-diagonal submatrix\r\n    of the Fubini-Study tensor :math:`g_{ij}^{(\\ell)}` is calculated directly on the\r\n    quantum device in a single evaluation:\r\n\r\n    .. math::\r\n\r\n        g_{ij}^{(\\ell)} = \\langle \\psi_\\ell | K_i K_j | \\psi_\\ell \\rangle\r\n        - \\langle \\psi_\\ell | K_i | \\psi_\\ell\\rangle\r\n        \\langle \\psi_\\ell |K_j | \\psi_\\ell\\rangle\r\n\r\n    where :math:`|\\psi_\\ell\\rangle =  V(\\theta_1, \\dots, \\theta_{i-1})|0\\rangle`\r\n    (that is, :math:`|\\psi_\\ell\\rangle` is the quantum state prior to the application\r\n    of parameterized layer :math:`\\ell`).\r\n\r\n    Combining the quantum natural gradient optimizer with the analytic parameter-shift\r\n    rule to optimize a variational circuit with :math:`d` parameters and :math:`L` layers,\r\n    a total of :math:`2d+L` quantum evaluations are required per optimization step.\r\n\r\n    For more details, see:\r\n\r\n        James Stokes, Josh Izaac, Nathan Killoran, Giuseppe Carleo.\r\n        \"Quantum Natural Gradient.\" `arXiv:1909.02108 <https://arxiv.org/abs/1909.02108>`_, 2019.\r\n\r\n    .. note::\r\n\r\n        The QNG optimizer **only supports single QNodes** as objective functions.\r\n\r\n        In particular:\r\n\r\n        * For hybrid classical-quantum models, the \"mixed geometry\" of the model\r\n          makes it unclear which metric should be used for which parameter.\r\n          For example, parameters of quantum nodes are better suited to\r\n          one metric (such as the QNG), whereas others (e.g., parameters of classical nodes)\r\n          are likely better suited to another metric.\r\n\r\n        * For multi-QNode models, we don't know what geometry is appropriate\r\n          if a parameter is shared amongst several QNodes.\r\n\r\n    .. seealso::\r\n\r\n        See the :ref:`quantum natural gradient example <quantum_natural_gradient>`\r\n        for more details on Fubini-Study metric tensor and this optimization class.\r\n\r\n    Args:\r\n        stepsize (float): the user-defined hyperparameter :math:`\\eta`\r\n        diag_approx (bool): If ``True``, forces a diagonal approximation\r\n            where the calculated metric tensor only contains diagonal\r\n            elements :math:`G_{ii}`. In some cases, this may reduce the\r\n            time taken per optimization step.\r\n        tol (float): tolerance used when finding the inverse of the\r\n            quantum gradient tensor\r\n    \"\"\"\r\n    def __init__(self, stepsize=0.01, diag_approx=False):\r\n        super().__init__(stepsize)\r\n        self.diag_approx = diag_approx\r\n        self.metric_tensor_inv = None\r\n\r\n    def step(self, qnode, x, recompute_tensor=True):\r\n        \"\"\"Update x with one step of the optimizer.\r\n\r\n        Args:\r\n            qnode (QNode): the QNode for optimization\r\n            x (array): NumPy array containing the current values of the variables to be updated\r\n            recompute_tensor (bool): Whether or not the metric tensor should\r\n                be recomputed. If not, the metric tensor from the previous\r\n                optimization step is used.\r\n\r\n        Returns:\r\n            array: the new variable values :math:`x^{(t+1)}`\r\n        \"\"\"\r\n        # pylint: disable=arguments-differ\r\n        if not hasattr(qnode, \"metric_tensor\"):\r\n            raise ValueError(\"Objective function must be encoded as a single QNode\")\r\n\r\n        if recompute_tensor or self.metric_tensor is None:\r\n            # pseudo-inverse metric tensor\r\n            metric_tensor = qnode.metric_tensor(x, diag_approx=self.diag_approx)\r\n            self.metric_tensor_inv = linalg.pinv(metric_tensor)\r\n\r\n        g = self.compute_grad(qnode, x)\r\n        x_out = self.apply_grad(g, x)\r\n        return x_out\r\n\r\n    def apply_grad(self, grad, x):\r\n        r\"\"\"Update the variables x to take a single optimization step. Flattens and unflattens\r\n        the inputs to maintain nested iterables as the parameters of the optimization.\r\n\r\n        Args:\r\n            grad (array): The gradient of the objective\r\n                function at point :math:`x^{(t)}`: :math:`\\nabla f(x^{(t)})`\r\n            x (array): the current value of the variables :math:`x^{(t)}`\r\n\r\n        Returns:\r\n            array: the new values :math:`x^{(t+1)}`\r\n        \"\"\"\r\n        grad_flat = np.array(list(_flatten(grad)))\r\n        x_flat = np.array(list(_flatten(x)))\r\n        x_new_flat = x_flat - self._stepsize * self.metric_tensor_inv @ grad_flat\r\n        return unflatten(x_new_flat, x)\r\n", "path": "pennylane/optimize/qng.py"}], "after_files": [{"content": "# Copyright 2018 Xanadu Quantum Technologies Inc.\r\n\r\n# Licensed under the Apache License, Version 2.0 (the \"License\");\r\n# you may not use this file except in compliance with the License.\r\n# You may obtain a copy of the License at\r\n\r\n#     http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n# Unless required by applicable law or agreed to in writing, software\r\n# distributed under the License is distributed on an \"AS IS\" BASIS,\r\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n# See the License for the specific language governing permissions and\r\n# limitations under the License.\r\n\"\"\"Quantum natural gradient optimizer\"\"\"\r\n#pylint: disable=too-many-branches\r\nimport autograd.numpy as np\r\nfrom scipy import linalg\r\n\r\nfrom pennylane.utils import _flatten, unflatten\r\n\r\nfrom .gradient_descent import GradientDescentOptimizer\r\n\r\n\r\nclass QNGOptimizer(GradientDescentOptimizer):\r\n    r\"\"\"Optimizer with adaptive learning rate, via calculation\r\n    of the diagonal or block-diagonal approximation to the Fubini-Study metric tensor.\r\n    A quantum generalization of natural gradient descent.\r\n\r\n    The QNG optimizer uses a step- and parameter-dependent learning rate,\r\n    with the learning rate dependent on the pseudo-inverse\r\n    of the Fubini-Study metric tensor :math:`g`:\r\n\r\n    .. math::\r\n        x^{(t+1)} = x^{(t)} - \\eta g(f(x^{(t)}))^{-1} \\nabla f(x^{(t)}),\r\n\r\n    where :math:`f(x^{(t)}) = \\langle 0 | U(x^{(t)})^\\dagger \\hat{B} U(x^{(t)}) | 0 \\rangle`\r\n    is an expectation value of some observable measured on the variational\r\n    quantum circuit :math:`U(x^{(t)})`.\r\n\r\n    Consider a quantum node represented by the variational quantum circuit\r\n\r\n    .. math::\r\n\r\n        U(\\mathbf{\\theta}) = W(\\theta_{i+1}, \\dots, \\theta_{N})X(\\theta_{i})\r\n        V(\\theta_1, \\dots, \\theta_{i-1}),\r\n\r\n    where all parametrized gates can be written of the form :math:`X(\\theta_{i}) = e^{i\\theta_i K_i}`.\r\n    That is, the gate :math:`K_i` is the *generator* of the parametrized operation :math:`X(\\theta_i)`\r\n    corresponding to the :math:`i`-th parameter.\r\n\r\n    For each parametric layer :math:`\\ell` in the variational quantum circuit\r\n    containing :math:`n` parameters, the :math:`n\\times n` block-diagonal submatrix\r\n    of the Fubini-Study tensor :math:`g_{ij}^{(\\ell)}` is calculated directly on the\r\n    quantum device in a single evaluation:\r\n\r\n    .. math::\r\n\r\n        g_{ij}^{(\\ell)} = \\langle \\psi_\\ell | K_i K_j | \\psi_\\ell \\rangle\r\n        - \\langle \\psi_\\ell | K_i | \\psi_\\ell\\rangle\r\n        \\langle \\psi_\\ell |K_j | \\psi_\\ell\\rangle\r\n\r\n    where :math:`|\\psi_\\ell\\rangle =  V(\\theta_1, \\dots, \\theta_{i-1})|0\\rangle`\r\n    (that is, :math:`|\\psi_\\ell\\rangle` is the quantum state prior to the application\r\n    of parameterized layer :math:`\\ell`).\r\n\r\n    Combining the quantum natural gradient optimizer with the analytic parameter-shift\r\n    rule to optimize a variational circuit with :math:`d` parameters and :math:`L` layers,\r\n    a total of :math:`2d+L` quantum evaluations are required per optimization step.\r\n\r\n    For more details, see:\r\n\r\n        James Stokes, Josh Izaac, Nathan Killoran, Giuseppe Carleo.\r\n        \"Quantum Natural Gradient.\" `arXiv:1909.02108 <https://arxiv.org/abs/1909.02108>`_, 2019.\r\n\r\n    .. note::\r\n\r\n        The QNG optimizer **only supports single QNodes** as objective functions.\r\n\r\n        In particular:\r\n\r\n        * For hybrid classical-quantum models, the \"mixed geometry\" of the model\r\n          makes it unclear which metric should be used for which parameter.\r\n          For example, parameters of quantum nodes are better suited to\r\n          one metric (such as the QNG), whereas others (e.g., parameters of classical nodes)\r\n          are likely better suited to another metric.\r\n\r\n        * For multi-QNode models, we don't know what geometry is appropriate\r\n          if a parameter is shared amongst several QNodes.\r\n\r\n    .. seealso::\r\n\r\n        See the :ref:`quantum natural gradient example <quantum_natural_gradient>`\r\n        for more details on Fubini-Study metric tensor and this optimization class.\r\n\r\n    Args:\r\n        stepsize (float): the user-defined hyperparameter :math:`\\eta`\r\n        diag_approx (bool): If ``True``, forces a diagonal approximation\r\n            where the calculated metric tensor only contains diagonal\r\n            elements :math:`G_{ii}`. In some cases, this may reduce the\r\n            time taken per optimization step.\r\n        tol (float): tolerance used when finding the inverse of the\r\n            quantum gradient tensor\r\n    \"\"\"\r\n    def __init__(self, stepsize=0.01, diag_approx=False):\r\n        super().__init__(stepsize)\r\n        self.diag_approx = diag_approx\r\n        self.metric_tensor_inv = None\r\n\r\n    def step(self, qnode, x, recompute_tensor=True):\r\n        \"\"\"Update x with one step of the optimizer.\r\n\r\n        Args:\r\n            qnode (QNode): the QNode for optimization\r\n            x (array): NumPy array containing the current values of the variables to be updated\r\n            recompute_tensor (bool): Whether or not the metric tensor should\r\n                be recomputed. If not, the metric tensor from the previous\r\n                optimization step is used.\r\n\r\n        Returns:\r\n            array: the new variable values :math:`x^{(t+1)}`\r\n        \"\"\"\r\n        # pylint: disable=arguments-differ\r\n        if not hasattr(qnode, \"metric_tensor\"):\r\n            raise ValueError(\"Objective function must be encoded as a single QNode\")\r\n\r\n        if recompute_tensor or self.metric_tensor is None:\r\n            # pseudo-inverse metric tensor\r\n            metric_tensor = qnode.metric_tensor(x, diag_approx=self.diag_approx)\r\n            self.metric_tensor_inv = linalg.pinvh(metric_tensor)\r\n\r\n        g = self.compute_grad(qnode, x)\r\n        x_out = self.apply_grad(g, x)\r\n        return x_out\r\n\r\n    def apply_grad(self, grad, x):\r\n        r\"\"\"Update the variables x to take a single optimization step. Flattens and unflattens\r\n        the inputs to maintain nested iterables as the parameters of the optimization.\r\n\r\n        Args:\r\n            grad (array): The gradient of the objective\r\n                function at point :math:`x^{(t)}`: :math:`\\nabla f(x^{(t)})`\r\n            x (array): the current value of the variables :math:`x^{(t)}`\r\n\r\n        Returns:\r\n            array: the new values :math:`x^{(t+1)}`\r\n        \"\"\"\r\n        grad_flat = np.array(list(_flatten(grad)))\r\n        x_flat = np.array(list(_flatten(x)))\r\n        x_new_flat = x_flat - self._stepsize * self.metric_tensor_inv @ grad_flat\r\n        return unflatten(x_new_flat, x)\r\n", "path": "pennylane/optimize/qng.py"}]}