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.
Files changed (146) hide show
  1. {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/build_docs.yml +1 -1
  2. {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/lint.yml +1 -1
  3. {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/test_all.yml +2 -2
  4. {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/test_examples.yml +1 -1
  5. {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/test_fast.yml +3 -3
  6. {qadence-1.2.0 → qadence-1.2.1}/PKG-INFO +21 -2
  7. {qadence-1.2.0 → qadence-1.2.1}/README.md +4 -1
  8. {qadence-1.2.0 → qadence-1.2.1}/pyproject.toml +22 -4
  9. {qadence-1.2.0 → qadence-1.2.1}/qadence/__init__.py +1 -0
  10. {qadence-1.2.0 → qadence-1.2.1}/qadence/backend.py +18 -14
  11. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/__init__.py +1 -2
  12. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/api.py +27 -9
  13. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/braket/backend.py +2 -1
  14. qadence-1.2.1/qadence/backends/horqrux/backend.py +216 -0
  15. qadence-1.2.1/qadence/backends/horqrux/config.py +26 -0
  16. qadence-1.2.1/qadence/backends/horqrux/convert_ops.py +273 -0
  17. qadence-1.2.1/qadence/backends/jax_utils.py +45 -0
  18. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/backend.py +2 -1
  19. qadence-1.2.1/qadence/backends/pyqtorch/__init__.py +5 -0
  20. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pyqtorch/backend.py +2 -1
  21. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pyqtorch/convert_ops.py +3 -3
  22. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/utils.py +8 -3
  23. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/embedding.py +46 -24
  24. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/utils.py +20 -1
  25. {qadence-1.2.0 → qadence-1.2.1}/qadence/circuit.py +3 -9
  26. qadence-1.2.1/qadence/engines/differentiable_backend.py +152 -0
  27. qadence-1.2.1/qadence/engines/jax/__init__.py +8 -0
  28. qadence-1.2.1/qadence/engines/jax/differentiable_backend.py +73 -0
  29. qadence-1.2.1/qadence/engines/jax/differentiable_expectation.py +94 -0
  30. qadence-1.2.1/qadence/engines/torch/__init__.py +4 -0
  31. qadence-1.2.1/qadence/engines/torch/differentiable_backend.py +85 -0
  32. qadence-1.2.0/qadence/backends/pytorch_wrapper.py → qadence-1.2.1/qadence/engines/torch/differentiable_expectation.py +1 -2
  33. {qadence-1.2.0 → qadence-1.2.1}/qadence/extensions.py +20 -3
  34. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/models.py +10 -3
  35. {qadence-1.2.0 → qadence-1.2.1}/qadence/models/quantum_model.py +13 -2
  36. {qadence-1.2.0 → qadence-1.2.1}/qadence/parameters.py +19 -16
  37. qadence-1.2.1/qadence/py.typed +0 -0
  38. {qadence-1.2.0 → qadence-1.2.1}/qadence/types.py +13 -1
  39. {qadence-1.2.0 → qadence-1.2.1}/.coveragerc +0 -0
  40. {qadence-1.2.0 → qadence-1.2.1}/.github/dependabot.yml +0 -0
  41. {qadence-1.2.0 → qadence-1.2.1}/.github/workflows/dependabot.yml +0 -0
  42. {qadence-1.2.0 → qadence-1.2.1}/.gitignore +0 -0
  43. {qadence-1.2.0 → qadence-1.2.1}/.pre-commit-config.yaml +0 -0
  44. {qadence-1.2.0 → qadence-1.2.1}/CODE_OF_CONDUCT.md +0 -0
  45. {qadence-1.2.0 → qadence-1.2.1}/CONTRIBUTING.md +0 -0
  46. {qadence-1.2.0 → qadence-1.2.1}/LICENSE +0 -0
  47. {qadence-1.2.0 → qadence-1.2.1}/MANIFEST.in +0 -0
  48. {qadence-1.2.0 → qadence-1.2.1}/mkdocs.yml +0 -0
  49. {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/__init__.py +0 -0
  50. {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/addressing.py +0 -0
  51. {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/constants.py +0 -0
  52. {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/device.py +0 -0
  53. {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/hamiltonian_terms.py +0 -0
  54. {qadence-1.2.0 → qadence-1.2.1}/qadence/analog/parse_analog.py +0 -0
  55. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/adjoint.py +0 -0
  56. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/braket/__init__.py +0 -0
  57. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/braket/config.py +0 -0
  58. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/braket/convert_ops.py +0 -0
  59. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/gpsr.py +0 -0
  60. {qadence-1.2.0/qadence/backends/pyqtorch → qadence-1.2.1/qadence/backends/horqrux}/__init__.py +0 -0
  61. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/__init__.py +0 -0
  62. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/channels.py +0 -0
  63. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/cloud.py +0 -0
  64. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/config.py +0 -0
  65. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/convert_ops.py +0 -0
  66. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/devices.py +0 -0
  67. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/pulses.py +0 -0
  68. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pulser/waveforms.py +0 -0
  69. {qadence-1.2.0 → qadence-1.2.1}/qadence/backends/pyqtorch/config.py +0 -0
  70. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/__init__.py +0 -0
  71. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/abstract.py +0 -0
  72. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/analog.py +0 -0
  73. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/block_to_tensor.py +0 -0
  74. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/composite.py +0 -0
  75. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/manipulate.py +0 -0
  76. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/matrix.py +0 -0
  77. {qadence-1.2.0 → qadence-1.2.1}/qadence/blocks/primitive.py +0 -0
  78. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/__init__.py +0 -0
  79. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/ansatze.py +0 -0
  80. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/daqc/__init__.py +0 -0
  81. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/daqc/daqc.py +0 -0
  82. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/daqc/gen_parser.py +0 -0
  83. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/daqc/utils.py +0 -0
  84. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/feature_maps.py +0 -0
  85. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/hamiltonians.py +0 -0
  86. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/iia.py +0 -0
  87. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/qft.py +0 -0
  88. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/rydberg_feature_maps.py +0 -0
  89. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/rydberg_hea.py +0 -0
  90. {qadence-1.2.0 → qadence-1.2.1}/qadence/constructors/utils.py +0 -0
  91. {qadence-1.2.0 → qadence-1.2.1}/qadence/decompose.py +0 -0
  92. {qadence-1.2.0 → qadence-1.2.1}/qadence/divergences.py +0 -0
  93. {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/__init__.py +0 -0
  94. {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/assets/dark/measurement.png +0 -0
  95. {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/assets/dark/measurement.svg +0 -0
  96. {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/assets/light/measurement.png +0 -0
  97. {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/assets/light/measurement.svg +0 -0
  98. {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/themes.py +0 -0
  99. {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/utils.py +0 -0
  100. {qadence-1.2.0 → qadence-1.2.1}/qadence/draw/vizbackend.py +0 -0
  101. /qadence-1.2.0/qadence/py.typed → /qadence-1.2.1/qadence/engines/__init__.py +0 -0
  102. {qadence-1.2.0 → qadence-1.2.1}/qadence/exceptions/__init__.py +0 -0
  103. {qadence-1.2.0 → qadence-1.2.1}/qadence/exceptions/exceptions.py +0 -0
  104. {qadence-1.2.0 → qadence-1.2.1}/qadence/execution.py +0 -0
  105. {qadence-1.2.0 → qadence-1.2.1}/qadence/finitediff.py +0 -0
  106. {qadence-1.2.0 → qadence-1.2.1}/qadence/logger.py +0 -0
  107. {qadence-1.2.0 → qadence-1.2.1}/qadence/measurements/__init__.py +0 -0
  108. {qadence-1.2.0 → qadence-1.2.1}/qadence/measurements/protocols.py +0 -0
  109. {qadence-1.2.0 → qadence-1.2.1}/qadence/measurements/shadow.py +0 -0
  110. {qadence-1.2.0 → qadence-1.2.1}/qadence/measurements/tomography.py +0 -0
  111. {qadence-1.2.0 → qadence-1.2.1}/qadence/mitigations/__init__.py +0 -0
  112. {qadence-1.2.0 → qadence-1.2.1}/qadence/mitigations/analog_zne.py +0 -0
  113. {qadence-1.2.0 → qadence-1.2.1}/qadence/mitigations/protocols.py +0 -0
  114. {qadence-1.2.0 → qadence-1.2.1}/qadence/mitigations/readout.py +0 -0
  115. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/__init__.py +0 -0
  116. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/config.py +0 -0
  117. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/data.py +0 -0
  118. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/optimize_step.py +0 -0
  119. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/parameters.py +0 -0
  120. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/printing.py +0 -0
  121. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/saveload.py +0 -0
  122. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/tensors.py +0 -0
  123. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/train_grad.py +0 -0
  124. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/train_no_grad.py +0 -0
  125. {qadence-1.2.0 → qadence-1.2.1}/qadence/ml_tools/utils.py +0 -0
  126. {qadence-1.2.0 → qadence-1.2.1}/qadence/models/__init__.py +0 -0
  127. {qadence-1.2.0 → qadence-1.2.1}/qadence/models/qnn.py +0 -0
  128. {qadence-1.2.0 → qadence-1.2.1}/qadence/noise/__init__.py +0 -0
  129. {qadence-1.2.0 → qadence-1.2.1}/qadence/noise/protocols.py +0 -0
  130. {qadence-1.2.0 → qadence-1.2.1}/qadence/noise/readout.py +0 -0
  131. {qadence-1.2.0 → qadence-1.2.1}/qadence/operations.py +0 -0
  132. {qadence-1.2.0 → qadence-1.2.1}/qadence/overlap.py +0 -0
  133. {qadence-1.2.0 → qadence-1.2.1}/qadence/qubit_support.py +0 -0
  134. {qadence-1.2.0 → qadence-1.2.1}/qadence/register.py +0 -0
  135. {qadence-1.2.0 → qadence-1.2.1}/qadence/serialization.py +0 -0
  136. {qadence-1.2.0 → qadence-1.2.1}/qadence/states.py +0 -0
  137. {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/__init__.py +0 -0
  138. {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/apply_fn.py +0 -0
  139. {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/block.py +0 -0
  140. {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/circuit.py +0 -0
  141. {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/digitalize.py +0 -0
  142. {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/flatten.py +0 -0
  143. {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/invert.py +0 -0
  144. {qadence-1.2.0 → qadence-1.2.1}/qadence/transpile/transpile.py +0 -0
  145. {qadence-1.2.0 → qadence-1.2.1}/qadence/utils.py +0 -0
  146. {qadence-1.2.0 → qadence-1.2.1}/setup.py +0 -0
@@ -35,7 +35,7 @@ jobs:
35
35
  run: sudo apt-get install -y graphviz
36
36
 
37
37
  - name: Set up Python 3.10
38
- uses: actions/setup-python@v4
38
+ uses: actions/setup-python@v5
39
39
  with:
40
40
  python-version: '3.10'
41
41
 
@@ -17,7 +17,7 @@ jobs:
17
17
  uses: actions/checkout@v4
18
18
 
19
19
  - name: Set up Python 3.x
20
- uses: actions/setup-python@v4
20
+ uses: actions/setup-python@v5
21
21
  with:
22
22
  python-version: '3.x'
23
23
 
@@ -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@v4
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@v4
50
+ uses: actions/setup-python@v5
51
51
  with:
52
52
  python-version: ${{ matrix.python-version }}
53
53
 
@@ -24,7 +24,7 @@ jobs:
24
24
  run: sudo apt-get install -y graphviz
25
25
 
26
26
  - name: Select Python 3.10
27
- uses: actions/setup-python@v4
27
+ uses: actions/setup-python@v5
28
28
  with:
29
29
  python-version: '3.10'
30
30
 
@@ -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@v4
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@v4
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@v4
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.0
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. It is possible to install additional backends and the circuit visualization library using the following extras:
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. It is possible to install additional backends and the circuit visualization library using the following extras:
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.0"
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
- "openfermion",
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
@@ -11,6 +11,7 @@ from .backends import *
11
11
  from .blocks import *
12
12
  from .circuit import *
13
13
  from .constructors import *
14
+ from .engines import *
14
15
  from .exceptions import *
15
16
  from .execution import *
16
17
  from .measurements import *
@@ -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: Tensor | None = None,
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, Tensor] = {},
263
- state: Tensor | None = None,
266
+ param_values: dict[str, ArrayLike] = {},
267
+ state: ArrayLike | None = None,
264
268
  endianness: Endianness = Endianness.BIG,
265
- ) -> Tensor:
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, Tensor] = {},
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
- ) -> Tensor:
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, Tensor] = {},
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: dict[str, Tensor] = {},
339
- state: Tensor | None = None,
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
- ) -> Tensor:
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: dict[str, Tensor]
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", "DifferentiableBackend"]
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.backends.pytorch_wrapper import DifferentiableBackend
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 (KeyError, ValueError):
23
- raise NotImplementedError(f"The requested backend '{backend_name}' is not implemented.")
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
- backend_inst = DifferentiableBackend(backend_inst, DiffMode(diff_mode))
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()