quantax 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quantax-0.2.0/quantax.egg-info → quantax-0.2.1}/PKG-INFO +3 -3
- {quantax-0.2.0 → quantax-0.2.1}/README.md +22 -12
- {quantax-0.2.0 → quantax-0.2.1}/docs/source/conf.py +1 -1
- {quantax-0.2.0 → quantax-0.2.1}/pyproject.toml +3 -3
- {quantax-0.2.0 → quantax-0.2.1}/quantax/model/conv_nets.py +9 -2
- {quantax-0.2.0 → quantax-0.2.1}/quantax/nn/modules.py +5 -4
- {quantax-0.2.0 → quantax-0.2.1}/quantax/optimizer/__init__.py +1 -1
- {quantax-0.2.0 → quantax-0.2.1}/quantax/optimizer/driver.py +13 -10
- {quantax-0.2.0 → quantax-0.2.1}/quantax/optimizer/sr.py +1 -1
- {quantax-0.2.0 → quantax-0.2.1}/quantax/optimizer/time_evol.py +24 -38
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sampler/metropolis.py +4 -9
- {quantax-0.2.0 → quantax-0.2.1}/quantax/state/variational.py +49 -23
- {quantax-0.2.0 → quantax-0.2.1}/quantax/utils/__init__.py +1 -1
- {quantax-0.2.0 → quantax-0.2.1}/quantax/utils/function.py +38 -6
- {quantax-0.2.0 → quantax-0.2.1/quantax.egg-info}/PKG-INFO +3 -3
- {quantax-0.2.0 → quantax-0.2.1}/quantax.egg-info/requires.txt +2 -2
- {quantax-0.2.0 → quantax-0.2.1}/LICENSE +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/__init__.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/global_defs.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/model/__init__.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/model/backflow.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/model/fermion_mf.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/model/jastrow.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/model/shallow_nets.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/model/transformer.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/model/triangular_nets.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/nn/__init__.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/nn/activation.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/nn/conv.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/nn/fermion.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/nn/initializers.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/nn/sign.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/operator/__init__.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/operator/common_operators.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/operator/operator.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/operator/site_operator.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/optimizer/solver.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/optimizer/supervised.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sampler/__init__.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sampler/common_samplers.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sampler/sampler.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sampler/samples.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sites/__init__.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sites/cluster.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sites/common_lattices.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sites/lattice.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/sites/sites.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/state/__init__.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/state/fermion_mf.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/state/lanczos.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/state/state.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/symmetry/__init__.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/symmetry/common_symmetries.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/symmetry/symmetry.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/symmetry/translation.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/utils/array.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/utils/basis.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/utils/big_array.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/utils/data.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/utils/sharding.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax/utils/tree.py +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax.egg-info/SOURCES.txt +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax.egg-info/dependency_links.txt +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/quantax.egg-info/top_level.txt +0 -0
- {quantax-0.2.0 → quantax-0.2.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantax
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Flexible neural quantum states based on JAX
|
|
5
5
|
Author: Christopher Roth
|
|
6
6
|
Author-email: Ao Chen <chenao.phys@gmail.com>
|
|
@@ -8,7 +8,7 @@ Requires-Python: <=3.13,>=3.10
|
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Requires-Dist: numpy>=1.26.0
|
|
10
10
|
Requires-Dist: scipy>=1.11.1
|
|
11
|
-
Requires-Dist: jax>=0.
|
|
11
|
+
Requires-Dist: jax>=0.6.1
|
|
12
12
|
Requires-Dist: equinox>=0.11.4
|
|
13
13
|
Requires-Dist: lrux>=0.1.0
|
|
14
14
|
Provides-Extra: full
|
|
@@ -16,7 +16,7 @@ Requires-Dist: numpy>=2.0.0; extra == "full"
|
|
|
16
16
|
Requires-Dist: scipy>=1.13.1; extra == "full"
|
|
17
17
|
Requires-Dist: matplotlib>=3.8.0; extra == "full"
|
|
18
18
|
Requires-Dist: quspin>=1.0.0; extra == "full"
|
|
19
|
-
Requires-Dist: jax>=0.
|
|
19
|
+
Requires-Dist: jax>=0.6.1; extra == "full"
|
|
20
20
|
Requires-Dist: equinox>=0.11.4; extra == "full"
|
|
21
21
|
Requires-Dist: lrux>=0.1.0; extra == "full"
|
|
22
22
|
Dynamic: license-file
|
|
@@ -1,34 +1,43 @@
|
|
|
1
1
|
<h1 align='center'>Quantax</h1>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>Flexible and scalable neural quantum states built on JAX</strong>
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://chenao-phys.github.io/quantax">📖 Documentation</a>
|
|
9
|
+
</p>
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
---
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
|
|
14
|
+
## 🔍Scope
|
|
15
|
+
|
|
16
|
+
Quantax is a research-oriented Python package for quantum many-body physics, with a focus on flexible and scalable neural quantum states (NQS). Apart from NQS, Quantax also includes several useful techniques in variational Monte Carlo (VMC):
|
|
17
|
+
|
|
18
|
+
- Exact diagonalization and small-system benchmarks via [QuSpin](https://github.com/QuSpin/QuSpin)
|
|
10
19
|
- Fermionic mean-field wavefunctions
|
|
11
|
-
- Flexible neural
|
|
20
|
+
- Flexible (neural) wavefunction design via [Equinox](https://github.com/patrick-kidger/equinox)
|
|
21
|
+
- Tensor networks via [quimb](https://github.com/jcmgray/quimb/tree/main) and [symmray](https://github.com/jcmgray/symmray) (to be implemented)
|
|
12
22
|
|
|
13
|
-
## Installation
|
|
23
|
+
## ⚙️Installation
|
|
14
24
|
|
|
15
|
-
Requires Python 3.10+, JAX 0.
|
|
25
|
+
Requires Python 3.10+, JAX 0.6.1+
|
|
16
26
|
|
|
17
|
-
First, ensure that a correct JAX version is installed.
|
|
18
|
-
For details, check [JAX Installation](https://docs.jax.dev/en/latest/installation.html).
|
|
27
|
+
First, ensure that a correct JAX version is installed. For details, check [JAX Installation](https://docs.jax.dev/en/latest/installation.html).
|
|
19
28
|
|
|
20
29
|
For a direct installation of full functionality (recommended in most cases),
|
|
21
|
-
```
|
|
30
|
+
```bash
|
|
22
31
|
pip install quantax[full]
|
|
23
32
|
```
|
|
24
33
|
|
|
25
34
|
For a minimal installation,
|
|
26
|
-
```
|
|
35
|
+
```bash
|
|
27
36
|
pip install quantax
|
|
28
37
|
```
|
|
29
38
|
|
|
30
39
|
|
|
31
|
-
## Quick Start
|
|
40
|
+
## 🚀Quick Start
|
|
32
41
|
|
|
33
42
|
```python
|
|
34
43
|
import quantax as qtx
|
|
@@ -65,3 +74,4 @@ for i in range(100):
|
|
|
65
74
|
energy_data.plot(baseline=E)
|
|
66
75
|
plt.show()
|
|
67
76
|
```
|
|
77
|
+

|
|
@@ -14,7 +14,7 @@ sys.path.insert(0, pathlib.Path(__file__).parents[2].resolve().as_posix())
|
|
|
14
14
|
project = "Quantax"
|
|
15
15
|
copyright = "2025, Ao Chen"
|
|
16
16
|
author = "Ao Chen, Christopher Roth"
|
|
17
|
-
release = "0.2.
|
|
17
|
+
release = "0.2.1"
|
|
18
18
|
|
|
19
19
|
# -- General configuration ---------------------------------------------------
|
|
20
20
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quantax"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Flexible neural quantum states based on JAX"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Ao Chen", email = "chenao.phys@gmail.com" },
|
|
@@ -14,7 +14,7 @@ requires-python = ">=3.10,<=3.13"
|
|
|
14
14
|
dependencies = [
|
|
15
15
|
"numpy>=1.26.0",
|
|
16
16
|
"scipy>=1.11.1",
|
|
17
|
-
"jax>=0.
|
|
17
|
+
"jax>=0.6.1",
|
|
18
18
|
"equinox>=0.11.4",
|
|
19
19
|
"lrux>=0.1.0",
|
|
20
20
|
]
|
|
@@ -25,7 +25,7 @@ full = [
|
|
|
25
25
|
"scipy>=1.13.1",
|
|
26
26
|
"matplotlib>=3.8.0",
|
|
27
27
|
"quspin>=1.0.0",
|
|
28
|
-
"jax>=0.
|
|
28
|
+
"jax>=0.6.1",
|
|
29
29
|
"equinox>=0.11.4",
|
|
30
30
|
"lrux>=0.1.0",
|
|
31
31
|
]
|
|
@@ -93,6 +93,8 @@ class _ConvBlock(eqx.Module):
|
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
class ResConv(Sequential):
|
|
96
|
+
"""Deep convolutional residual network."""
|
|
97
|
+
|
|
96
98
|
nblocks: int
|
|
97
99
|
channels: int
|
|
98
100
|
kernel_size: Union[int, Sequence[int]]
|
|
@@ -133,10 +135,15 @@ class ResConv(Sequential):
|
|
|
133
135
|
The translation symmetry to be applied in the last layer, see `~quantax.nn.ConvSymmetrize`.
|
|
134
136
|
|
|
135
137
|
:param dtype:
|
|
136
|
-
The data type of the parameters.
|
|
138
|
+
The data type of the parameters. Must be a real dtype.
|
|
139
|
+
|
|
140
|
+
:param out_dtype:
|
|
141
|
+
The data type of the output wavefunction. By default, it is the same as `dtype`.
|
|
142
|
+
If `out_dtype` is complex, `~quantax.nn.pair_cpl` will be applied to the output
|
|
143
|
+
of convolutional layers to make the final output complex.
|
|
137
144
|
|
|
138
145
|
.. tip::
|
|
139
|
-
This is the recommended architecture for deep
|
|
146
|
+
This is the recommended architecture for deep NQS in spin systems.
|
|
140
147
|
"""
|
|
141
148
|
if jnp.issubdtype(dtype, jnp.complexfloating):
|
|
142
149
|
raise ValueError("`ResSum` doesn't support complex dtypes.")
|
|
@@ -3,6 +3,7 @@ from typing import Sequence, Tuple, Union, Callable
|
|
|
3
3
|
from jaxtyping import PyTree
|
|
4
4
|
import jax
|
|
5
5
|
import equinox as eqx
|
|
6
|
+
from ..utils import PsiArray
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class Sequential(eqx.nn.Sequential):
|
|
@@ -35,7 +36,7 @@ class Sequential(eqx.nn.Sequential):
|
|
|
35
36
|
super().__init__(layers)
|
|
36
37
|
self.holomorphic = holomorphic
|
|
37
38
|
|
|
38
|
-
def __call__(self, x: jax.Array, *, s: jax.Array = None) ->
|
|
39
|
+
def __call__(self, x: jax.Array, *, s: jax.Array = None) -> PsiArray:
|
|
39
40
|
"""**Arguments:**
|
|
40
41
|
|
|
41
42
|
- `x`: passed to the first member of the sequence.
|
|
@@ -74,7 +75,7 @@ class RawInputLayer(eqx.Module):
|
|
|
74
75
|
basis state.
|
|
75
76
|
"""
|
|
76
77
|
|
|
77
|
-
def __call__(self, x: jax.Array, s: jax.Array) ->
|
|
78
|
+
def __call__(self, x: jax.Array, s: jax.Array) -> Callable:
|
|
78
79
|
"""
|
|
79
80
|
The forward pass.
|
|
80
81
|
|
|
@@ -97,7 +98,7 @@ class RefModel(eqx.Module):
|
|
|
97
98
|
Return initial internal values for the given configuration.
|
|
98
99
|
"""
|
|
99
100
|
|
|
100
|
-
def __call__(self, x: jax.Array) ->
|
|
101
|
+
def __call__(self, x: jax.Array) -> PsiArray:
|
|
101
102
|
"""
|
|
102
103
|
Usual forward pass without internal quantities.
|
|
103
104
|
"""
|
|
@@ -109,7 +110,7 @@ class RefModel(eqx.Module):
|
|
|
109
110
|
nflips: int,
|
|
110
111
|
internal: PyTree,
|
|
111
112
|
return_update: bool = False,
|
|
112
|
-
) -> Union[
|
|
113
|
+
) -> Union[PsiArray, Tuple[PsiArray, PyTree]]:
|
|
113
114
|
"""
|
|
114
115
|
Accelerated forward pass through local updates and internal quantities.
|
|
115
116
|
|
|
@@ -7,7 +7,7 @@ from ..sampler import Sampler
|
|
|
7
7
|
from ..utils import DataTracer
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class Driver
|
|
10
|
+
class Driver:
|
|
11
11
|
def __init__(
|
|
12
12
|
self,
|
|
13
13
|
state: Variational,
|
|
@@ -26,8 +26,10 @@ class Driver():
|
|
|
26
26
|
def step(self) -> None:
|
|
27
27
|
"""iteration"""
|
|
28
28
|
|
|
29
|
+
|
|
29
30
|
class Euler(Driver):
|
|
30
31
|
"""First order Euler driver"""
|
|
32
|
+
|
|
31
33
|
def step(self) -> None:
|
|
32
34
|
samples = self._sampler.sweep()
|
|
33
35
|
step = self._optimizer.get_step(samples)
|
|
@@ -39,6 +41,7 @@ class Euler(Driver):
|
|
|
39
41
|
|
|
40
42
|
class AdaptiveHeunEvolution(Driver):
|
|
41
43
|
"""Adaptive second order Heun driver, designed for unitary time-evolution"""
|
|
44
|
+
|
|
42
45
|
def __init__(
|
|
43
46
|
self,
|
|
44
47
|
state: Variational,
|
|
@@ -57,13 +60,13 @@ class AdaptiveHeunEvolution(Driver):
|
|
|
57
60
|
|
|
58
61
|
samples = self._sampler.sweep()
|
|
59
62
|
stepi = tdvp.get_step(samples)
|
|
60
|
-
self._state.update(dt * stepi
|
|
63
|
+
self._state.update(dt * stepi)
|
|
61
64
|
dtheta0_i = 1j * tdvp.energy - jnp.dot(tdvp._Omean, stepi)
|
|
62
|
-
|
|
65
|
+
|
|
63
66
|
samples = self._sampler.sweep()
|
|
64
67
|
stepf = tdvp.get_step(samples)
|
|
65
68
|
step1 = (stepi + stepf) / 2
|
|
66
|
-
self._state.update(-dt / 2 * stepi
|
|
69
|
+
self._state.update(-dt / 2 * stepi)
|
|
67
70
|
|
|
68
71
|
samples = self._sampler.sweep()
|
|
69
72
|
stepm = tdvp.get_step(samples)
|
|
@@ -72,18 +75,18 @@ class AdaptiveHeunEvolution(Driver):
|
|
|
72
75
|
|
|
73
76
|
samples = self._sampler.sweep()
|
|
74
77
|
stepmm = tdvp.get_step(samples)
|
|
75
|
-
self._state.update(dt / 2 * stepmm
|
|
78
|
+
self._state.update(dt / 2 * stepmm)
|
|
76
79
|
dtheta0_mm = 1j * tdvp.energy - jnp.dot(tdvp._Omean, stepmm)
|
|
77
80
|
|
|
78
81
|
samples = self._sampler.sweep()
|
|
79
82
|
Smat, Fvec = tdvp.get_SF(samples)
|
|
80
83
|
stepff = tdvp.solve(Smat, Fvec)
|
|
81
|
-
self._state.update(dt / 4 * (stepff - stepmm)
|
|
84
|
+
self._state.update(dt / 4 * (stepff - stepmm))
|
|
82
85
|
dtheta0_ff = 1j * tdvp.energy - jnp.dot(tdvp._Omean, stepff)
|
|
83
86
|
step2 = (stepi + stepm + stepmm + stepff) / 4
|
|
84
87
|
|
|
85
|
-
dtheta0 = dt * (dtheta0_i + dtheta0_m + dtheta0_mm + dtheta0_ff) / 4
|
|
86
|
-
self._state.rescale(dtheta0)
|
|
88
|
+
# dtheta0 = dt * (dtheta0_i + dtheta0_m + dtheta0_mm + dtheta0_ff) / 4
|
|
89
|
+
# self._state.rescale(dtheta0)
|
|
87
90
|
|
|
88
91
|
diff = step1 - step2
|
|
89
92
|
new_err = jnp.einsum("k,kq,q", diff.conj(), Smat, diff).real
|
|
@@ -95,5 +98,5 @@ class AdaptiveHeunEvolution(Driver):
|
|
|
95
98
|
self._step_length = new_step_length
|
|
96
99
|
|
|
97
100
|
self.step_size.append(new_step_length, self._time)
|
|
98
|
-
self.energy.append(
|
|
99
|
-
self.VarE.append(
|
|
101
|
+
self.energy.append(tdvp.energy, self._time)
|
|
102
|
+
self.VarE.append(tdvp.VarE, self._time)
|
|
@@ -491,7 +491,7 @@ class ER(QNGD):
|
|
|
491
491
|
energy = dense @ H_psi
|
|
492
492
|
Ebar = H_psi - dense * energy
|
|
493
493
|
self._energy = energy.real
|
|
494
|
-
return Ebar.psi
|
|
494
|
+
return jnp.asarray(Ebar.psi)
|
|
495
495
|
|
|
496
496
|
def get_Obar(self, psi: jax.Array) -> jax.Array:
|
|
497
497
|
r"""Compute :math:`\bar O` in the full Hilbert space."""
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
from typing import
|
|
2
|
-
from numbers import Number
|
|
1
|
+
from typing import Tuple, Optional, Callable
|
|
3
2
|
from functools import partial
|
|
4
|
-
import numpy as np
|
|
5
3
|
import jax
|
|
6
4
|
import jax.numpy as jnp
|
|
7
5
|
|
|
8
6
|
from .sr import SR
|
|
9
7
|
from .solver import pinvh_solve
|
|
10
|
-
from ..state import
|
|
8
|
+
from ..state import Variational, VS_TYPE
|
|
11
9
|
from ..operator import Operator
|
|
12
10
|
from ..sampler import Samples
|
|
13
11
|
from ..utils import get_distribute_sharding, array_extend
|
|
@@ -26,18 +24,40 @@ def _AconjB(A: jax.Array, B: jax.Array) -> jax.Array:
|
|
|
26
24
|
|
|
27
25
|
|
|
28
26
|
class TimeEvol(SR):
|
|
27
|
+
r"""
|
|
28
|
+
Time evolution optimizer, equivalent to real-time `~quantax.optimizer.SR`.
|
|
29
|
+
This optimizer assumes the number of samples is more than the number of parameters,
|
|
30
|
+
and is more memory-efficient than `~quantax.optimizer.SR` when this is the case.
|
|
31
|
+
"""
|
|
32
|
+
|
|
29
33
|
def __init__(
|
|
30
34
|
self,
|
|
31
35
|
state: Variational,
|
|
32
36
|
hamiltonian: Operator,
|
|
33
37
|
solver: Optional[Callable] = None,
|
|
34
38
|
):
|
|
39
|
+
r"""
|
|
40
|
+
:param state:
|
|
41
|
+
Variational state to be evolved.
|
|
42
|
+
|
|
43
|
+
:param hamiltonian:
|
|
44
|
+
Hamiltonian operator for time evolution.
|
|
45
|
+
|
|
46
|
+
:param solver:
|
|
47
|
+
The numerical solver for :math:`Sx = F`, default to pseudo-inverse.
|
|
48
|
+
"""
|
|
49
|
+
|
|
35
50
|
if solver is None:
|
|
36
51
|
solver = pinvh_solve()
|
|
37
52
|
super().__init__(state, hamiltonian, imag_time=False, solver=solver)
|
|
38
53
|
self._max_parallel = state._backward_chunk
|
|
39
54
|
|
|
40
55
|
def get_SF(self, samples: Samples) -> Tuple[jax.Array, jax.Array]:
|
|
56
|
+
r"""
|
|
57
|
+
Compute :math:`S = \bar O^\dagger \bar O` and :math:`F = \bar O^\dagger \bar \epsilon`
|
|
58
|
+
with the given samples. When the number of samples is large, this function will
|
|
59
|
+
automatically switch to a more memory-efficient implementation.
|
|
60
|
+
"""
|
|
41
61
|
if (
|
|
42
62
|
self._max_parallel is None
|
|
43
63
|
or samples.nsamples <= self._max_parallel * jax.device_count()
|
|
@@ -81,7 +101,6 @@ class TimeEvol(SR):
|
|
|
81
101
|
newF = _AconjB(Omat, e)
|
|
82
102
|
Smat += newS
|
|
83
103
|
Fvec += newF
|
|
84
|
-
# psum here, nsamples definition should be modified to all samples across nodes
|
|
85
104
|
Smat = jnp.sum(Smat, axis=0) / nsamples
|
|
86
105
|
Fvec = jnp.sum(Fvec, axis=0) / nsamples
|
|
87
106
|
Omean = jnp.sum(Omean, axis=0) / nsamples
|
|
@@ -113,36 +132,3 @@ class TimeEvol(SR):
|
|
|
113
132
|
Smat, Fvec = self.get_SF(samples)
|
|
114
133
|
step = self.solve(Smat, Fvec)
|
|
115
134
|
return step
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
class ExactTimeEvol:
|
|
119
|
-
def __init__(self, init_state: DenseState, hamiltonian: Operator) -> None:
|
|
120
|
-
self._init_state = init_state
|
|
121
|
-
self._symm = self._init_state.symm
|
|
122
|
-
self._eigs, self._U = hamiltonian.diagonalize(self._symm, "full")
|
|
123
|
-
self._eigs = jnp.asarray(self._eigs)
|
|
124
|
-
self._U = jnp.asarray(self._U)
|
|
125
|
-
|
|
126
|
-
def get_evolved_psi(self, time: Union[float, jax.Array]) -> jax.Array:
|
|
127
|
-
is_float = isinstance(time, float)
|
|
128
|
-
if is_float:
|
|
129
|
-
time = jnp.array([time])
|
|
130
|
-
exp_eigs = jnp.exp(-1j * jnp.einsum("t,d->td", time, self._eigs))
|
|
131
|
-
psi0 = self._init_state.psi
|
|
132
|
-
psi = jnp.einsum("ij,tj,kj,k->ti", self._U, exp_eigs, self._U.conj(), psi0)
|
|
133
|
-
if is_float:
|
|
134
|
-
psi = psi[0]
|
|
135
|
-
return psi
|
|
136
|
-
|
|
137
|
-
def expectation(
|
|
138
|
-
self, operator: Operator, time: Union[float, jax.Array]
|
|
139
|
-
) -> Union[Number, jax.Array]:
|
|
140
|
-
psi = self.get_evolved_psi(time)
|
|
141
|
-
psi /= jnp.linalg.norm(psi, axis=1, keepdims=True)
|
|
142
|
-
op = operator.get_quspin_op(self._symm)
|
|
143
|
-
|
|
144
|
-
# this hasn't been tested
|
|
145
|
-
out = jnp.einsum("ti,it->t", psi.conj(), op.dot(np.ascontiguousarray(psi.T)))
|
|
146
|
-
if isinstance(time, float):
|
|
147
|
-
out = out.item()
|
|
148
|
-
return out
|
|
@@ -181,15 +181,10 @@ class Metropolis(Sampler):
|
|
|
181
181
|
|
|
182
182
|
state = self._state
|
|
183
183
|
use_ref = state.use_ref and self.nflips is not None
|
|
184
|
-
if use_ref
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
has_chunk = (
|
|
189
|
-
hasattr(state, "forward_chunk") and state.forward_chunk is not None
|
|
190
|
-
)
|
|
191
|
-
chunk_size = state.forward_chunk
|
|
192
|
-
is_chunked = has_chunk and chunk_size < self.nsamples // jax.device_count()
|
|
184
|
+
attr = "ref_chunk" if use_ref else "forward_chunk"
|
|
185
|
+
chunk_size = getattr(state, attr, None)
|
|
186
|
+
ns = self.nsamples // jax.device_count()
|
|
187
|
+
is_chunked = chunk_size is not None and chunk_size < ns
|
|
193
188
|
|
|
194
189
|
if is_chunked:
|
|
195
190
|
if use_ref:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional, Tuple, Union, BinaryIO
|
|
3
3
|
from jaxtyping import PyTree
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
@@ -16,6 +16,8 @@ from .state import State
|
|
|
16
16
|
from ..symmetry import Symmetry
|
|
17
17
|
from ..nn import RefModel
|
|
18
18
|
from ..utils import (
|
|
19
|
+
chunk_map,
|
|
20
|
+
shard_vmap,
|
|
19
21
|
chunk_shard_vmap,
|
|
20
22
|
to_distribute_array,
|
|
21
23
|
filter_replicate,
|
|
@@ -114,7 +116,7 @@ class Variational(State):
|
|
|
114
116
|
model: eqx.Module,
|
|
115
117
|
param_file: Optional[Union[str, Path, BinaryIO]] = None,
|
|
116
118
|
symm: Optional[Symmetry] = None,
|
|
117
|
-
max_parallel: Union[None, int, Tuple[int, int]] = None,
|
|
119
|
+
max_parallel: Union[None, int, Tuple[int, int], Tuple[int, int, int]] = None,
|
|
118
120
|
use_ref: bool = True,
|
|
119
121
|
):
|
|
120
122
|
r"""
|
|
@@ -126,23 +128,35 @@ class Variational(State):
|
|
|
126
128
|
or `equinox.tree_serialise_leaves`, default to not loading parameters.
|
|
127
129
|
|
|
128
130
|
:param symm: Symmetry of the network, default to `~quantax.symmetry.Identity`.
|
|
131
|
+
Denoting the network output as :math:`f(s)`
|
|
132
|
+
and symmetry elements as :math:`T_i` with characters :math:`\omega_i`,
|
|
133
|
+
the wave function is given by
|
|
134
|
+
:math:`\psi(s) = \sum_i \omega_i \, f(T_i s) / n_{symm}`
|
|
129
135
|
|
|
130
136
|
:param max_parallel:
|
|
131
|
-
The maximum
|
|
132
|
-
Specifying a limited value is important for
|
|
133
|
-
For
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
The maximum chunk size allowed per device.
|
|
138
|
+
Specifying a limited value is important for avoiding memory overflow.
|
|
139
|
+
For many hamiltonians, this also helps to improve the efficiency
|
|
140
|
+
by keeping a constant amount of forward pass and avoiding re-jitting.
|
|
141
|
+
The allowed input formats are:
|
|
142
|
+
|
|
143
|
+
- None:
|
|
144
|
+
No chunk size (default).
|
|
145
|
+
|
|
146
|
+
- int:
|
|
147
|
+
The same chunk size for all forward and backward passes.
|
|
148
|
+
|
|
149
|
+
- Tuple[int, int]:
|
|
150
|
+
The chunk size for forward and backward passes respectively.
|
|
151
|
+
|
|
152
|
+
- Tuple[int, int, int]:
|
|
153
|
+
The chunk size for forward pass, backward pass and
|
|
154
|
+
`~quantax.state.Variational.ref_forward_with_updates` respectively.
|
|
136
155
|
|
|
137
156
|
:param use_ref:
|
|
138
157
|
Whether `ref_forward` and `ref_forward_with_updates` will be used when
|
|
139
158
|
the model is a `~quantax.nn.RefModel`. When the model is not a `RefModel`,
|
|
140
159
|
this argument has no effect. Default to ``True``.
|
|
141
|
-
|
|
142
|
-
Denoting the network output as :math:`f(s)`,
|
|
143
|
-
and symmetry elements as :math:`T_i` with characters :math:`\omega_i`,
|
|
144
|
-
the final wave function is given by
|
|
145
|
-
:math:`\psi(s) = \sum_i \omega_i \, f(T_i s) / n_{symm}`
|
|
146
160
|
"""
|
|
147
161
|
super().__init__(symm)
|
|
148
162
|
if param_file is not None:
|
|
@@ -180,17 +194,20 @@ class Variational(State):
|
|
|
180
194
|
|
|
181
195
|
@property
|
|
182
196
|
def forward_chunk(self) -> int:
|
|
183
|
-
"""The maximum
|
|
197
|
+
"""The maximum chunk size of forward pass allowed per device."""
|
|
184
198
|
return self._forward_chunk
|
|
185
199
|
|
|
186
200
|
@property
|
|
187
201
|
def backward_chunk(self) -> int:
|
|
188
|
-
"""The maximum backward pass allowed per device."""
|
|
202
|
+
"""The maximum chunk size of backward pass allowed per device."""
|
|
189
203
|
return self._backward_chunk
|
|
190
204
|
|
|
191
205
|
@property
|
|
192
206
|
def ref_chunk(self) -> int:
|
|
193
|
-
"""
|
|
207
|
+
"""
|
|
208
|
+
The maximum chunk size of `~quantax.state.Variational.ref_forward_with_updates`
|
|
209
|
+
allowed per device.
|
|
210
|
+
"""
|
|
194
211
|
return self._ref_chunk
|
|
195
212
|
|
|
196
213
|
@property
|
|
@@ -242,23 +259,28 @@ class Variational(State):
|
|
|
242
259
|
)
|
|
243
260
|
|
|
244
261
|
def _init_forward(self) -> None:
|
|
245
|
-
def
|
|
262
|
+
def batch_forward(model: eqx.Module, s: jax.Array) -> jax.Array:
|
|
246
263
|
s_symm = self.symm.get_symm_spins(s)
|
|
247
264
|
psi = jax.vmap(model)(s_symm)
|
|
248
265
|
psi = self.symm.symmetrize(psi, s)
|
|
249
266
|
return psi.astype(get_default_dtype())
|
|
250
267
|
|
|
251
|
-
self.
|
|
252
|
-
|
|
268
|
+
self._batch_forward = shard_vmap(batch_forward, in_axes=(None, 0), out_axes=0)
|
|
269
|
+
self._direct_forward = chunk_map(
|
|
270
|
+
self._batch_forward, in_axes=(None, 0), chunk_size=self.forward_chunk
|
|
271
|
+
)
|
|
272
|
+
self._fulljit_forward = chunk_shard_vmap(
|
|
273
|
+
batch_forward, in_axes=(None, 0), out_axes=0, chunk_size=self.forward_chunk
|
|
253
274
|
)
|
|
254
275
|
|
|
255
276
|
def init_internal(model, s):
|
|
256
277
|
s_symm = self.symm.get_symm_spins(s)
|
|
257
278
|
return jax.vmap(model.init_internal)(s_symm)
|
|
258
279
|
|
|
259
|
-
|
|
280
|
+
init_internal = chunk_shard_vmap(
|
|
260
281
|
init_internal, in_axes=(None, 0), out_axes=0, chunk_size=self.ref_chunk
|
|
261
282
|
)
|
|
283
|
+
self._init_internal = eqx.filter_jit(init_internal)
|
|
262
284
|
|
|
263
285
|
def ref_forward_with_updates(model, s, s_old, nflips, internal):
|
|
264
286
|
s_symm = self.symm.get_symm_spins(s)
|
|
@@ -288,11 +310,15 @@ class Variational(State):
|
|
|
288
310
|
psi = self.symm.symmetrize(psi, s)
|
|
289
311
|
return psi.astype(get_default_dtype())
|
|
290
312
|
|
|
291
|
-
self.
|
|
313
|
+
self._batch_ref_forward = shard_vmap(
|
|
292
314
|
ref_forward,
|
|
293
315
|
in_axes=(None, 0, None, None, 0, None),
|
|
294
|
-
shard_axes=(None, 0, 0, None, 0, 0),
|
|
295
316
|
out_axes=0,
|
|
317
|
+
shard_axes=(None, 0, 0, None, 0, 0),
|
|
318
|
+
)
|
|
319
|
+
self._ref_forward = chunk_map(
|
|
320
|
+
self._batch_ref_forward,
|
|
321
|
+
in_axes=(None, 0, None, None, 0, None),
|
|
296
322
|
chunk_size=self.forward_chunk,
|
|
297
323
|
)
|
|
298
324
|
|
|
@@ -355,7 +381,7 @@ class Variational(State):
|
|
|
355
381
|
if self._use_ref:
|
|
356
382
|
out = self._ref_forward_with_updates(self.model, s, s_old, nflips, internal)
|
|
357
383
|
else:
|
|
358
|
-
out = self(s), None
|
|
384
|
+
out = self._fulljit_forward(self.model, s), None
|
|
359
385
|
return out
|
|
360
386
|
|
|
361
387
|
def ref_forward(
|
|
@@ -392,7 +418,7 @@ class Variational(State):
|
|
|
392
418
|
if self._use_ref:
|
|
393
419
|
out = self._ref_forward(self.model, s, s_old, nflips, idx_segment, internal)
|
|
394
420
|
else:
|
|
395
|
-
out = self(s)
|
|
421
|
+
out = self._direct_forward(self.model, s)
|
|
396
422
|
return out
|
|
397
423
|
|
|
398
424
|
def _init_backward(self) -> None:
|
|
@@ -23,5 +23,5 @@ from .tree import (
|
|
|
23
23
|
apply_updates,
|
|
24
24
|
)
|
|
25
25
|
from .big_array import LogArray, ScaleArray, PsiArray, where
|
|
26
|
-
from .function import
|
|
26
|
+
from .function import chunk_map, shmap, shard_vmap, chunk_shard_vmap
|
|
27
27
|
from .basis import ints_to_array, array_to_ints, neel, stripe, Sqz_factor, rand_states
|
|
@@ -4,7 +4,6 @@ import jax
|
|
|
4
4
|
import jax.numpy as jnp
|
|
5
5
|
from jaxtyping import PyTree
|
|
6
6
|
from jax.sharding import Mesh, PartitionSpec
|
|
7
|
-
from jax.experimental.shard_map import shard_map
|
|
8
7
|
import equinox as eqx
|
|
9
8
|
from .array import array_extend
|
|
10
9
|
from .tree import filter_tree_map
|
|
@@ -180,19 +179,20 @@ def shmap(
|
|
|
180
179
|
mesh = Mesh(jax.devices(), "x")
|
|
181
180
|
in_specs = _axes_to_specs(in_axes)
|
|
182
181
|
out_specs = _axes_to_specs(out_axes)
|
|
183
|
-
f = shard_map(
|
|
182
|
+
f = jax.shard_map(
|
|
183
|
+
f, mesh=mesh, in_specs=in_specs, out_specs=out_specs, check_vma=False
|
|
184
|
+
)
|
|
184
185
|
return f
|
|
185
186
|
|
|
186
187
|
|
|
187
|
-
def
|
|
188
|
+
def shard_vmap(
|
|
188
189
|
f: Callable,
|
|
189
190
|
in_axes: Union[tuple, int, None],
|
|
190
191
|
out_axes: Union[tuple, int, None],
|
|
191
|
-
chunk_size: Optional[int] = None,
|
|
192
192
|
shard_axes: Union[tuple, int, None] = None,
|
|
193
193
|
) -> Callable:
|
|
194
194
|
"""
|
|
195
|
-
f ->
|
|
195
|
+
f -> shard_map(vmap(f))
|
|
196
196
|
|
|
197
197
|
:param f:
|
|
198
198
|
The function to be converted. The arguments of f will be sharded.
|
|
@@ -202,12 +202,44 @@ def chunk_shard_vmap(
|
|
|
202
202
|
|
|
203
203
|
:param out_axes:
|
|
204
204
|
The mapped axes of f outputs.
|
|
205
|
-
"""
|
|
206
205
|
|
|
206
|
+
:param shard_axes:
|
|
207
|
+
The sharded axes of f input arguments. Default to in_axes.
|
|
208
|
+
"""
|
|
207
209
|
shard_axes = in_axes if shard_axes is None else shard_axes
|
|
208
210
|
|
|
209
211
|
f = jax.vmap(f, in_axes, out_axes)
|
|
210
212
|
f = shmap(f, shard_axes, out_axes)
|
|
213
|
+
f = eqx.filter_jit(f)
|
|
214
|
+
return f
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def chunk_shard_vmap(
|
|
218
|
+
f: Callable,
|
|
219
|
+
in_axes: Union[tuple, int, None],
|
|
220
|
+
out_axes: Union[tuple, int, None],
|
|
221
|
+
shard_axes: Union[tuple, int, None] = None,
|
|
222
|
+
chunk_size: Optional[int] = None,
|
|
223
|
+
) -> Callable:
|
|
224
|
+
"""
|
|
225
|
+
f -> chunk_map(shard_map(vmap(f)), use_scan=True)
|
|
226
|
+
|
|
227
|
+
:param f:
|
|
228
|
+
The function to be converted. The arguments of f will be sharded.
|
|
229
|
+
|
|
230
|
+
:param in_axes:
|
|
231
|
+
The mapped axes of f input arguments.
|
|
232
|
+
|
|
233
|
+
:param out_axes:
|
|
234
|
+
The mapped axes of f outputs.
|
|
235
|
+
|
|
236
|
+
:param shard_axes:
|
|
237
|
+
The sharded axes of f input arguments. Default to in_axes.
|
|
238
|
+
|
|
239
|
+
:param chunk_size:
|
|
240
|
+
The chunk size on each machine. If None, no chunking will be applied.
|
|
241
|
+
"""
|
|
242
|
+
f = shard_vmap(f, in_axes, out_axes, shard_axes)
|
|
211
243
|
f = chunk_map(f, in_axes, out_axes, chunk_size, use_scan=True)
|
|
212
244
|
f = eqx.filter_jit(f)
|
|
213
245
|
return f
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantax
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Flexible neural quantum states based on JAX
|
|
5
5
|
Author: Christopher Roth
|
|
6
6
|
Author-email: Ao Chen <chenao.phys@gmail.com>
|
|
@@ -8,7 +8,7 @@ Requires-Python: <=3.13,>=3.10
|
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Requires-Dist: numpy>=1.26.0
|
|
10
10
|
Requires-Dist: scipy>=1.11.1
|
|
11
|
-
Requires-Dist: jax>=0.
|
|
11
|
+
Requires-Dist: jax>=0.6.1
|
|
12
12
|
Requires-Dist: equinox>=0.11.4
|
|
13
13
|
Requires-Dist: lrux>=0.1.0
|
|
14
14
|
Provides-Extra: full
|
|
@@ -16,7 +16,7 @@ Requires-Dist: numpy>=2.0.0; extra == "full"
|
|
|
16
16
|
Requires-Dist: scipy>=1.13.1; extra == "full"
|
|
17
17
|
Requires-Dist: matplotlib>=3.8.0; extra == "full"
|
|
18
18
|
Requires-Dist: quspin>=1.0.0; extra == "full"
|
|
19
|
-
Requires-Dist: jax>=0.
|
|
19
|
+
Requires-Dist: jax>=0.6.1; extra == "full"
|
|
20
20
|
Requires-Dist: equinox>=0.11.4; extra == "full"
|
|
21
21
|
Requires-Dist: lrux>=0.1.0; extra == "full"
|
|
22
22
|
Dynamic: license-file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|