qadence 1.1.1__tar.gz → 1.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.
- {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/build_docs.yml +1 -1
- {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/lint.yml +1 -1
- {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/test_all.yml +26 -1
- {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/test_examples.yml +1 -1
- {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/test_fast.yml +3 -3
- {qadence-1.1.1 → qadence-1.2.1}/PKG-INFO +22 -3
- {qadence-1.1.1 → qadence-1.2.1}/README.md +4 -1
- {qadence-1.1.1 → qadence-1.2.1}/mkdocs.yml +1 -2
- {qadence-1.1.1 → qadence-1.2.1}/pyproject.toml +25 -7
- {qadence-1.1.1 → qadence-1.2.1}/qadence/__init__.py +1 -0
- qadence-1.2.1/qadence/analog/__init__.py +7 -0
- qadence-1.2.1/qadence/analog/addressing.py +167 -0
- qadence-1.2.1/qadence/analog/constants.py +59 -0
- qadence-1.2.1/qadence/analog/device.py +82 -0
- qadence-1.2.1/qadence/analog/hamiltonian_terms.py +101 -0
- qadence-1.2.1/qadence/analog/parse_analog.py +120 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backend.py +42 -12
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/__init__.py +1 -2
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/api.py +27 -9
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/braket/backend.py +3 -2
- qadence-1.2.1/qadence/backends/horqrux/backend.py +216 -0
- qadence-1.2.1/qadence/backends/horqrux/config.py +26 -0
- qadence-1.2.1/qadence/backends/horqrux/convert_ops.py +273 -0
- qadence-1.2.1/qadence/backends/jax_utils.py +45 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/__init__.py +0 -1
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/backend.py +31 -15
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/config.py +19 -10
- qadence-1.2.1/qadence/backends/pulser/devices.py +71 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/pulses.py +70 -12
- qadence-1.2.1/qadence/backends/pyqtorch/__init__.py +5 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pyqtorch/backend.py +4 -4
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pyqtorch/config.py +18 -12
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pyqtorch/convert_ops.py +15 -7
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/utils.py +5 -9
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/abstract.py +5 -1
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/analog.py +18 -9
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/block_to_tensor.py +11 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/embedding.py +46 -24
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/primitive.py +81 -9
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/utils.py +20 -1
- {qadence-1.1.1 → qadence-1.2.1}/qadence/circuit.py +3 -9
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/__init__.py +4 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/feature_maps.py +84 -60
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/hamiltonians.py +27 -98
- qadence-1.2.1/qadence/constructors/rydberg_feature_maps.py +113 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/divergences.py +12 -0
- qadence-1.2.1/qadence/engines/differentiable_backend.py +152 -0
- qadence-1.2.1/qadence/engines/jax/__init__.py +8 -0
- qadence-1.2.1/qadence/engines/jax/differentiable_backend.py +73 -0
- qadence-1.2.1/qadence/engines/jax/differentiable_expectation.py +94 -0
- qadence-1.2.1/qadence/engines/torch/__init__.py +4 -0
- qadence-1.2.1/qadence/engines/torch/differentiable_backend.py +85 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/extensions.py +21 -9
- qadence-1.2.1/qadence/finitediff.py +47 -0
- qadence-1.2.1/qadence/mitigations/readout.py +160 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/models.py +10 -3
- {qadence-1.1.1 → qadence-1.2.1}/qadence/models/qnn.py +88 -23
- {qadence-1.1.1 → qadence-1.2.1}/qadence/models/quantum_model.py +13 -2
- {qadence-1.1.1 → qadence-1.2.1}/qadence/operations.py +55 -70
- {qadence-1.1.1 → qadence-1.2.1}/qadence/parameters.py +24 -13
- qadence-1.2.1/qadence/py.typed +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/register.py +91 -43
- {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/__init__.py +1 -0
- qadence-1.2.1/qadence/transpile/apply_fn.py +40 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/types.py +32 -2
- {qadence-1.1.1 → qadence-1.2.1}/qadence/utils.py +35 -0
- qadence-1.1.1/qadence/analog/__init__.py +0 -5
- qadence-1.1.1/qadence/analog/interaction.py +0 -198
- qadence-1.1.1/qadence/analog/utils.py +0 -132
- qadence-1.1.1/qadence/backends/pulser/devices.py +0 -77
- qadence-1.1.1/qadence/mitigations/readout.py +0 -93
- {qadence-1.1.1 → qadence-1.2.1}/.coveragerc +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/.github/dependabot.yml +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/dependabot.yml +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/.gitignore +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/.pre-commit-config.yaml +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/CODE_OF_CONDUCT.md +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/CONTRIBUTING.md +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/LICENSE +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/MANIFEST.in +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/adjoint.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/braket/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/braket/config.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/braket/convert_ops.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/gpsr.py +0 -0
- {qadence-1.1.1/qadence/backends/pyqtorch → qadence-1.2.1/qadence/backends/horqrux}/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/channels.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/cloud.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/convert_ops.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/waveforms.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/composite.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/manipulate.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/matrix.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/ansatze.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/daqc/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/daqc/daqc.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/daqc/gen_parser.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/daqc/utils.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/iia.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/qft.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/rydberg_hea.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/utils.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/decompose.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/assets/dark/measurement.png +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/assets/dark/measurement.svg +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/assets/light/measurement.png +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/assets/light/measurement.svg +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/themes.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/utils.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/vizbackend.py +0 -0
- /qadence-1.1.1/qadence/py.typed → /qadence-1.2.1/qadence/engines/__init__.py +0 -0
- /qadence-1.1.1/qadence/backends/pytorch_wrapper.py → /qadence-1.2.1/qadence/engines/torch/differentiable_expectation.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/exceptions/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/exceptions/exceptions.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/execution.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/logger.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/measurements/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/measurements/protocols.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/measurements/shadow.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/measurements/tomography.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/mitigations/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/mitigations/analog_zne.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/mitigations/protocols.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/config.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/data.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/optimize_step.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/parameters.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/printing.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/saveload.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/tensors.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/train_grad.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/train_no_grad.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/utils.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/models/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/noise/__init__.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/noise/protocols.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/noise/readout.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/overlap.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/qubit_support.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/serialization.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/states.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/block.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/circuit.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/digitalize.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/flatten.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/invert.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/transpile.py +0 -0
- {qadence-1.1.1 → qadence-1.2.1}/setup.py +0 -0
@@ -10,6 +10,7 @@ concurrency:
|
|
10
10
|
group: all-${{ github.head_ref || github.run_id }}
|
11
11
|
cancel-in-progress: true
|
12
12
|
|
13
|
+
|
13
14
|
jobs:
|
14
15
|
test_qadence_ubuntu:
|
15
16
|
name: Test Qadence (ubuntu)
|
@@ -22,7 +23,7 @@ jobs:
|
|
22
23
|
uses: actions/checkout@v4
|
23
24
|
|
24
25
|
- name: Set up Python ${{ matrix.python-version }}
|
25
|
-
uses: actions/setup-python@
|
26
|
+
uses: actions/setup-python@v5
|
26
27
|
with:
|
27
28
|
python-version: ${{ matrix.python-version }}
|
28
29
|
|
@@ -33,3 +34,27 @@ jobs:
|
|
33
34
|
- name: Run tests
|
34
35
|
run: |
|
35
36
|
hatch -v run test
|
37
|
+
|
38
|
+
test_fast_qadence_windows_mac:
|
39
|
+
name: Test Qadence (Windows, MacOS)
|
40
|
+
runs-on: ${{ matrix.os }}
|
41
|
+
strategy:
|
42
|
+
matrix:
|
43
|
+
os: [macos-latest, windows-latest]
|
44
|
+
python-version: ["3.10"]
|
45
|
+
steps:
|
46
|
+
- name: Checkout Qadence
|
47
|
+
uses: actions/checkout@v4
|
48
|
+
|
49
|
+
- name: Set up Python ${{ matrix.python-version }}
|
50
|
+
uses: actions/setup-python@v5
|
51
|
+
with:
|
52
|
+
python-version: ${{ matrix.python-version }}
|
53
|
+
|
54
|
+
- name: Install Hatch
|
55
|
+
run: |
|
56
|
+
pip install hatch
|
57
|
+
|
58
|
+
- name: Run tests
|
59
|
+
run: |
|
60
|
+
hatch -v run test -m "not slow"
|
@@ -27,7 +27,7 @@ jobs:
|
|
27
27
|
- name: Checkout Qadence
|
28
28
|
uses: actions/checkout@v4
|
29
29
|
- name: Set up Python ${{ matrix.python-version }}
|
30
|
-
uses: actions/setup-python@
|
30
|
+
uses: actions/setup-python@v5
|
31
31
|
with:
|
32
32
|
python-version: ${{ matrix.python-version }}
|
33
33
|
- name: Install Hatch
|
@@ -54,7 +54,7 @@ jobs:
|
|
54
54
|
with:
|
55
55
|
ref: ${{ github.ref }}
|
56
56
|
- name: Set up Python
|
57
|
-
uses: actions/setup-python@
|
57
|
+
uses: actions/setup-python@v5
|
58
58
|
with:
|
59
59
|
python-version: "3.10"
|
60
60
|
- name: Install Python dependencies
|
@@ -94,7 +94,7 @@ jobs:
|
|
94
94
|
- name: Install graphviz
|
95
95
|
run: sudo apt-get install -y graphviz
|
96
96
|
- name: Set up Python 3.10
|
97
|
-
uses: actions/setup-python@
|
97
|
+
uses: actions/setup-python@v5
|
98
98
|
with:
|
99
99
|
python-version: '3.10'
|
100
100
|
- name: Install Hatch
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qadence
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.2.1
|
4
4
|
Summary: Pasqal interface for circuit-based quantum computing SDKs
|
5
5
|
Author-email: Aleksander Wennersteen <aleksander.wennersteen@pasqal.com>, Gert-Jan Both <gert-jan.both@pasqal.com>, Niklas Heim <niklas.heim@pasqal.com>, Mario Dagrada <mario.dagrada@pasqal.com>, Vincent Elfving <vincent.elfving@pasqal.com>, Dominik Seitz <dominik.seitz@pasqal.com>, Roland Guichard <roland.guichard@pasqal.com>, "Joao P. Moutinho" <joao.moutinho@pasqal.com>, Vytautas Abramavicius <vytautas.abramavicius@pasqal.com>
|
6
6
|
License: Apache 2.0
|
@@ -18,8 +18,9 @@ Requires-Dist: deepdiff
|
|
18
18
|
Requires-Dist: jsonschema
|
19
19
|
Requires-Dist: matplotlib
|
20
20
|
Requires-Dist: nevergrad
|
21
|
+
Requires-Dist: numpy
|
21
22
|
Requires-Dist: openfermion
|
22
|
-
Requires-Dist: pyqtorch==1.0.
|
23
|
+
Requires-Dist: pyqtorch==1.0.3
|
23
24
|
Requires-Dist: rich
|
24
25
|
Requires-Dist: scipy
|
25
26
|
Requires-Dist: sympytorch>=0.1.2
|
@@ -27,10 +28,25 @@ Requires-Dist: tensorboard>=2.12.0
|
|
27
28
|
Requires-Dist: torch
|
28
29
|
Provides-Extra: all
|
29
30
|
Requires-Dist: amazon-braket-sdk; extra == 'all'
|
31
|
+
Requires-Dist: einops; extra == 'all'
|
32
|
+
Requires-Dist: flax; extra == 'all'
|
30
33
|
Requires-Dist: graphviz; extra == 'all'
|
34
|
+
Requires-Dist: horqrux==0.3.0; extra == 'all'
|
35
|
+
Requires-Dist: jax; extra == 'all'
|
36
|
+
Requires-Dist: jaxopt; extra == 'all'
|
37
|
+
Requires-Dist: optax; extra == 'all'
|
31
38
|
Requires-Dist: pulser>=0.15.2; extra == 'all'
|
39
|
+
Requires-Dist: sympy2jax; extra == 'all'
|
32
40
|
Provides-Extra: braket
|
33
41
|
Requires-Dist: amazon-braket-sdk; extra == 'braket'
|
42
|
+
Provides-Extra: horqrux
|
43
|
+
Requires-Dist: einops; extra == 'horqrux'
|
44
|
+
Requires-Dist: flax; extra == 'horqrux'
|
45
|
+
Requires-Dist: horqrux==0.3.0; extra == 'horqrux'
|
46
|
+
Requires-Dist: jax; extra == 'horqrux'
|
47
|
+
Requires-Dist: jaxopt; extra == 'horqrux'
|
48
|
+
Requires-Dist: optax; extra == 'horqrux'
|
49
|
+
Requires-Dist: sympy2jax; extra == 'horqrux'
|
34
50
|
Provides-Extra: pulser
|
35
51
|
Requires-Dist: pasqal-cloud>=0.3.5; extra == 'pulser'
|
36
52
|
Requires-Dist: pulser>=v0.15.2; extra == 'pulser'
|
@@ -74,12 +90,15 @@ Qadence is available on [PyPI](https://pypi.org/project/qadence/) and can be ins
|
|
74
90
|
pip install qadence
|
75
91
|
```
|
76
92
|
|
77
|
-
The default, pre-installed backend for Qadence is [PyQTorch](https://github.com/pasqal-io/pyqtorch), a differentiable state vector simulator for digital-analog simulation
|
93
|
+
The default, pre-installed backend for Qadence is [PyQTorch](https://github.com/pasqal-io/pyqtorch), a differentiable state vector simulator for digital-analog simulation based on `PyTorch`. It is possible to install additional, `PyTorch` -based backends and the circuit visualization library using the following extras:
|
78
94
|
|
79
95
|
* `pulser`: The [Pulser](https://github.com/pasqal-io/Pulser) backend for composing, simulating and executing pulse sequences for neutral-atom quantum devices.
|
80
96
|
* `braket`: The [Braket](https://github.com/amazon-braket/amazon-braket-sdk-python) backend, an open source library that provides a framework for interacting with quantum computing hardware devices through Amazon Braket.
|
81
97
|
* `visualization`: A visualization library to display quantum circuit diagrams.
|
82
98
|
|
99
|
+
Qadence also supports a `JAX` engine which is currently supporting the [Horqrux](https://github.com/pasqal-io/horqrux) backend. `horqrux` is currently only available via the [low-level API](examples/backends/low_level/horqrux_backend.py).
|
100
|
+
|
101
|
+
|
83
102
|
To install individual extras, use the following syntax (**IMPORTANT** Make sure to use quotes):
|
84
103
|
|
85
104
|
```bash
|
@@ -34,12 +34,15 @@ Qadence is available on [PyPI](https://pypi.org/project/qadence/) and can be ins
|
|
34
34
|
pip install qadence
|
35
35
|
```
|
36
36
|
|
37
|
-
The default, pre-installed backend for Qadence is [PyQTorch](https://github.com/pasqal-io/pyqtorch), a differentiable state vector simulator for digital-analog simulation
|
37
|
+
The default, pre-installed backend for Qadence is [PyQTorch](https://github.com/pasqal-io/pyqtorch), a differentiable state vector simulator for digital-analog simulation based on `PyTorch`. It is possible to install additional, `PyTorch` -based backends and the circuit visualization library using the following extras:
|
38
38
|
|
39
39
|
* `pulser`: The [Pulser](https://github.com/pasqal-io/Pulser) backend for composing, simulating and executing pulse sequences for neutral-atom quantum devices.
|
40
40
|
* `braket`: The [Braket](https://github.com/amazon-braket/amazon-braket-sdk-python) backend, an open source library that provides a framework for interacting with quantum computing hardware devices through Amazon Braket.
|
41
41
|
* `visualization`: A visualization library to display quantum circuit diagrams.
|
42
42
|
|
43
|
+
Qadence also supports a `JAX` engine which is currently supporting the [Horqrux](https://github.com/pasqal-io/horqrux) backend. `horqrux` is currently only available via the [low-level API](examples/backends/low_level/horqrux_backend.py).
|
44
|
+
|
45
|
+
|
43
46
|
To install individual extras, use the following syntax (**IMPORTANT** Make sure to use quotes):
|
44
47
|
|
45
48
|
```bash
|
@@ -23,10 +23,9 @@ nav:
|
|
23
23
|
- digital_analog_qc/index.md
|
24
24
|
- Basic operations on neutral-atoms: digital_analog_qc/analog-basics.md
|
25
25
|
- Fitting a simple function: digital_analog_qc/analog-qcl.md
|
26
|
-
-
|
26
|
+
- Restricted local addressability: digital_analog_qc/semi-local-addressing.md
|
27
27
|
- Pulse-level programming with Pulser: digital_analog_qc/pulser-basic.md
|
28
28
|
- Solve a QUBO problem: digital_analog_qc/analog-qubo.md
|
29
|
-
- Pulse-level programming with Pulser: digital_analog_qc/pulser-basic.md
|
30
29
|
- CNOT with interacting qubits: digital_analog_qc/daqc-cnot.md
|
31
30
|
|
32
31
|
- Variational quantum algorithms:
|
@@ -19,7 +19,7 @@ authors = [
|
|
19
19
|
]
|
20
20
|
requires-python = ">=3.9,<3.12"
|
21
21
|
license = {text = "Apache 2.0"}
|
22
|
-
version = "1.
|
22
|
+
version = "1.2.1"
|
23
23
|
classifiers=[
|
24
24
|
"License :: OSI Approved :: Apache Software License",
|
25
25
|
"Programming Language :: Python",
|
@@ -31,8 +31,9 @@ classifiers=[
|
|
31
31
|
"Programming Language :: Python :: Implementation :: PyPy",
|
32
32
|
]
|
33
33
|
dependencies = [
|
34
|
-
"
|
34
|
+
"numpy",
|
35
35
|
"torch",
|
36
|
+
"openfermion",
|
36
37
|
"sympytorch>=0.1.2",
|
37
38
|
"rich",
|
38
39
|
"tensorboard>=2.12.0",
|
@@ -40,8 +41,8 @@ dependencies = [
|
|
40
41
|
"jsonschema",
|
41
42
|
"nevergrad",
|
42
43
|
"scipy",
|
43
|
-
"pyqtorch==1.0.
|
44
|
-
"matplotlib"
|
44
|
+
"pyqtorch==1.0.3",
|
45
|
+
"matplotlib",
|
45
46
|
]
|
46
47
|
|
47
48
|
[tool.hatch.metadata]
|
@@ -57,6 +58,15 @@ visualization = [
|
|
57
58
|
# "latex2svg @ git+https://github.com/Moonbase59/latex2svg.git#egg=latex2svg",
|
58
59
|
# "scour",
|
59
60
|
]
|
61
|
+
horqrux = [
|
62
|
+
"horqrux==0.3.0",
|
63
|
+
"jax",
|
64
|
+
"flax",
|
65
|
+
"optax",
|
66
|
+
"jaxopt",
|
67
|
+
"einops",
|
68
|
+
"sympy2jax"]
|
69
|
+
|
60
70
|
all = [
|
61
71
|
"pulser>=0.15.2",
|
62
72
|
"amazon-braket-sdk",
|
@@ -64,6 +74,13 @@ all = [
|
|
64
74
|
# FIXME: will be needed once we support latex labels
|
65
75
|
# "latex2svg @ git+https://github.com/Moonbase59/latex2svg.git#egg=latex2svg",
|
66
76
|
# "scour",
|
77
|
+
"horqrux==0.3.0",
|
78
|
+
"jax",
|
79
|
+
"flax",
|
80
|
+
"optax",
|
81
|
+
"jaxopt",
|
82
|
+
"einops",
|
83
|
+
"sympy2jax"
|
67
84
|
]
|
68
85
|
|
69
86
|
[tool.hatch.envs.default]
|
@@ -111,16 +128,16 @@ filterwarnings = [
|
|
111
128
|
|
112
129
|
[tool.hatch.envs.docs]
|
113
130
|
dependencies = [
|
114
|
-
"mkdocs
|
131
|
+
"mkdocs",
|
115
132
|
"mkdocs-material",
|
116
133
|
"mkdocstrings",
|
117
134
|
"mkdocstrings-python",
|
118
|
-
"mkdocs-section-index
|
135
|
+
"mkdocs-section-index",
|
119
136
|
"mkdocs-exclude",
|
120
137
|
"markdown-exec",
|
121
138
|
"mike",
|
122
139
|
]
|
123
|
-
features = ["pulser", "braket", "visualization"]
|
140
|
+
features = ["pulser", "braket", "horqrux", "visualization"]
|
124
141
|
|
125
142
|
[tool.hatch.envs.docs.scripts]
|
126
143
|
build = "mkdocs build --clean --strict"
|
@@ -167,6 +184,7 @@ required-imports = ["from __future__ import annotations"]
|
|
167
184
|
[tool.ruff.per-file-ignores]
|
168
185
|
"__init__.py" = ["F401"]
|
169
186
|
"operations.py" = ["E742"] # Avoid ambiguous class name warning for identity.
|
187
|
+
"qadence/backends/horqrux/convert_ops.py" = ["E741"] # Avoid ambiguous class name warning for 0.
|
170
188
|
|
171
189
|
[tool.ruff.mccabe]
|
172
190
|
max-complexity = 15
|
@@ -0,0 +1,7 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from .addressing import AddressingPattern
|
4
|
+
from .device import IdealDevice, RealisticDevice, RydbergDevice
|
5
|
+
from .parse_analog import add_background_hamiltonian
|
6
|
+
|
7
|
+
__all__ = ["RydbergDevice", "IdealDevice", "RealisticDevice", "AddressingPattern"]
|
@@ -0,0 +1,167 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass, fields
|
4
|
+
from typing import Union
|
5
|
+
from warnings import warn
|
6
|
+
|
7
|
+
from sympy import Expr, Heaviside, exp
|
8
|
+
from torch import Tensor, pi
|
9
|
+
|
10
|
+
from qadence.parameters import Parameter, evaluate
|
11
|
+
|
12
|
+
# FIXME: Clarify the roles of these values in the context
|
13
|
+
# device specification and how they relate with the
|
14
|
+
# maximum values for delta and omega.
|
15
|
+
GLOBAL_MAX_AMPLITUDE = 300
|
16
|
+
GLOBAL_MAX_DETUNING = 2 * pi * 2000
|
17
|
+
LOCAL_MAX_AMPLITUDE = 3
|
18
|
+
LOCAL_MAX_DETUNING = 2 * pi * 20
|
19
|
+
|
20
|
+
TWeight = Union[str, float, Tensor, Parameter]
|
21
|
+
|
22
|
+
|
23
|
+
def sigmoid(x: Tensor, a: float, b: float) -> Expr:
|
24
|
+
return 1.0 / (1.0 + exp(-a * (x + b)))
|
25
|
+
|
26
|
+
|
27
|
+
@dataclass
|
28
|
+
class AddressingPattern:
|
29
|
+
"""Semi-local addressing pattern."""
|
30
|
+
|
31
|
+
n_qubits: int
|
32
|
+
"""Number of qubits in register."""
|
33
|
+
|
34
|
+
weights_amp: dict[int, TWeight]
|
35
|
+
"""List of weights for fixed amplitude pattern that cannot be changed during the execution."""
|
36
|
+
|
37
|
+
weights_det: dict[int, TWeight]
|
38
|
+
"""List of weights for fixed detuning pattern that cannot be changed during the execution."""
|
39
|
+
|
40
|
+
amp: TWeight = LOCAL_MAX_AMPLITUDE
|
41
|
+
"""Maximum amplitude of the amplitude pattern felt by a single qubit."""
|
42
|
+
|
43
|
+
det: TWeight = LOCAL_MAX_DETUNING
|
44
|
+
"""Maximum detuning of the detuning pattern felt by a single qubit."""
|
45
|
+
|
46
|
+
def _validate_weights(
|
47
|
+
self,
|
48
|
+
weights: dict[int, TWeight],
|
49
|
+
) -> None:
|
50
|
+
for v in weights.values():
|
51
|
+
if not isinstance(v, (str, Parameter)):
|
52
|
+
if not (v >= 0.0 and v <= 1.0):
|
53
|
+
raise ValueError("Addressing pattern weights must sum fall in range [0.0, 1.0]")
|
54
|
+
|
55
|
+
def _constrain_weights(
|
56
|
+
self,
|
57
|
+
weights: dict[int, TWeight],
|
58
|
+
) -> dict:
|
59
|
+
# augment weight dict if needed
|
60
|
+
weights = {
|
61
|
+
i: Parameter(0.0)
|
62
|
+
if i not in weights
|
63
|
+
else (Parameter(weights[i]) if not isinstance(weights[i], Parameter) else weights[i])
|
64
|
+
for i in range(self.n_qubits)
|
65
|
+
}
|
66
|
+
|
67
|
+
# restrict weights to [0, 1] range - equal to 0 everywhere else
|
68
|
+
weights = {
|
69
|
+
k: v if v.is_number else abs(v * (sigmoid(v, 20, 1) - sigmoid(v, 20.0, -1))) # type: ignore [union-attr]
|
70
|
+
for k, v in weights.items()
|
71
|
+
}
|
72
|
+
|
73
|
+
return weights
|
74
|
+
|
75
|
+
def _constrain_max_vals(self) -> None:
|
76
|
+
# enforce constraints:
|
77
|
+
# 0 <= amp <= GLOBAL_MAX_AMPLITUDE
|
78
|
+
# 0 <= abs(det) <= GLOBAL_MAX_DETUNING
|
79
|
+
self.amp = abs(
|
80
|
+
self.amp
|
81
|
+
* (
|
82
|
+
Heaviside(self.amp + GLOBAL_MAX_AMPLITUDE) # type: ignore [operator]
|
83
|
+
- Heaviside(self.amp - GLOBAL_MAX_AMPLITUDE) # type: ignore [operator]
|
84
|
+
)
|
85
|
+
)
|
86
|
+
self.det = -abs(
|
87
|
+
self.det
|
88
|
+
* (
|
89
|
+
Heaviside(self.det + GLOBAL_MAX_DETUNING)
|
90
|
+
- Heaviside(self.det - GLOBAL_MAX_DETUNING)
|
91
|
+
)
|
92
|
+
)
|
93
|
+
|
94
|
+
def _create_local_constraint(self, val: Expr, weights: dict, max_val: float) -> dict:
|
95
|
+
# enforce local constraints:
|
96
|
+
# amp * w_amp_i < LOCAL_MAX_AMPLITUDE or
|
97
|
+
# abs(det) * w_det_i < LOCAL_MAX_DETUNING
|
98
|
+
local_constr = {k: val * v for k, v in weights.items()}
|
99
|
+
local_constr = {k: Heaviside(v) - Heaviside(v - max_val) for k, v in local_constr.items()}
|
100
|
+
|
101
|
+
return local_constr
|
102
|
+
|
103
|
+
def _create_global_constraint(self, val: Expr, weights: dict, max_val: float) -> Expr:
|
104
|
+
# enforce global constraints:
|
105
|
+
# amp * sum(w_amp_0, w_amp_1, ...) < GLOBAL_MAX_AMPLITUDE or
|
106
|
+
# abs(det) * sum(w_det_0, w_det_1, ...) < GLOBAL_MAX_DETUNING
|
107
|
+
weighted_vals_global = val * sum([v for v in weights.values()])
|
108
|
+
weighted_vals_global = Heaviside(weighted_vals_global) - Heaviside(
|
109
|
+
weighted_vals_global - max_val
|
110
|
+
)
|
111
|
+
|
112
|
+
return weighted_vals_global
|
113
|
+
|
114
|
+
def __post_init__(self) -> None:
|
115
|
+
# validate amplitude/detuning weights
|
116
|
+
self._validate_weights(self.weights_amp)
|
117
|
+
self._validate_weights(self.weights_det)
|
118
|
+
|
119
|
+
# validate maximum global amplitude/detuning values
|
120
|
+
if not isinstance(self.amp, (str, Parameter)):
|
121
|
+
if self.amp > GLOBAL_MAX_AMPLITUDE:
|
122
|
+
warn("Maximum absolute value of amplitude is exceeded")
|
123
|
+
elif isinstance(self.amp, str):
|
124
|
+
self.amp = Parameter(self.amp, trainable=True)
|
125
|
+
if not isinstance(self.det, (str, Parameter)):
|
126
|
+
if abs(self.det) > GLOBAL_MAX_DETUNING:
|
127
|
+
warn("Maximum absolute value of detuning is exceeded")
|
128
|
+
elif isinstance(self.det, str):
|
129
|
+
self.det = Parameter(self.det, trainable=True)
|
130
|
+
|
131
|
+
# constrain amplitude/detuning parameterized weights to [0.0, 1.0] interval
|
132
|
+
self.weights_amp = self._constrain_weights(self.weights_amp)
|
133
|
+
self.weights_det = self._constrain_weights(self.weights_det)
|
134
|
+
|
135
|
+
# constrain max global amplitude and detuning to strict interval
|
136
|
+
self._constrain_max_vals()
|
137
|
+
|
138
|
+
# create additional local and global constraints for amplitude/detuning masks
|
139
|
+
self.local_constr_amp = self._create_local_constraint(
|
140
|
+
self.amp, self.weights_amp, LOCAL_MAX_AMPLITUDE
|
141
|
+
)
|
142
|
+
self.local_constr_det = self._create_local_constraint(
|
143
|
+
-self.det, self.weights_det, LOCAL_MAX_DETUNING
|
144
|
+
)
|
145
|
+
self.global_constr_amp = self._create_global_constraint(
|
146
|
+
self.amp, self.weights_amp, GLOBAL_MAX_AMPLITUDE
|
147
|
+
)
|
148
|
+
self.global_constr_det = self._create_global_constraint(
|
149
|
+
-self.det, self.weights_det, GLOBAL_MAX_DETUNING
|
150
|
+
)
|
151
|
+
|
152
|
+
# validate number of qubits in mask
|
153
|
+
if max(list(self.weights_amp.keys())) >= self.n_qubits:
|
154
|
+
raise ValueError("Amplitude weight specified for non-existing qubit")
|
155
|
+
if max(list(self.weights_det.keys())) >= self.n_qubits:
|
156
|
+
raise ValueError("Detuning weight specified for non-existing qubit")
|
157
|
+
|
158
|
+
def evaluate(self, weights: dict, values: dict) -> dict:
|
159
|
+
# evaluate weight expressions with actual values
|
160
|
+
return {k: evaluate(v, values, as_torch=True).flatten() for k, v in weights.items()} # type: ignore [union-attr]
|
161
|
+
|
162
|
+
def _to_dict(self) -> dict:
|
163
|
+
return {field.name: getattr(self, field.name) for field in fields(self)}
|
164
|
+
|
165
|
+
@classmethod
|
166
|
+
def _from_dict(cls, d: dict) -> AddressingPattern | None:
|
167
|
+
return cls(**d) if len(d) > 0 else None
|
@@ -0,0 +1,59 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
# Ising coupling coefficient depending on the Rydberg level
|
4
|
+
# Include a normalization to the Planck constant hbar
|
5
|
+
# In units of [rad . µm^6 / µs]
|
6
|
+
|
7
|
+
C6_DICT = {
|
8
|
+
50: 96120.72,
|
9
|
+
51: 122241.6,
|
10
|
+
52: 154693.02,
|
11
|
+
53: 194740.36,
|
12
|
+
54: 243973.91,
|
13
|
+
55: 304495.01,
|
14
|
+
56: 378305.98,
|
15
|
+
57: 468027.05,
|
16
|
+
58: 576714.85,
|
17
|
+
59: 707911.38,
|
18
|
+
60: 865723.02,
|
19
|
+
61: 1054903.11,
|
20
|
+
62: 1281042.11,
|
21
|
+
63: 1550531.15,
|
22
|
+
64: 1870621.31,
|
23
|
+
65: 2249728.57,
|
24
|
+
66: 2697498.69,
|
25
|
+
67: 3224987.51,
|
26
|
+
68: 3844734.37,
|
27
|
+
69: 4571053.32,
|
28
|
+
70: 5420158.53,
|
29
|
+
71: 6410399.4,
|
30
|
+
72: 7562637.31,
|
31
|
+
73: 8900342.14,
|
32
|
+
74: 10449989.62,
|
33
|
+
75: 12241414.53,
|
34
|
+
76: 14308028.03,
|
35
|
+
77: 16687329.94,
|
36
|
+
78: 19421333.62,
|
37
|
+
79: 22557029.94,
|
38
|
+
80: 26146720.74,
|
39
|
+
81: 30248886.65,
|
40
|
+
82: 34928448.69,
|
41
|
+
83: 40257623.67,
|
42
|
+
84: 46316557.88,
|
43
|
+
85: 53194043.52,
|
44
|
+
86: 60988354.64,
|
45
|
+
87: 69808179.15,
|
46
|
+
88: 79773468.88,
|
47
|
+
89: 91016513.07,
|
48
|
+
90: 103677784.57,
|
49
|
+
91: 117933293.96,
|
50
|
+
92: 133943541.9,
|
51
|
+
93: 151907135.94,
|
52
|
+
94: 172036137.34,
|
53
|
+
95: 194562889.89,
|
54
|
+
96: 219741590.56,
|
55
|
+
97: 247850178.91,
|
56
|
+
98: 279192193.77,
|
57
|
+
99: 314098829.39,
|
58
|
+
100: 352931119.11,
|
59
|
+
}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass, fields
|
4
|
+
|
5
|
+
from torch import pi
|
6
|
+
|
7
|
+
from qadence.analog import AddressingPattern
|
8
|
+
from qadence.types import DeviceType, Interaction
|
9
|
+
|
10
|
+
|
11
|
+
@dataclass(frozen=True, eq=True)
|
12
|
+
class RydbergDevice:
|
13
|
+
"""
|
14
|
+
Dataclass for interacting Rydberg atoms under an Hamiltonian:
|
15
|
+
|
16
|
+
H = ∑_i [Ω/2 * (cos(φ) * Xᵢ - sin(φ) * Yᵢ) - δ * N_i] + H_int,
|
17
|
+
|
18
|
+
where:
|
19
|
+
|
20
|
+
H_int = ∑_(j<i) (C_6 / R**6) * (N_i @ N_j) for the NN interaction;
|
21
|
+
|
22
|
+
H_int = ∑_(j<i) (C_3 / R**3) * ((X_i @ X_j) + (Y_i @ Y_j)) for the XY interaction;
|
23
|
+
"""
|
24
|
+
|
25
|
+
interaction: Interaction = Interaction.NN
|
26
|
+
"""Defines the interaction Hamiltonian."""
|
27
|
+
|
28
|
+
rydberg_level: int = 60
|
29
|
+
"""Rydberg level affecting the value of C_6."""
|
30
|
+
|
31
|
+
coeff_xy: float = 3700.00
|
32
|
+
"""Value of C_3."""
|
33
|
+
|
34
|
+
max_detuning: float = 2 * pi * 4
|
35
|
+
"""Maximum value of the detuning δ."""
|
36
|
+
|
37
|
+
max_amp: float = 2 * pi * 3
|
38
|
+
"""Maximum value of the amplitude Ω."""
|
39
|
+
|
40
|
+
pattern: AddressingPattern | None = None
|
41
|
+
"""Semi-local addressing pattern configuration."""
|
42
|
+
|
43
|
+
type: DeviceType = DeviceType.IDEALIZED
|
44
|
+
"""DeviceType.IDEALIZED or REALISTIC to convert to the Pulser backend."""
|
45
|
+
|
46
|
+
def __post_init__(self) -> None:
|
47
|
+
# FIXME: Currently not supporting custom interaction functions.
|
48
|
+
if self.interaction not in [Interaction.NN, Interaction.XY]:
|
49
|
+
raise KeyError(
|
50
|
+
"RydbergDevice currently only supports Interaction.NN or Interaction.XY."
|
51
|
+
)
|
52
|
+
|
53
|
+
def _to_dict(self) -> dict:
|
54
|
+
device_dict = {}
|
55
|
+
for field in fields(self):
|
56
|
+
if field.name != "pattern":
|
57
|
+
device_dict[field.name] = getattr(self, field.name)
|
58
|
+
else:
|
59
|
+
device_dict[field.name] = (
|
60
|
+
self.pattern._to_dict() if self.pattern is not None else {}
|
61
|
+
)
|
62
|
+
return device_dict
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def _from_dict(cls, d: dict) -> RydbergDevice:
|
66
|
+
pattern = AddressingPattern._from_dict(d["pattern"])
|
67
|
+
d["pattern"] = pattern
|
68
|
+
return cls(**d)
|
69
|
+
|
70
|
+
|
71
|
+
def IdealDevice(pattern: AddressingPattern | None = None) -> RydbergDevice:
|
72
|
+
return RydbergDevice(
|
73
|
+
pattern=pattern,
|
74
|
+
type=DeviceType.IDEALIZED,
|
75
|
+
)
|
76
|
+
|
77
|
+
|
78
|
+
def RealisticDevice(pattern: AddressingPattern | None = None) -> RydbergDevice:
|
79
|
+
return RydbergDevice(
|
80
|
+
pattern=pattern,
|
81
|
+
type=DeviceType.REALISTIC,
|
82
|
+
)
|