We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`QGTJacobian***(holomorphic=True)` for R->C models returns wrong output. Should error.
cc @attila-i-szabo

I agree that `holomorphic=True` is wrong in that case, but it should rather throw an error than give wrong results...
It took me a while to notice that this was the cause of some wrong optimisations.

```python
import netket as nk
import jax

L = 20
g = nk.graph.Hypercube(length=L, n_dim=1, pbc=True)
hi = nk.hilbert.Spin(s=1 / 2, N=g.n_nodes)
ha = nk.operator.Ising(hilbert=hi, graph=g, h=1.0)
ma = nk.models.RBMModPhase(alpha=1, param_dtype=float)
sa = nk.sampler.MetropolisLocal(hi, n_chains=16)
vs = nk.vqs.MCState(sa, ma, n_samples=1000, n_discard_per_chain=100)

qgt_holo = nk.optimizer.qgt.QGTJacobianDense(holomorphic=True)
qgt_nonholo = nk.optimizer.qgt.QGTJacobianDense(holomorphic=False)
qgt_otf = nk.optimizer.qgt.QGTOnTheFly()

S_holo = vs.quantum_geometric_tensor(qgt_holo)
S_nonholo = vs.quantum_geometric_tensor(qgt_nonholo)
S_otf = vs.quantum_geometric_tensor(qgt_otf)

F = vs.parameters

r_holo = S_holo@F
r_nonholo = S_nonholo@F
r_otf = S_otf@F

jax.tree_map(lambda x,y:x-y, r_holo, r_nonholo)
```
`QGTJacobian***(holomorphic=True)` for R->C models returns wrong output. Should error.
cc @attila-i-szabo

I agree that `holomorphic=True` is wrong in that case, but it should rather throw an error than give wrong results...
It took me a while to notice that this was the cause of some wrong optimisations.

```python
import netket as nk
import jax

L = 20
g = nk.graph.Hypercube(length=L, n_dim=1, pbc=True)
hi = nk.hilbert.Spin(s=1 / 2, N=g.n_nodes)
ha = nk.operator.Ising(hilbert=hi, graph=g, h=1.0)
ma = nk.models.RBMModPhase(alpha=1, param_dtype=float)
sa = nk.sampler.MetropolisLocal(hi, n_chains=16)
vs = nk.vqs.MCState(sa, ma, n_samples=1000, n_discard_per_chain=100)

qgt_holo = nk.optimizer.qgt.QGTJacobianDense(holomorphic=True)
qgt_nonholo = nk.optimizer.qgt.QGTJacobianDense(holomorphic=False)
qgt_otf = nk.optimizer.qgt.QGTOnTheFly()

S_holo = vs.quantum_geometric_tensor(qgt_holo)
S_nonholo = vs.quantum_geometric_tensor(qgt_nonholo)
S_otf = vs.quantum_geometric_tensor(qgt_otf)

F = vs.parameters

r_holo = S_holo@F
r_nonholo = S_nonholo@F
r_otf = S_otf@F

jax.tree_map(lambda x,y:x-y, r_holo, r_nonholo)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `netket/optimizer/qgt/qgt_jacobian_common.py`
Content:
```
1 # Copyright 2021 The NetKet Authors - All rights reserved.
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 
15 from functools import partial
16 import warnings
17 from textwrap import dedent
18 
19 import jax
20 
21 import netket.jax as nkjax
22 
23 
24 @partial(jax.jit, static_argnums=(0, 4, 5))
25 def _choose_jacobian_mode(apply_fun, pars, model_state, samples, mode, holomorphic):
26     homogeneous_vars = nkjax.tree_ishomogeneous(pars)
27 
28     if holomorphic is True:
29         if not homogeneous_vars:
30             warnings.warn(
31                 dedent(
32                     """The ansatz has non homogeneous variables, which might not behave well with the
33                        holomorhic implementation.
34                        Use `holomorphic=False` or mode='complex' for more accurate results but
35                        lower performance.
36                     """
37                 )
38             )
39         mode = "holomorphic"
40     else:
41         leaf_iscomplex = nkjax.tree_leaf_iscomplex(pars)
42         complex_output = nkjax.is_complex(
43             jax.eval_shape(
44                 apply_fun,
45                 {"params": pars, **model_state},
46                 samples.reshape(-1, samples.shape[-1]),
47             )
48         )
49 
50         if complex_output:
51             if leaf_iscomplex:
52                 if holomorphic is None:
53                     warnings.warn(
54                         dedent(
55                             """
56                                 Complex-to-Complex model detected. Defaulting to `holomorphic=False` for
57                                 the implementation of QGTJacobianDense.
58                                 If your model is holomorphic, specify `holomorphic=True` to use a more
59                                 performant implementation.
60                                 To suppress this warning specify `holomorphic`.
61                                 """
62                         ),
63                         UserWarning,
64                     )
65                 mode = "complex"
66             else:
67                 mode = "complex"
68         else:
69             mode = "real"
70 
71     if mode == "real":
72         return 0
73     elif mode == "complex":
74         return 1
75     elif mode == "holomorphic":
76         return 2
77     else:
78         raise ValueError(f"unknown mode {mode}")
79 
80 
81 def choose_jacobian_mode(afun, pars, state, samples, *, mode, holomorphic):
82     """
83     Select an implementation of Jacobian
84     """
85     i = _choose_jacobian_mode(afun, pars, state, samples, mode, holomorphic).item()
86     if i == 0:
87         return "real"
88     elif i == 1:
89         return "complex"
90     elif i == 2:
91         return "holomorphic"
92     else:
93         raise ValueError(f"unknown mode {i}")
94
```
--- 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/netket/optimizer/qgt/qgt_jacobian_common.py b/netket/optimizer/qgt/qgt_jacobian_common.py
--- a/netket/optimizer/qgt/qgt_jacobian_common.py
+++ b/netket/optimizer/qgt/qgt_jacobian_common.py
@@ -24,21 +24,37 @@
 @partial(jax.jit, static_argnums=(0, 4, 5))
 def _choose_jacobian_mode(apply_fun, pars, model_state, samples, mode, holomorphic):
     homogeneous_vars = nkjax.tree_ishomogeneous(pars)
+    leaf_iscomplex = nkjax.tree_leaf_iscomplex(pars)
 
     if holomorphic is True:
-        if not homogeneous_vars:
+        if homogeneous_vars and leaf_iscomplex:
+            ## all complex parameters
+            mode = "holomorphic"
+        elif homogeneous_vars and not leaf_iscomplex:
+            # all real parameters
+            raise ValueError(
+                dedent(
+                    """
+                A function with real parameters cannot be holomorphic. 
+                
+                Please remove the kw-arg `holomorphic=True`.
+                """
+                )
+            )
+        else:
+            # mixed complex and real parameters
             warnings.warn(
                 dedent(
                     """The ansatz has non homogeneous variables, which might not behave well with the
                        holomorhic implementation.
+
                        Use `holomorphic=False` or mode='complex' for more accurate results but
                        lower performance.
                     """
                 )
             )
-        mode = "holomorphic"
+            mode = "holomorphic"
     else:
-        leaf_iscomplex = nkjax.tree_leaf_iscomplex(pars)
         complex_output = nkjax.is_complex(
             jax.eval_shape(
                 apply_fun,

{"golden_diff": "diff --git a/netket/optimizer/qgt/qgt_jacobian_common.py b/netket/optimizer/qgt/qgt_jacobian_common.py\n--- a/netket/optimizer/qgt/qgt_jacobian_common.py\n+++ b/netket/optimizer/qgt/qgt_jacobian_common.py\n@@ -24,21 +24,37 @@\n @partial(jax.jit, static_argnums=(0, 4, 5))\n def _choose_jacobian_mode(apply_fun, pars, model_state, samples, mode, holomorphic):\n     homogeneous_vars = nkjax.tree_ishomogeneous(pars)\n+    leaf_iscomplex = nkjax.tree_leaf_iscomplex(pars)\n \n     if holomorphic is True:\n-        if not homogeneous_vars:\n+        if homogeneous_vars and leaf_iscomplex:\n+            ## all complex parameters\n+            mode = \"holomorphic\"\n+        elif homogeneous_vars and not leaf_iscomplex:\n+            # all real parameters\n+            raise ValueError(\n+                dedent(\n+                    \"\"\"\n+                A function with real parameters cannot be holomorphic. \n+                \n+                Please remove the kw-arg `holomorphic=True`.\n+                \"\"\"\n+                )\n+            )\n+        else:\n+            # mixed complex and real parameters\n             warnings.warn(\n                 dedent(\n                     \"\"\"The ansatz has non homogeneous variables, which might not behave well with the\n                        holomorhic implementation.\n+\n                        Use `holomorphic=False` or mode='complex' for more accurate results but\n                        lower performance.\n                     \"\"\"\n                 )\n             )\n-        mode = \"holomorphic\"\n+            mode = \"holomorphic\"\n     else:\n-        leaf_iscomplex = nkjax.tree_leaf_iscomplex(pars)\n         complex_output = nkjax.is_complex(\n             jax.eval_shape(\n                 apply_fun,\n", "issue": "`QGTJacobian***(holomorphic=True)` for R->C models returns wrong output. Should error.\ncc @attila-i-szabo\r\n\r\nI agree that `holomorphic=True`\u00a0is wrong in that case, but it should rather throw an error than give wrong results...\r\nIt took me a while to notice that this was the cause of some wrong optimisations.\r\n\r\n```python\r\nimport netket as nk\r\nimport jax\r\n\r\nL = 20\r\ng = nk.graph.Hypercube(length=L, n_dim=1, pbc=True)\r\nhi = nk.hilbert.Spin(s=1 / 2, N=g.n_nodes)\r\nha = nk.operator.Ising(hilbert=hi, graph=g, h=1.0)\r\nma = nk.models.RBMModPhase(alpha=1, param_dtype=float)\r\nsa = nk.sampler.MetropolisLocal(hi, n_chains=16)\r\nvs = nk.vqs.MCState(sa, ma, n_samples=1000, n_discard_per_chain=100)\r\n\r\nqgt_holo = nk.optimizer.qgt.QGTJacobianDense(holomorphic=True)\r\nqgt_nonholo = nk.optimizer.qgt.QGTJacobianDense(holomorphic=False)\r\nqgt_otf = nk.optimizer.qgt.QGTOnTheFly()\r\n\r\nS_holo = vs.quantum_geometric_tensor(qgt_holo)\r\nS_nonholo = vs.quantum_geometric_tensor(qgt_nonholo)\r\nS_otf = vs.quantum_geometric_tensor(qgt_otf)\r\n\r\nF = vs.parameters\r\n\r\nr_holo = S_holo@F\r\nr_nonholo = S_nonholo@F\r\nr_otf = S_otf@F\r\n\r\njax.tree_map(lambda x,y:x-y, r_holo, r_nonholo)\r\n```\n`QGTJacobian***(holomorphic=True)` for R->C models returns wrong output. Should error.\ncc @attila-i-szabo\r\n\r\nI agree that `holomorphic=True`\u00a0is wrong in that case, but it should rather throw an error than give wrong results...\r\nIt took me a while to notice that this was the cause of some wrong optimisations.\r\n\r\n```python\r\nimport netket as nk\r\nimport jax\r\n\r\nL = 20\r\ng = nk.graph.Hypercube(length=L, n_dim=1, pbc=True)\r\nhi = nk.hilbert.Spin(s=1 / 2, N=g.n_nodes)\r\nha = nk.operator.Ising(hilbert=hi, graph=g, h=1.0)\r\nma = nk.models.RBMModPhase(alpha=1, param_dtype=float)\r\nsa = nk.sampler.MetropolisLocal(hi, n_chains=16)\r\nvs = nk.vqs.MCState(sa, ma, n_samples=1000, n_discard_per_chain=100)\r\n\r\nqgt_holo = nk.optimizer.qgt.QGTJacobianDense(holomorphic=True)\r\nqgt_nonholo = nk.optimizer.qgt.QGTJacobianDense(holomorphic=False)\r\nqgt_otf = nk.optimizer.qgt.QGTOnTheFly()\r\n\r\nS_holo = vs.quantum_geometric_tensor(qgt_holo)\r\nS_nonholo = vs.quantum_geometric_tensor(qgt_nonholo)\r\nS_otf = vs.quantum_geometric_tensor(qgt_otf)\r\n\r\nF = vs.parameters\r\n\r\nr_holo = S_holo@F\r\nr_nonholo = S_nonholo@F\r\nr_otf = S_otf@F\r\n\r\njax.tree_map(lambda x,y:x-y, r_holo, r_nonholo)\r\n```\n", "before_files": [{"content": "# Copyright 2021 The NetKet Authors - All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom functools import partial\nimport warnings\nfrom textwrap import dedent\n\nimport jax\n\nimport netket.jax as nkjax\n\n\n@partial(jax.jit, static_argnums=(0, 4, 5))\ndef _choose_jacobian_mode(apply_fun, pars, model_state, samples, mode, holomorphic):\n    homogeneous_vars = nkjax.tree_ishomogeneous(pars)\n\n    if holomorphic is True:\n        if not homogeneous_vars:\n            warnings.warn(\n                dedent(\n                    \"\"\"The ansatz has non homogeneous variables, which might not behave well with the\n                       holomorhic implementation.\n                       Use `holomorphic=False` or mode='complex' for more accurate results but\n                       lower performance.\n                    \"\"\"\n                )\n            )\n        mode = \"holomorphic\"\n    else:\n        leaf_iscomplex = nkjax.tree_leaf_iscomplex(pars)\n        complex_output = nkjax.is_complex(\n            jax.eval_shape(\n                apply_fun,\n                {\"params\": pars, **model_state},\n                samples.reshape(-1, samples.shape[-1]),\n            )\n        )\n\n        if complex_output:\n            if leaf_iscomplex:\n                if holomorphic is None:\n                    warnings.warn(\n                        dedent(\n                            \"\"\"\n                                Complex-to-Complex model detected. Defaulting to `holomorphic=False` for\n                                the implementation of QGTJacobianDense.\n                                If your model is holomorphic, specify `holomorphic=True` to use a more\n                                performant implementation.\n                                To suppress this warning specify `holomorphic`.\n                                \"\"\"\n                        ),\n                        UserWarning,\n                    )\n                mode = \"complex\"\n            else:\n                mode = \"complex\"\n        else:\n            mode = \"real\"\n\n    if mode == \"real\":\n        return 0\n    elif mode == \"complex\":\n        return 1\n    elif mode == \"holomorphic\":\n        return 2\n    else:\n        raise ValueError(f\"unknown mode {mode}\")\n\n\ndef choose_jacobian_mode(afun, pars, state, samples, *, mode, holomorphic):\n    \"\"\"\n    Select an implementation of Jacobian\n    \"\"\"\n    i = _choose_jacobian_mode(afun, pars, state, samples, mode, holomorphic).item()\n    if i == 0:\n        return \"real\"\n    elif i == 1:\n        return \"complex\"\n    elif i == 2:\n        return \"holomorphic\"\n    else:\n        raise ValueError(f\"unknown mode {i}\")\n", "path": "netket/optimizer/qgt/qgt_jacobian_common.py"}], "after_files": [{"content": "# Copyright 2021 The NetKet Authors - All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom functools import partial\nimport warnings\nfrom textwrap import dedent\n\nimport jax\n\nimport netket.jax as nkjax\n\n\n@partial(jax.jit, static_argnums=(0, 4, 5))\ndef _choose_jacobian_mode(apply_fun, pars, model_state, samples, mode, holomorphic):\n    homogeneous_vars = nkjax.tree_ishomogeneous(pars)\n    leaf_iscomplex = nkjax.tree_leaf_iscomplex(pars)\n\n    if holomorphic is True:\n        if homogeneous_vars and leaf_iscomplex:\n            ## all complex parameters\n            mode = \"holomorphic\"\n        elif homogeneous_vars and not leaf_iscomplex:\n            # all real parameters\n            raise ValueError(\n                dedent(\n                    \"\"\"\n                A function with real parameters cannot be holomorphic. \n                \n                Please remove the kw-arg `holomorphic=True`.\n                \"\"\"\n                )\n            )\n        else:\n            # mixed complex and real parameters\n            warnings.warn(\n                dedent(\n                    \"\"\"The ansatz has non homogeneous variables, which might not behave well with the\n                       holomorhic implementation.\n\n                       Use `holomorphic=False` or mode='complex' for more accurate results but\n                       lower performance.\n                    \"\"\"\n                )\n            )\n            mode = \"holomorphic\"\n    else:\n        complex_output = nkjax.is_complex(\n            jax.eval_shape(\n                apply_fun,\n                {\"params\": pars, **model_state},\n                samples.reshape(-1, samples.shape[-1]),\n            )\n        )\n\n        if complex_output:\n            if leaf_iscomplex:\n                if holomorphic is None:\n                    warnings.warn(\n                        dedent(\n                            \"\"\"\n                                Complex-to-Complex model detected. Defaulting to `holomorphic=False` for\n                                the implementation of QGTJacobianDense.\n                                If your model is holomorphic, specify `holomorphic=True` to use a more\n                                performant implementation.\n                                To suppress this warning specify `holomorphic`.\n                                \"\"\"\n                        ),\n                        UserWarning,\n                    )\n                mode = \"complex\"\n            else:\n                mode = \"complex\"\n        else:\n            mode = \"real\"\n\n    if mode == \"real\":\n        return 0\n    elif mode == \"complex\":\n        return 1\n    elif mode == \"holomorphic\":\n        return 2\n    else:\n        raise ValueError(f\"unknown mode {mode}\")\n\n\ndef choose_jacobian_mode(afun, pars, state, samples, *, mode, holomorphic):\n    \"\"\"\n    Select an implementation of Jacobian\n    \"\"\"\n    i = _choose_jacobian_mode(afun, pars, state, samples, mode, holomorphic).item()\n    if i == 0:\n        return \"real\"\n    elif i == 1:\n        return \"complex\"\n    elif i == 2:\n        return \"holomorphic\"\n    else:\n        raise ValueError(f\"unknown mode {i}\")\n", "path": "netket/optimizer/qgt/qgt_jacobian_common.py"}]}