prompt: 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()
  
  ```
  
golden_diff: 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,
  
verification_info: {"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"}]}