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.
Files changed (151) hide show
  1. {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/build_docs.yml +1 -1
  2. {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/lint.yml +1 -1
  3. {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/test_all.yml +26 -1
  4. {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/test_examples.yml +1 -1
  5. {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/test_fast.yml +3 -3
  6. {qadence-1.1.1 → qadence-1.2.1}/PKG-INFO +22 -3
  7. {qadence-1.1.1 → qadence-1.2.1}/README.md +4 -1
  8. {qadence-1.1.1 → qadence-1.2.1}/mkdocs.yml +1 -2
  9. {qadence-1.1.1 → qadence-1.2.1}/pyproject.toml +25 -7
  10. {qadence-1.1.1 → qadence-1.2.1}/qadence/__init__.py +1 -0
  11. qadence-1.2.1/qadence/analog/__init__.py +7 -0
  12. qadence-1.2.1/qadence/analog/addressing.py +167 -0
  13. qadence-1.2.1/qadence/analog/constants.py +59 -0
  14. qadence-1.2.1/qadence/analog/device.py +82 -0
  15. qadence-1.2.1/qadence/analog/hamiltonian_terms.py +101 -0
  16. qadence-1.2.1/qadence/analog/parse_analog.py +120 -0
  17. {qadence-1.1.1 → qadence-1.2.1}/qadence/backend.py +42 -12
  18. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/__init__.py +1 -2
  19. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/api.py +27 -9
  20. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/braket/backend.py +3 -2
  21. qadence-1.2.1/qadence/backends/horqrux/backend.py +216 -0
  22. qadence-1.2.1/qadence/backends/horqrux/config.py +26 -0
  23. qadence-1.2.1/qadence/backends/horqrux/convert_ops.py +273 -0
  24. qadence-1.2.1/qadence/backends/jax_utils.py +45 -0
  25. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/__init__.py +0 -1
  26. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/backend.py +31 -15
  27. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/config.py +19 -10
  28. qadence-1.2.1/qadence/backends/pulser/devices.py +71 -0
  29. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/pulses.py +70 -12
  30. qadence-1.2.1/qadence/backends/pyqtorch/__init__.py +5 -0
  31. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pyqtorch/backend.py +4 -4
  32. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pyqtorch/config.py +18 -12
  33. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pyqtorch/convert_ops.py +15 -7
  34. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/utils.py +5 -9
  35. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/abstract.py +5 -1
  36. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/analog.py +18 -9
  37. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/block_to_tensor.py +11 -0
  38. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/embedding.py +46 -24
  39. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/primitive.py +81 -9
  40. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/utils.py +20 -1
  41. {qadence-1.1.1 → qadence-1.2.1}/qadence/circuit.py +3 -9
  42. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/__init__.py +4 -0
  43. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/feature_maps.py +84 -60
  44. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/hamiltonians.py +27 -98
  45. qadence-1.2.1/qadence/constructors/rydberg_feature_maps.py +113 -0
  46. {qadence-1.1.1 → qadence-1.2.1}/qadence/divergences.py +12 -0
  47. qadence-1.2.1/qadence/engines/differentiable_backend.py +152 -0
  48. qadence-1.2.1/qadence/engines/jax/__init__.py +8 -0
  49. qadence-1.2.1/qadence/engines/jax/differentiable_backend.py +73 -0
  50. qadence-1.2.1/qadence/engines/jax/differentiable_expectation.py +94 -0
  51. qadence-1.2.1/qadence/engines/torch/__init__.py +4 -0
  52. qadence-1.2.1/qadence/engines/torch/differentiable_backend.py +85 -0
  53. {qadence-1.1.1 → qadence-1.2.1}/qadence/extensions.py +21 -9
  54. qadence-1.2.1/qadence/finitediff.py +47 -0
  55. qadence-1.2.1/qadence/mitigations/readout.py +160 -0
  56. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/models.py +10 -3
  57. {qadence-1.1.1 → qadence-1.2.1}/qadence/models/qnn.py +88 -23
  58. {qadence-1.1.1 → qadence-1.2.1}/qadence/models/quantum_model.py +13 -2
  59. {qadence-1.1.1 → qadence-1.2.1}/qadence/operations.py +55 -70
  60. {qadence-1.1.1 → qadence-1.2.1}/qadence/parameters.py +24 -13
  61. qadence-1.2.1/qadence/py.typed +0 -0
  62. {qadence-1.1.1 → qadence-1.2.1}/qadence/register.py +91 -43
  63. {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/__init__.py +1 -0
  64. qadence-1.2.1/qadence/transpile/apply_fn.py +40 -0
  65. {qadence-1.1.1 → qadence-1.2.1}/qadence/types.py +32 -2
  66. {qadence-1.1.1 → qadence-1.2.1}/qadence/utils.py +35 -0
  67. qadence-1.1.1/qadence/analog/__init__.py +0 -5
  68. qadence-1.1.1/qadence/analog/interaction.py +0 -198
  69. qadence-1.1.1/qadence/analog/utils.py +0 -132
  70. qadence-1.1.1/qadence/backends/pulser/devices.py +0 -77
  71. qadence-1.1.1/qadence/mitigations/readout.py +0 -93
  72. {qadence-1.1.1 → qadence-1.2.1}/.coveragerc +0 -0
  73. {qadence-1.1.1 → qadence-1.2.1}/.github/dependabot.yml +0 -0
  74. {qadence-1.1.1 → qadence-1.2.1}/.github/workflows/dependabot.yml +0 -0
  75. {qadence-1.1.1 → qadence-1.2.1}/.gitignore +0 -0
  76. {qadence-1.1.1 → qadence-1.2.1}/.pre-commit-config.yaml +0 -0
  77. {qadence-1.1.1 → qadence-1.2.1}/CODE_OF_CONDUCT.md +0 -0
  78. {qadence-1.1.1 → qadence-1.2.1}/CONTRIBUTING.md +0 -0
  79. {qadence-1.1.1 → qadence-1.2.1}/LICENSE +0 -0
  80. {qadence-1.1.1 → qadence-1.2.1}/MANIFEST.in +0 -0
  81. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/adjoint.py +0 -0
  82. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/braket/__init__.py +0 -0
  83. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/braket/config.py +0 -0
  84. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/braket/convert_ops.py +0 -0
  85. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/gpsr.py +0 -0
  86. {qadence-1.1.1/qadence/backends/pyqtorch → qadence-1.2.1/qadence/backends/horqrux}/__init__.py +0 -0
  87. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/channels.py +0 -0
  88. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/cloud.py +0 -0
  89. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/convert_ops.py +0 -0
  90. {qadence-1.1.1 → qadence-1.2.1}/qadence/backends/pulser/waveforms.py +0 -0
  91. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/__init__.py +0 -0
  92. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/composite.py +0 -0
  93. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/manipulate.py +0 -0
  94. {qadence-1.1.1 → qadence-1.2.1}/qadence/blocks/matrix.py +0 -0
  95. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/ansatze.py +0 -0
  96. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/daqc/__init__.py +0 -0
  97. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/daqc/daqc.py +0 -0
  98. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/daqc/gen_parser.py +0 -0
  99. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/daqc/utils.py +0 -0
  100. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/iia.py +0 -0
  101. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/qft.py +0 -0
  102. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/rydberg_hea.py +0 -0
  103. {qadence-1.1.1 → qadence-1.2.1}/qadence/constructors/utils.py +0 -0
  104. {qadence-1.1.1 → qadence-1.2.1}/qadence/decompose.py +0 -0
  105. {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/__init__.py +0 -0
  106. {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/assets/dark/measurement.png +0 -0
  107. {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/assets/dark/measurement.svg +0 -0
  108. {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/assets/light/measurement.png +0 -0
  109. {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/assets/light/measurement.svg +0 -0
  110. {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/themes.py +0 -0
  111. {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/utils.py +0 -0
  112. {qadence-1.1.1 → qadence-1.2.1}/qadence/draw/vizbackend.py +0 -0
  113. /qadence-1.1.1/qadence/py.typed → /qadence-1.2.1/qadence/engines/__init__.py +0 -0
  114. /qadence-1.1.1/qadence/backends/pytorch_wrapper.py → /qadence-1.2.1/qadence/engines/torch/differentiable_expectation.py +0 -0
  115. {qadence-1.1.1 → qadence-1.2.1}/qadence/exceptions/__init__.py +0 -0
  116. {qadence-1.1.1 → qadence-1.2.1}/qadence/exceptions/exceptions.py +0 -0
  117. {qadence-1.1.1 → qadence-1.2.1}/qadence/execution.py +0 -0
  118. {qadence-1.1.1 → qadence-1.2.1}/qadence/logger.py +0 -0
  119. {qadence-1.1.1 → qadence-1.2.1}/qadence/measurements/__init__.py +0 -0
  120. {qadence-1.1.1 → qadence-1.2.1}/qadence/measurements/protocols.py +0 -0
  121. {qadence-1.1.1 → qadence-1.2.1}/qadence/measurements/shadow.py +0 -0
  122. {qadence-1.1.1 → qadence-1.2.1}/qadence/measurements/tomography.py +0 -0
  123. {qadence-1.1.1 → qadence-1.2.1}/qadence/mitigations/__init__.py +0 -0
  124. {qadence-1.1.1 → qadence-1.2.1}/qadence/mitigations/analog_zne.py +0 -0
  125. {qadence-1.1.1 → qadence-1.2.1}/qadence/mitigations/protocols.py +0 -0
  126. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/__init__.py +0 -0
  127. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/config.py +0 -0
  128. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/data.py +0 -0
  129. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/optimize_step.py +0 -0
  130. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/parameters.py +0 -0
  131. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/printing.py +0 -0
  132. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/saveload.py +0 -0
  133. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/tensors.py +0 -0
  134. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/train_grad.py +0 -0
  135. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/train_no_grad.py +0 -0
  136. {qadence-1.1.1 → qadence-1.2.1}/qadence/ml_tools/utils.py +0 -0
  137. {qadence-1.1.1 → qadence-1.2.1}/qadence/models/__init__.py +0 -0
  138. {qadence-1.1.1 → qadence-1.2.1}/qadence/noise/__init__.py +0 -0
  139. {qadence-1.1.1 → qadence-1.2.1}/qadence/noise/protocols.py +0 -0
  140. {qadence-1.1.1 → qadence-1.2.1}/qadence/noise/readout.py +0 -0
  141. {qadence-1.1.1 → qadence-1.2.1}/qadence/overlap.py +0 -0
  142. {qadence-1.1.1 → qadence-1.2.1}/qadence/qubit_support.py +0 -0
  143. {qadence-1.1.1 → qadence-1.2.1}/qadence/serialization.py +0 -0
  144. {qadence-1.1.1 → qadence-1.2.1}/qadence/states.py +0 -0
  145. {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/block.py +0 -0
  146. {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/circuit.py +0 -0
  147. {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/digitalize.py +0 -0
  148. {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/flatten.py +0 -0
  149. {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/invert.py +0 -0
  150. {qadence-1.1.1 → qadence-1.2.1}/qadence/transpile/transpile.py +0 -0
  151. {qadence-1.1.1 → 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
 
@@ -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@v4
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"
@@ -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.1.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.1
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. 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
@@ -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
- - Hardware efficient ansatz with restricted addressability: digital_analog_qc/rydberg-hea.md
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.1.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
- "openfermion",
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.1",
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==1.5.2",
131
+ "mkdocs",
115
132
  "mkdocs-material",
116
133
  "mkdocstrings",
117
134
  "mkdocstrings-python",
118
- "mkdocs-section-index==0.3.6",
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
@@ -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 *
@@ -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
+ )