qadence 1.2.0__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.2.0 → qadence-1.2.1}/.github/workflows/build_docs.yml +1 -1
- {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/lint.yml +1 -1
- {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/test_all.yml +2 -2
- {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/test_examples.yml +1 -1
- {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/test_fast.yml +3 -3
- {qadence-1.2.0 → qadence-1.2.1}/PKG-INFO +21 -2
- {qadence-1.2.0 → qadence-1.2.1}/README.md +4 -1
- {qadence-1.2.0 → qadence-1.2.1}/pyproject.toml +22 -4
- {qadence-1.2.0 → qadence-1.2.1}/qadence/__init__.py +1 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backend.py +18 -14
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/__init__.py +1 -2
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/api.py +27 -9
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/braket/backend.py +2 -1
- 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.2.0 → qadence-1.2.1}/qadence/backends/pulser/backend.py +2 -1
- qadence-1.2.1/qadence/backends/pyqtorch/__init__.py +5 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pyqtorch/backend.py +2 -1
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pyqtorch/convert_ops.py +3 -3
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/utils.py +8 -3
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/embedding.py +46 -24
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/utils.py +20 -1
- {qadence-1.2.0 → qadence-1.2.1}/qadence/circuit.py +3 -9
- 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.2.0/qadence/backends/pytorch_wrapper.py → qadence-1.2.1/qadence/engines/torch/differentiable_expectation.py +1 -2
- {qadence-1.2.0 → qadence-1.2.1}/qadence/extensions.py +20 -3
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/models.py +10 -3
- {qadence-1.2.0 → qadence-1.2.1}/qadence/models/quantum_model.py +13 -2
- {qadence-1.2.0 → qadence-1.2.1}/qadence/parameters.py +19 -16
- qadence-1.2.1/qadence/py.typed +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/types.py +13 -1
- {qadence-1.2.0 → qadence-1.2.1}/.coveragerc +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/.github/dependabot.yml +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/dependabot.yml +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/.gitignore +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/.pre-commit-config.yaml +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/CODE_OF_CONDUCT.md +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/CONTRIBUTING.md +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/LICENSE +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/MANIFEST.in +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/mkdocs.yml +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/addressing.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/constants.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/device.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/hamiltonian_terms.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/parse_analog.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/adjoint.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/braket/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/braket/config.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/braket/convert_ops.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/gpsr.py +0 -0
- {qadence-1.2.0/qadence/backends/pyqtorch → qadence-1.2.1/qadence/backends/horqrux}/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/channels.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/cloud.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/config.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/convert_ops.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/devices.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/pulses.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/waveforms.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pyqtorch/config.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/abstract.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/analog.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/block_to_tensor.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/composite.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/manipulate.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/matrix.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/primitive.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/ansatze.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/daqc/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/daqc/daqc.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/daqc/gen_parser.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/daqc/utils.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/feature_maps.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/hamiltonians.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/iia.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/qft.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/rydberg_feature_maps.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/rydberg_hea.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/utils.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/decompose.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/divergences.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/assets/dark/measurement.png +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/assets/dark/measurement.svg +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/assets/light/measurement.png +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/assets/light/measurement.svg +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/themes.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/utils.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/vizbackend.py +0 -0
- /qadence-1.2.0/qadence/py.typed → /qadence-1.2.1/qadence/engines/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/exceptions/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/exceptions/exceptions.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/execution.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/finitediff.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/logger.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/measurements/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/measurements/protocols.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/measurements/shadow.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/measurements/tomography.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/mitigations/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/mitigations/analog_zne.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/mitigations/protocols.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/mitigations/readout.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/config.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/data.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/optimize_step.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/parameters.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/printing.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/saveload.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/tensors.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/train_grad.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/train_no_grad.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/utils.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/models/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/models/qnn.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/noise/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/noise/protocols.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/noise/readout.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/operations.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/overlap.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/qubit_support.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/register.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/serialization.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/states.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/__init__.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/apply_fn.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/block.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/circuit.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/digitalize.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/flatten.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/invert.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/transpile.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/qadence/utils.py +0 -0
- {qadence-1.2.0 → qadence-1.2.1}/setup.py +0 -0
@@ -23,7 +23,7 @@ jobs:
|
|
23
23
|
uses: actions/checkout@v4
|
24
24
|
|
25
25
|
- name: Set up Python ${{ matrix.python-version }}
|
26
|
-
uses: actions/setup-python@
|
26
|
+
uses: actions/setup-python@v5
|
27
27
|
with:
|
28
28
|
python-version: ${{ matrix.python-version }}
|
29
29
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
47
47
|
uses: actions/checkout@v4
|
48
48
|
|
49
49
|
- name: Set up Python ${{ matrix.python-version }}
|
50
|
-
uses: actions/setup-python@
|
50
|
+
uses: actions/setup-python@v5
|
51
51
|
with:
|
52
52
|
python-version: ${{ matrix.python-version }}
|
53
53
|
|
@@ -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.2.
|
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,6 +18,7 @@ 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
23
|
Requires-Dist: pyqtorch==1.0.3
|
23
24
|
Requires-Dist: rich
|
@@ -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
|
@@ -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.2.
|
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",
|
@@ -41,7 +42,7 @@ dependencies = [
|
|
41
42
|
"nevergrad",
|
42
43
|
"scipy",
|
43
44
|
"pyqtorch==1.0.3",
|
44
|
-
"matplotlib"
|
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]
|
@@ -120,7 +137,7 @@ dependencies = [
|
|
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
|
@@ -25,7 +25,7 @@ from qadence.measurements import Measurements
|
|
25
25
|
from qadence.mitigations import Mitigations
|
26
26
|
from qadence.noise import Noise
|
27
27
|
from qadence.parameters import stringify
|
28
|
-
from qadence.types import BackendName, DiffMode, Endianness
|
28
|
+
from qadence.types import ArrayLike, BackendName, DiffMode, Endianness, Engine, ParamDictType
|
29
29
|
from qadence.utils import validate_values_and_state
|
30
30
|
|
31
31
|
logger = get_logger(__file__)
|
@@ -100,11 +100,14 @@ class Backend(ABC):
|
|
100
100
|
name: backend unique string identifier
|
101
101
|
supports_ad: whether or not the backend has a native autograd
|
102
102
|
supports_bp: whether or not the backend has a native backprop
|
103
|
+
supports_adjoint: Does the backend support native adjoint differentation.
|
103
104
|
is_remote: whether computations are executed locally or remotely on this
|
104
105
|
backend, useful when using cloud platforms where credentials are
|
105
106
|
needed for example.
|
106
107
|
with_measurements: whether it supports counts or not
|
107
108
|
with_noise: whether to add realistic noise or not
|
109
|
+
native_endianness: The native endianness of the backend
|
110
|
+
engine: The underlying (native) automatic differentiation engine of the backend.
|
108
111
|
"""
|
109
112
|
|
110
113
|
name: BackendName
|
@@ -114,6 +117,7 @@ class Backend(ABC):
|
|
114
117
|
is_remote: bool
|
115
118
|
with_measurements: bool
|
116
119
|
native_endianness: Endianness
|
120
|
+
engine: Engine
|
117
121
|
|
118
122
|
# FIXME: should this also go into the configuration?
|
119
123
|
with_noise: bool
|
@@ -199,7 +203,7 @@ class Backend(ABC):
|
|
199
203
|
|
200
204
|
conv_circ = self.circuit(circuit)
|
201
205
|
circ_params, circ_embedding_fn = embedding(
|
202
|
-
conv_circ.abstract.block, self.config._use_gate_params
|
206
|
+
conv_circ.abstract.block, self.config._use_gate_params, self.engine
|
203
207
|
)
|
204
208
|
params = circ_params
|
205
209
|
if observable is not None:
|
@@ -211,7 +215,7 @@ class Backend(ABC):
|
|
211
215
|
obs = check_observable(obs)
|
212
216
|
c_obs = self.observable(obs, max(circuit.n_qubits, obs.n_qubits))
|
213
217
|
obs_params, obs_embedding_fn = embedding(
|
214
|
-
c_obs.abstract, self.config._use_gate_params
|
218
|
+
c_obs.abstract, self.config._use_gate_params, self.engine
|
215
219
|
)
|
216
220
|
params.update(obs_params)
|
217
221
|
obs_embedding_fn_list.append(obs_embedding_fn)
|
@@ -236,7 +240,7 @@ class Backend(ABC):
|
|
236
240
|
circuit: ConvertedCircuit,
|
237
241
|
param_values: dict[str, Tensor] = {},
|
238
242
|
n_shots: int = 1000,
|
239
|
-
state:
|
243
|
+
state: ArrayLike | None = None,
|
240
244
|
noise: Noise | None = None,
|
241
245
|
mitigation: Mitigations | None = None,
|
242
246
|
endianness: Endianness = Endianness.BIG,
|
@@ -259,10 +263,10 @@ class Backend(ABC):
|
|
259
263
|
def _run(
|
260
264
|
self,
|
261
265
|
circuit: ConvertedCircuit,
|
262
|
-
param_values: dict[str,
|
263
|
-
state:
|
266
|
+
param_values: dict[str, ArrayLike] = {},
|
267
|
+
state: ArrayLike | None = None,
|
264
268
|
endianness: Endianness = Endianness.BIG,
|
265
|
-
) ->
|
269
|
+
) -> ArrayLike:
|
266
270
|
"""Run a circuit and return the resulting wave function.
|
267
271
|
|
268
272
|
Arguments:
|
@@ -281,12 +285,12 @@ class Backend(ABC):
|
|
281
285
|
def run(
|
282
286
|
self,
|
283
287
|
circuit: ConvertedCircuit,
|
284
|
-
param_values: dict[str,
|
288
|
+
param_values: dict[str, ArrayLike] = {},
|
285
289
|
state: Tensor | None = None,
|
286
290
|
endianness: Endianness = Endianness.BIG,
|
287
291
|
*args: Any,
|
288
292
|
**kwargs: Any,
|
289
|
-
) ->
|
293
|
+
) -> ArrayLike:
|
290
294
|
"""Run a circuit and return the resulting wave function.
|
291
295
|
|
292
296
|
Arguments:
|
@@ -308,7 +312,7 @@ class Backend(ABC):
|
|
308
312
|
self,
|
309
313
|
circuit: ConvertedCircuit,
|
310
314
|
noise: Noise,
|
311
|
-
param_values: dict[str,
|
315
|
+
param_values: dict[str, ArrayLike] = {},
|
312
316
|
state: Tensor | None = None,
|
313
317
|
endianness: Endianness = Endianness.BIG,
|
314
318
|
) -> Tensor:
|
@@ -335,13 +339,13 @@ class Backend(ABC):
|
|
335
339
|
self,
|
336
340
|
circuit: ConvertedCircuit,
|
337
341
|
observable: list[ConvertedObservable] | ConvertedObservable,
|
338
|
-
param_values:
|
339
|
-
state:
|
342
|
+
param_values: ParamDictType = {},
|
343
|
+
state: ArrayLike | None = None,
|
340
344
|
measurement: Measurements | None = None,
|
341
345
|
noise: Noise | None = None,
|
342
346
|
mitigation: Mitigations | None = None,
|
343
347
|
endianness: Endianness = Endianness.BIG,
|
344
|
-
) ->
|
348
|
+
) -> ArrayLike:
|
345
349
|
"""Compute the expectation value of the `circuit` with the given `observable`.
|
346
350
|
|
347
351
|
Arguments:
|
@@ -398,7 +402,7 @@ class Converted:
|
|
398
402
|
circuit: ConvertedCircuit
|
399
403
|
observable: list[ConvertedObservable] | ConvertedObservable | None
|
400
404
|
embedding_fn: Callable
|
401
|
-
params:
|
405
|
+
params: ParamDictType
|
402
406
|
|
403
407
|
def __iter__(self) -> Iterator:
|
404
408
|
yield self.circuit
|
@@ -2,7 +2,6 @@
|
|
2
2
|
from __future__ import annotations
|
3
3
|
|
4
4
|
from .api import backend_factory, config_factory
|
5
|
-
from .pytorch_wrapper import DifferentiableBackend
|
6
5
|
|
7
6
|
# Modules to be automatically added to the qadence namespace
|
8
|
-
__all__ = ["backend_factory", "config_factory"
|
7
|
+
__all__ = ["backend_factory", "config_factory"]
|
@@ -1,9 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from qadence.backend import Backend, BackendConfiguration
|
4
|
-
from qadence.
|
5
|
-
from qadence.extensions import available_backends, set_backend_config
|
6
|
-
from qadence.types import BackendName, DiffMode
|
4
|
+
from qadence.engines.differentiable_backend import DifferentiableBackend
|
5
|
+
from qadence.extensions import available_backends, available_engines, set_backend_config
|
6
|
+
from qadence.types import BackendName, DiffMode, Engine
|
7
7
|
|
8
8
|
__all__ = ["backend_factory", "config_factory"]
|
9
9
|
|
@@ -14,13 +14,18 @@ def backend_factory(
|
|
14
14
|
configuration: BackendConfiguration | dict | None = None,
|
15
15
|
) -> Backend | DifferentiableBackend:
|
16
16
|
backend_inst: Backend | DifferentiableBackend
|
17
|
-
backend_name = BackendName(backend)
|
18
17
|
backends = available_backends()
|
19
|
-
|
18
|
+
try:
|
19
|
+
backend_name = BackendName(backend)
|
20
|
+
except ValueError:
|
21
|
+
raise NotImplementedError(f"The requested backend '{backend}' is not implemented.")
|
20
22
|
try:
|
21
23
|
BackendCls = backends[backend_name]
|
22
|
-
except
|
23
|
-
raise
|
24
|
+
except Exception as e:
|
25
|
+
raise ImportError(
|
26
|
+
f"The requested backend '{backend_name}' is either not installed\
|
27
|
+
or could not be imported due to {e}."
|
28
|
+
)
|
24
29
|
|
25
30
|
default_config = BackendCls.default_configuration()
|
26
31
|
if configuration is None:
|
@@ -44,9 +49,22 @@ def backend_factory(
|
|
44
49
|
|
45
50
|
# Set backend configurations which depend on the differentiation mode
|
46
51
|
set_backend_config(backend_inst, diff_mode)
|
47
|
-
|
52
|
+
# Wrap the quantum Backend in a DifferentiableBackend if a diff_mode is passed.
|
48
53
|
if diff_mode is not None:
|
49
|
-
|
54
|
+
try:
|
55
|
+
engine_name = Engine(backend_inst.engine)
|
56
|
+
except ValueError:
|
57
|
+
raise NotImplementedError(
|
58
|
+
f"The requested engine '{backend_inst.engine}' is not implemented."
|
59
|
+
)
|
60
|
+
try:
|
61
|
+
diff_backend_cls = available_engines()[engine_name]
|
62
|
+
backend_inst = diff_backend_cls(backend=backend_inst, diff_mode=DiffMode(diff_mode)) # type: ignore[arg-type]
|
63
|
+
except Exception as e:
|
64
|
+
raise ImportError(
|
65
|
+
f"The requested engine '{engine_name}' is either not installed\
|
66
|
+
or could not be imported due to {e}."
|
67
|
+
)
|
50
68
|
return backend_inst
|
51
69
|
|
52
70
|
|
@@ -23,7 +23,7 @@ from qadence.noise import Noise
|
|
23
23
|
from qadence.noise.protocols import apply_noise
|
24
24
|
from qadence.overlap import overlap_exact
|
25
25
|
from qadence.transpile import transpile
|
26
|
-
from qadence.types import BackendName
|
26
|
+
from qadence.types import BackendName, Engine
|
27
27
|
from qadence.utils import Endianness
|
28
28
|
|
29
29
|
from .config import Configuration, default_passes
|
@@ -55,6 +55,7 @@ class Backend(BackendInterface):
|
|
55
55
|
with_noise: bool = False
|
56
56
|
native_endianness: Endianness = Endianness.BIG
|
57
57
|
config: Configuration = field(default_factory=Configuration)
|
58
|
+
engine: Engine = Engine.TORCH
|
58
59
|
|
59
60
|
# braket specifics
|
60
61
|
# TODO: include it in the configuration?
|
@@ -0,0 +1,216 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from collections import Counter
|
4
|
+
from dataclasses import dataclass, field
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
import jax
|
8
|
+
import jax.numpy as jnp
|
9
|
+
from horqrux.utils import prepare_state
|
10
|
+
from jax.typing import ArrayLike
|
11
|
+
|
12
|
+
from qadence.backend import Backend as BackendInterface
|
13
|
+
from qadence.backend import ConvertedCircuit, ConvertedObservable
|
14
|
+
from qadence.backends.jax_utils import (
|
15
|
+
tensor_to_jnp,
|
16
|
+
unhorqify,
|
17
|
+
uniform_batchsize,
|
18
|
+
)
|
19
|
+
from qadence.backends.utils import pyqify
|
20
|
+
from qadence.blocks import AbstractBlock
|
21
|
+
from qadence.circuit import QuantumCircuit
|
22
|
+
from qadence.measurements import Measurements
|
23
|
+
from qadence.mitigations import Mitigations
|
24
|
+
from qadence.noise import Noise
|
25
|
+
from qadence.transpile import flatten, scale_primitive_blocks_only, transpile
|
26
|
+
from qadence.types import BackendName, Endianness, Engine, ParamDictType
|
27
|
+
from qadence.utils import int_to_basis
|
28
|
+
|
29
|
+
from .config import Configuration, default_passes
|
30
|
+
from .convert_ops import HorqruxCircuit, convert_block, convert_observable
|
31
|
+
|
32
|
+
|
33
|
+
@dataclass(frozen=True, eq=True)
|
34
|
+
class Backend(BackendInterface):
|
35
|
+
# set standard interface parameters
|
36
|
+
name: BackendName = BackendName.HORQRUX # type: ignore[assignment]
|
37
|
+
supports_ad: bool = True
|
38
|
+
supports_adjoint: bool = False
|
39
|
+
support_bp: bool = True
|
40
|
+
supports_native_psr: bool = False
|
41
|
+
is_remote: bool = False
|
42
|
+
with_measurements: bool = True
|
43
|
+
with_noise: bool = False
|
44
|
+
native_endianness: Endianness = Endianness.BIG
|
45
|
+
config: Configuration = field(default_factory=Configuration)
|
46
|
+
engine: Engine = Engine.JAX
|
47
|
+
|
48
|
+
def circuit(self, circuit: QuantumCircuit) -> ConvertedCircuit:
|
49
|
+
passes = self.config.transpilation_passes
|
50
|
+
if passes is None:
|
51
|
+
passes = default_passes(self.config)
|
52
|
+
|
53
|
+
original_circ = circuit
|
54
|
+
if len(passes) > 0:
|
55
|
+
circuit = transpile(*passes)(circuit)
|
56
|
+
ops = convert_block(circuit.block, n_qubits=circuit.n_qubits, config=self.config)
|
57
|
+
return ConvertedCircuit(
|
58
|
+
native=HorqruxCircuit(ops), abstract=circuit, original=original_circ
|
59
|
+
)
|
60
|
+
|
61
|
+
def observable(self, observable: AbstractBlock, n_qubits: int) -> ConvertedObservable:
|
62
|
+
transpilations = [
|
63
|
+
flatten,
|
64
|
+
scale_primitive_blocks_only,
|
65
|
+
]
|
66
|
+
block = transpile(*transpilations)(observable) # type: ignore[call-overload]
|
67
|
+
hq_obs = convert_observable(block, n_qubits=n_qubits, config=self.config)
|
68
|
+
return ConvertedObservable(native=hq_obs, abstract=block, original=observable)
|
69
|
+
|
70
|
+
def _run(
|
71
|
+
self,
|
72
|
+
circuit: ConvertedCircuit,
|
73
|
+
param_values: ParamDictType = {},
|
74
|
+
state: ArrayLike | None = None,
|
75
|
+
endianness: Endianness = Endianness.BIG,
|
76
|
+
horqify_state: bool = True,
|
77
|
+
unhorqify_state: bool = True,
|
78
|
+
) -> ArrayLike:
|
79
|
+
n_qubits = circuit.abstract.n_qubits
|
80
|
+
if state is None:
|
81
|
+
state = prepare_state(n_qubits, "0" * n_qubits)
|
82
|
+
else:
|
83
|
+
state = tensor_to_jnp(pyqify(state)) if horqify_state else state
|
84
|
+
state = circuit.native.forward(state, param_values)
|
85
|
+
if endianness != self.native_endianness:
|
86
|
+
state = jnp.reshape(state, (1, 2**n_qubits)) # batch_size is always 1
|
87
|
+
ls = list(range(2**n_qubits))
|
88
|
+
permute_ind = jnp.array([int(f"{num:0{n_qubits}b}"[::-1], 2) for num in ls])
|
89
|
+
state = state[:, permute_ind]
|
90
|
+
if unhorqify_state:
|
91
|
+
state = unhorqify(state)
|
92
|
+
return state
|
93
|
+
|
94
|
+
def run_dm(
|
95
|
+
self,
|
96
|
+
circuit: ConvertedCircuit,
|
97
|
+
noise: Noise,
|
98
|
+
param_values: ParamDictType = {},
|
99
|
+
state: ArrayLike | None = None,
|
100
|
+
endianness: Endianness = Endianness.BIG,
|
101
|
+
) -> ArrayLike:
|
102
|
+
raise NotImplementedError
|
103
|
+
|
104
|
+
def expectation(
|
105
|
+
self,
|
106
|
+
circuit: ConvertedCircuit,
|
107
|
+
observable: list[ConvertedObservable] | ConvertedObservable,
|
108
|
+
param_values: ParamDictType = {},
|
109
|
+
state: ArrayLike | None = None,
|
110
|
+
measurement: Measurements | None = None,
|
111
|
+
noise: Noise | None = None,
|
112
|
+
mitigation: Mitigations | None = None,
|
113
|
+
endianness: Endianness = Endianness.BIG,
|
114
|
+
) -> ArrayLike:
|
115
|
+
observable = observable if isinstance(observable, list) else [observable]
|
116
|
+
batch_size = max([arr.size for arr in param_values.values()])
|
117
|
+
n_obs = len(observable)
|
118
|
+
|
119
|
+
def _expectation(params: ParamDictType) -> ArrayLike:
|
120
|
+
out_state = self.run(
|
121
|
+
circuit, params, state, endianness, horqify_state=True, unhorqify_state=False
|
122
|
+
)
|
123
|
+
return jnp.array([o.native.forward(out_state, params) for o in observable])
|
124
|
+
|
125
|
+
if batch_size > 1: # We vmap for batch_size > 1
|
126
|
+
expvals = jax.vmap(_expectation, in_axes=({k: 0 for k in param_values.keys()},))(
|
127
|
+
uniform_batchsize(param_values)
|
128
|
+
)
|
129
|
+
else:
|
130
|
+
expvals = _expectation(param_values)
|
131
|
+
if expvals.size > 1:
|
132
|
+
expvals = jnp.reshape(expvals, (batch_size, n_obs))
|
133
|
+
else:
|
134
|
+
expvals = jnp.squeeze(
|
135
|
+
expvals, 0
|
136
|
+
) # For the case of batch_size == n_obs == 1, we remove the dims
|
137
|
+
return expvals
|
138
|
+
|
139
|
+
def sample(
|
140
|
+
self,
|
141
|
+
circuit: ConvertedCircuit,
|
142
|
+
param_values: ParamDictType = {},
|
143
|
+
n_shots: int = 1,
|
144
|
+
state: ArrayLike | None = None,
|
145
|
+
noise: Noise | None = None,
|
146
|
+
mitigation: Mitigations | None = None,
|
147
|
+
endianness: Endianness = Endianness.BIG,
|
148
|
+
) -> list[Counter]:
|
149
|
+
"""Samples from a batch of discrete probability distributions.
|
150
|
+
|
151
|
+
Args:
|
152
|
+
circuit: A ConvertedCircuit object holding the native PyQ Circuit.
|
153
|
+
param_values: A dict holding the embedded parameters which the native ciruit expects.
|
154
|
+
n_shots: The number of samples to generate per distribution.
|
155
|
+
state: The input state.
|
156
|
+
endianness (Endianness): The target endianness of the resulting samples.
|
157
|
+
|
158
|
+
Returns:
|
159
|
+
A list of Counter objects where each key represents a bitstring
|
160
|
+
and its value the number of times it has been sampled from the given wave function.
|
161
|
+
"""
|
162
|
+
if n_shots < 1:
|
163
|
+
raise ValueError("You can only call sample with n_shots>0.")
|
164
|
+
|
165
|
+
def _sample(
|
166
|
+
_probs: ArrayLike, n_shots: int, endianness: Endianness, n_qubits: int
|
167
|
+
) -> Counter:
|
168
|
+
_logits = jax.vmap(lambda _p: jnp.log(_p / (1 - _p)))(_probs)
|
169
|
+
|
170
|
+
def _smple(accumulator: ArrayLike, i: int) -> tuple[ArrayLike, None]:
|
171
|
+
accumulator = accumulator.at[i].set(
|
172
|
+
jax.random.categorical(jax.random.PRNGKey(i), _logits)
|
173
|
+
)
|
174
|
+
return accumulator, None
|
175
|
+
|
176
|
+
samples = jax.lax.scan(
|
177
|
+
_smple, jnp.empty_like(jnp.arange(n_shots)), jnp.arange(n_shots)
|
178
|
+
)[0]
|
179
|
+
return Counter(
|
180
|
+
{
|
181
|
+
int_to_basis(k=k, n_qubits=n_qubits, endianness=endianness): count.item()
|
182
|
+
for k, count in enumerate(jnp.bincount(samples))
|
183
|
+
if count > 0
|
184
|
+
}
|
185
|
+
)
|
186
|
+
|
187
|
+
wf = self.run(
|
188
|
+
circuit=circuit,
|
189
|
+
param_values=param_values,
|
190
|
+
state=state,
|
191
|
+
horqify_state=True,
|
192
|
+
unhorqify_state=False,
|
193
|
+
)
|
194
|
+
probs = jnp.abs(jnp.float_power(wf, 2.0)).ravel()
|
195
|
+
samples = [
|
196
|
+
_sample(
|
197
|
+
_probs=probs,
|
198
|
+
n_shots=n_shots,
|
199
|
+
endianness=endianness,
|
200
|
+
n_qubits=circuit.abstract.n_qubits,
|
201
|
+
),
|
202
|
+
]
|
203
|
+
|
204
|
+
return samples
|
205
|
+
|
206
|
+
def assign_parameters(self, circuit: ConvertedCircuit, param_values: ParamDictType) -> Any:
|
207
|
+
raise NotImplementedError
|
208
|
+
|
209
|
+
@staticmethod
|
210
|
+
def _overlap(bras: ArrayLike, kets: ArrayLike) -> ArrayLike:
|
211
|
+
# TODO
|
212
|
+
raise NotImplementedError
|
213
|
+
|
214
|
+
@staticmethod
|
215
|
+
def default_configuration() -> Configuration:
|
216
|
+
return Configuration()
|