qadence 1.7.7__tar.gz → 1.8.0__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 (158) hide show
  1. {qadence-1.7.7 → qadence-1.8.0}/PKG-INFO +5 -8
  2. {qadence-1.7.7 → qadence-1.8.0}/mkdocs.yml +1 -0
  3. {qadence-1.7.7 → qadence-1.8.0}/pyproject.toml +8 -9
  4. {qadence-1.7.7 → qadence-1.8.0}/qadence/analog/device.py +1 -1
  5. {qadence-1.7.7 → qadence-1.8.0}/qadence/backend.py +3 -3
  6. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/horqrux/backend.py +3 -3
  7. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/backend.py +16 -17
  8. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/convert_ops.py +2 -2
  9. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pyqtorch/backend.py +7 -7
  10. qadence-1.8.0/qadence/backends/pyqtorch/convert_ops.py +332 -0
  11. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/utils.py +9 -1
  12. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/abstract.py +1 -1
  13. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/embedding.py +21 -11
  14. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/matrix.py +3 -1
  15. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/primitive.py +36 -11
  16. {qadence-1.7.7 → qadence-1.8.0}/qadence/circuit.py +1 -1
  17. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/__init__.py +2 -1
  18. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/ansatze.py +176 -0
  19. {qadence-1.7.7 → qadence-1.8.0}/qadence/engines/differentiable_backend.py +3 -3
  20. {qadence-1.7.7 → qadence-1.8.0}/qadence/engines/jax/differentiable_backend.py +2 -2
  21. {qadence-1.7.7 → qadence-1.8.0}/qadence/engines/jax/differentiable_expectation.py +2 -2
  22. {qadence-1.7.7 → qadence-1.8.0}/qadence/engines/torch/differentiable_backend.py +2 -2
  23. {qadence-1.7.7 → qadence-1.8.0}/qadence/engines/torch/differentiable_expectation.py +2 -2
  24. {qadence-1.7.7 → qadence-1.8.0}/qadence/execution.py +14 -14
  25. {qadence-1.7.7 → qadence-1.8.0}/qadence/extensions.py +1 -1
  26. {qadence-1.7.7 → qadence-1.8.0}/qadence/measurements/shadow.py +4 -5
  27. {qadence-1.7.7 → qadence-1.8.0}/qadence/measurements/tomography.py +2 -2
  28. {qadence-1.7.7 → qadence-1.8.0}/qadence/measurements/utils.py +2 -2
  29. {qadence-1.7.7 → qadence-1.8.0}/qadence/mitigations/analog_zne.py +8 -7
  30. {qadence-1.7.7 → qadence-1.8.0}/qadence/mitigations/protocols.py +2 -2
  31. {qadence-1.7.7 → qadence-1.8.0}/qadence/mitigations/readout.py +8 -5
  32. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/config.py +14 -0
  33. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/constructors.py +9 -4
  34. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/models.py +7 -7
  35. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/printing.py +2 -1
  36. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/train_grad.py +39 -7
  37. {qadence-1.7.7 → qadence-1.8.0}/qadence/model.py +5 -5
  38. qadence-1.8.0/qadence/noise/__init__.py +6 -0
  39. qadence-1.8.0/qadence/noise/protocols.py +241 -0
  40. {qadence-1.7.7 → qadence-1.8.0}/qadence/operations/control_ops.py +37 -22
  41. {qadence-1.7.7 → qadence-1.8.0}/qadence/operations/ham_evo.py +1 -0
  42. {qadence-1.7.7 → qadence-1.8.0}/qadence/operations/parametric.py +32 -10
  43. {qadence-1.7.7 → qadence-1.8.0}/qadence/operations/primitive.py +61 -29
  44. {qadence-1.7.7 → qadence-1.8.0}/qadence/overlap.py +0 -6
  45. {qadence-1.7.7 → qadence-1.8.0}/qadence/parameters.py +3 -2
  46. {qadence-1.7.7 → qadence-1.8.0}/qadence/transpile/__init__.py +2 -1
  47. qadence-1.8.0/qadence/transpile/noise.py +46 -0
  48. {qadence-1.7.7 → qadence-1.8.0}/qadence/types.py +26 -2
  49. {qadence-1.7.7 → qadence-1.8.0}/renovate.json +0 -2
  50. qadence-1.7.7/qadence/backends/braket/__init__.py +0 -4
  51. qadence-1.7.7/qadence/backends/braket/backend.py +0 -234
  52. qadence-1.7.7/qadence/backends/braket/config.py +0 -22
  53. qadence-1.7.7/qadence/backends/braket/convert_ops.py +0 -116
  54. qadence-1.7.7/qadence/backends/pyqtorch/convert_ops.py +0 -381
  55. qadence-1.7.7/qadence/noise/__init__.py +0 -6
  56. qadence-1.7.7/qadence/noise/protocols.py +0 -54
  57. {qadence-1.7.7 → qadence-1.8.0}/.coveragerc +0 -0
  58. {qadence-1.7.7 → qadence-1.8.0}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  59. {qadence-1.7.7 → qadence-1.8.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  60. {qadence-1.7.7 → qadence-1.8.0}/.github/ISSUE_TEMPLATE/new-feature.yml +0 -0
  61. {qadence-1.7.7 → qadence-1.8.0}/.github/workflows/build_docs.yml +0 -0
  62. {qadence-1.7.7 → qadence-1.8.0}/.github/workflows/lint.yml +0 -0
  63. {qadence-1.7.7 → qadence-1.8.0}/.github/workflows/test_all.yml +0 -0
  64. {qadence-1.7.7 → qadence-1.8.0}/.github/workflows/test_examples.yml +0 -0
  65. {qadence-1.7.7 → qadence-1.8.0}/.github/workflows/test_fast.yml +0 -0
  66. {qadence-1.7.7 → qadence-1.8.0}/.gitignore +0 -0
  67. {qadence-1.7.7 → qadence-1.8.0}/.pre-commit-config.yaml +0 -0
  68. {qadence-1.7.7 → qadence-1.8.0}/LICENSE +0 -0
  69. {qadence-1.7.7 → qadence-1.8.0}/MANIFEST.in +0 -0
  70. {qadence-1.7.7 → qadence-1.8.0}/README.md +0 -0
  71. {qadence-1.7.7 → qadence-1.8.0}/qadence/__init__.py +0 -0
  72. {qadence-1.7.7 → qadence-1.8.0}/qadence/analog/__init__.py +0 -0
  73. {qadence-1.7.7 → qadence-1.8.0}/qadence/analog/addressing.py +0 -0
  74. {qadence-1.7.7 → qadence-1.8.0}/qadence/analog/constants.py +0 -0
  75. {qadence-1.7.7 → qadence-1.8.0}/qadence/analog/hamiltonian_terms.py +0 -0
  76. {qadence-1.7.7 → qadence-1.8.0}/qadence/analog/parse_analog.py +0 -0
  77. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/__init__.py +0 -0
  78. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/api.py +0 -0
  79. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/gpsr.py +0 -0
  80. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/horqrux/__init__.py +0 -0
  81. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/horqrux/config.py +0 -0
  82. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/horqrux/convert_ops.py +0 -0
  83. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/jax_utils.py +0 -0
  84. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/__init__.py +0 -0
  85. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/channels.py +0 -0
  86. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/cloud.py +0 -0
  87. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/config.py +0 -0
  88. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/devices.py +0 -0
  89. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/pulses.py +0 -0
  90. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pulser/waveforms.py +0 -0
  91. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pyqtorch/__init__.py +0 -0
  92. {qadence-1.7.7 → qadence-1.8.0}/qadence/backends/pyqtorch/config.py +0 -0
  93. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/__init__.py +0 -0
  94. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/analog.py +0 -0
  95. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/block_to_tensor.py +0 -0
  96. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/composite.py +0 -0
  97. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/manipulate.py +0 -0
  98. {qadence-1.7.7 → qadence-1.8.0}/qadence/blocks/utils.py +0 -0
  99. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/daqc/__init__.py +0 -0
  100. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/daqc/daqc.py +0 -0
  101. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/daqc/gen_parser.py +0 -0
  102. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/daqc/utils.py +0 -0
  103. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/feature_maps.py +0 -0
  104. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/hamiltonians.py +0 -0
  105. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/iia.py +0 -0
  106. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/qft.py +0 -0
  107. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/rydberg_feature_maps.py +0 -0
  108. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/rydberg_hea.py +0 -0
  109. {qadence-1.7.7 → qadence-1.8.0}/qadence/constructors/utils.py +0 -0
  110. {qadence-1.7.7 → qadence-1.8.0}/qadence/decompose.py +0 -0
  111. {qadence-1.7.7 → qadence-1.8.0}/qadence/divergences.py +0 -0
  112. {qadence-1.7.7 → qadence-1.8.0}/qadence/draw/__init__.py +0 -0
  113. {qadence-1.7.7 → qadence-1.8.0}/qadence/draw/assets/dark/measurement.png +0 -0
  114. {qadence-1.7.7 → qadence-1.8.0}/qadence/draw/assets/dark/measurement.svg +0 -0
  115. {qadence-1.7.7 → qadence-1.8.0}/qadence/draw/assets/light/measurement.png +0 -0
  116. {qadence-1.7.7 → qadence-1.8.0}/qadence/draw/assets/light/measurement.svg +0 -0
  117. {qadence-1.7.7 → qadence-1.8.0}/qadence/draw/themes.py +0 -0
  118. {qadence-1.7.7 → qadence-1.8.0}/qadence/draw/utils.py +0 -0
  119. {qadence-1.7.7 → qadence-1.8.0}/qadence/draw/vizbackend.py +0 -0
  120. {qadence-1.7.7 → qadence-1.8.0}/qadence/engines/__init__.py +0 -0
  121. {qadence-1.7.7 → qadence-1.8.0}/qadence/engines/jax/__init__.py +0 -0
  122. {qadence-1.7.7 → qadence-1.8.0}/qadence/engines/torch/__init__.py +0 -0
  123. {qadence-1.7.7 → qadence-1.8.0}/qadence/exceptions/__init__.py +0 -0
  124. {qadence-1.7.7 → qadence-1.8.0}/qadence/exceptions/exceptions.py +0 -0
  125. {qadence-1.7.7 → qadence-1.8.0}/qadence/libs.py +0 -0
  126. {qadence-1.7.7 → qadence-1.8.0}/qadence/log_config.yaml +0 -0
  127. {qadence-1.7.7 → qadence-1.8.0}/qadence/logger.py +0 -0
  128. {qadence-1.7.7 → qadence-1.8.0}/qadence/measurements/__init__.py +0 -0
  129. {qadence-1.7.7 → qadence-1.8.0}/qadence/measurements/protocols.py +0 -0
  130. {qadence-1.7.7 → qadence-1.8.0}/qadence/measurements/samples.py +0 -0
  131. {qadence-1.7.7 → qadence-1.8.0}/qadence/mitigations/__init__.py +0 -0
  132. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/__init__.py +0 -0
  133. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/data.py +0 -0
  134. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/optimize_step.py +0 -0
  135. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/parameters.py +0 -0
  136. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/saveload.py +0 -0
  137. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/tensors.py +0 -0
  138. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/train_no_grad.py +0 -0
  139. {qadence-1.7.7 → qadence-1.8.0}/qadence/ml_tools/utils.py +0 -0
  140. {qadence-1.7.7 → qadence-1.8.0}/qadence/noise/readout.py +0 -0
  141. {qadence-1.7.7 → qadence-1.8.0}/qadence/operations/__init__.py +0 -0
  142. {qadence-1.7.7 → qadence-1.8.0}/qadence/operations/analog.py +0 -0
  143. {qadence-1.7.7 → qadence-1.8.0}/qadence/protocols.py +0 -0
  144. {qadence-1.7.7 → qadence-1.8.0}/qadence/py.typed +0 -0
  145. {qadence-1.7.7 → qadence-1.8.0}/qadence/qubit_support.py +0 -0
  146. {qadence-1.7.7 → qadence-1.8.0}/qadence/register.py +0 -0
  147. {qadence-1.7.7 → qadence-1.8.0}/qadence/serial_expr_grammar.peg +0 -0
  148. {qadence-1.7.7 → qadence-1.8.0}/qadence/serialization.py +0 -0
  149. {qadence-1.7.7 → qadence-1.8.0}/qadence/states.py +0 -0
  150. {qadence-1.7.7 → qadence-1.8.0}/qadence/transpile/apply_fn.py +0 -0
  151. {qadence-1.7.7 → qadence-1.8.0}/qadence/transpile/block.py +0 -0
  152. {qadence-1.7.7 → qadence-1.8.0}/qadence/transpile/circuit.py +0 -0
  153. {qadence-1.7.7 → qadence-1.8.0}/qadence/transpile/digitalize.py +0 -0
  154. {qadence-1.7.7 → qadence-1.8.0}/qadence/transpile/flatten.py +0 -0
  155. {qadence-1.7.7 → qadence-1.8.0}/qadence/transpile/invert.py +0 -0
  156. {qadence-1.7.7 → qadence-1.8.0}/qadence/transpile/transpile.py +0 -0
  157. {qadence-1.7.7 → qadence-1.8.0}/qadence/utils.py +0 -0
  158. {qadence-1.7.7 → qadence-1.8.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qadence
3
- Version: 1.7.7
3
+ Version: 1.8.0
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>, Gergana Velikova <gergana.velikova@pasqal.com>, Eduardo Maschio <eduardo.maschio@pasqal.com>, Smit Chaudhary <smit.chaudhary@pasqal.com>, Ignacio Fernández Graña <ignacio.fernandez-grana@pasqal.com>, Charles Moussa <charles.moussa@pasqal.com>, Giorgio Tosti Balducci <giorgio.tosti-balducci@pasqal.com>, Daniele Cucurachi <daniele.cucurachi@pasqal.com>
6
6
  License: Apache 2.0
@@ -22,7 +22,7 @@ Requires-Dist: matplotlib
22
22
  Requires-Dist: nevergrad
23
23
  Requires-Dist: numpy
24
24
  Requires-Dist: openfermion
25
- Requires-Dist: pyqtorch==1.4.7
25
+ Requires-Dist: pyqtorch==1.5.1
26
26
  Requires-Dist: pyyaml
27
27
  Requires-Dist: rich
28
28
  Requires-Dist: scipy
@@ -31,14 +31,11 @@ Requires-Dist: sympytorch>=0.1.2
31
31
  Requires-Dist: tensorboard>=2.12.0
32
32
  Requires-Dist: torch
33
33
  Provides-Extra: all
34
- Requires-Dist: braket; extra == 'all'
35
34
  Requires-Dist: libs; extra == 'all'
36
35
  Requires-Dist: mlflow; extra == 'all'
37
36
  Requires-Dist: protocols; extra == 'all'
38
37
  Requires-Dist: pulser; extra == 'all'
39
38
  Requires-Dist: visualization; extra == 'all'
40
- Provides-Extra: braket
41
- Requires-Dist: amazon-braket-sdk<1.71.2; extra == 'braket'
42
39
  Provides-Extra: dlprof
43
40
  Requires-Dist: nvidia-dlprof[pytorch]; extra == 'dlprof'
44
41
  Requires-Dist: nvidia-pyindex; extra == 'dlprof'
@@ -57,9 +54,9 @@ Requires-Dist: mlflow; extra == 'mlflow'
57
54
  Provides-Extra: protocols
58
55
  Requires-Dist: qadence-protocols; extra == 'protocols'
59
56
  Provides-Extra: pulser
60
- Requires-Dist: pasqal-cloud==0.11.4; extra == 'pulser'
61
- Requires-Dist: pulser-core==0.19.0; extra == 'pulser'
62
- Requires-Dist: pulser-simulation==0.19.0; extra == 'pulser'
57
+ Requires-Dist: pasqal-cloud==0.12.4; extra == 'pulser'
58
+ Requires-Dist: pulser-core==1.1.1; extra == 'pulser'
59
+ Requires-Dist: pulser-simulation==1.1.1; extra == 'pulser'
63
60
  Provides-Extra: visualization
64
61
  Requires-Dist: graphviz; extra == 'visualization'
65
62
  Description-Content-Type: text/markdown
@@ -72,6 +72,7 @@ nav:
72
72
  - QuantumCircuit: api/quantumcircuit.md
73
73
  - Parameters: api/parameters.md
74
74
  - State preparation: api/states.md
75
+ - Noise: api/noise.md
75
76
  - Constructors: api/constructors.md
76
77
  - Transpilation: api/transpile.md
77
78
  - Execution: api/execution.md
@@ -26,7 +26,7 @@ authors = [
26
26
  ]
27
27
  requires-python = ">=3.9"
28
28
  license = { text = "Apache 2.0" }
29
- version = "1.7.7"
29
+ version = "1.8.0"
30
30
  classifiers = [
31
31
  "License :: OSI Approved :: Apache Software License",
32
32
  "Programming Language :: Python",
@@ -50,7 +50,7 @@ dependencies = [
50
50
  "jsonschema",
51
51
  "nevergrad",
52
52
  "scipy",
53
- "pyqtorch==1.4.7",
53
+ "pyqtorch==1.5.1",
54
54
  "pyyaml",
55
55
  "matplotlib",
56
56
  "Arpeggio==2.0.2",
@@ -62,11 +62,10 @@ allow-ambiguous-features = true
62
62
 
63
63
  [project.optional-dependencies]
64
64
  pulser = [
65
- "pulser-core==0.19.0",
66
- "pulser-simulation==0.19.0",
67
- "pasqal-cloud==0.11.4",
65
+ "pulser-core==1.1.1",
66
+ "pulser-simulation==1.1.1",
67
+ "pasqal-cloud==0.12.4",
68
68
  ]
69
- braket = ["amazon-braket-sdk<1.71.2"]
70
69
  visualization = [
71
70
  "graphviz",
72
71
  # FIXME: will be needed once we support latex labels
@@ -86,7 +85,7 @@ protocols = ["qadence-protocols"]
86
85
  libs = ["qadence-libs"]
87
86
  dlprof = ["nvidia-pyindex", "nvidia-dlprof[pytorch]"]
88
87
  mlflow = ["mlflow"]
89
- all = ["pulser", "braket", "visualization", "protocols", "libs", "mlflow"]
88
+ all = ["pulser", "visualization", "protocols", "libs", "mlflow"]
90
89
 
91
90
 
92
91
  [tool.hatch.envs.default]
@@ -105,7 +104,7 @@ dependencies = [
105
104
  "ruff",
106
105
  "pydocstringformatter",
107
106
  ]
108
- features = ["pulser", "braket", "visualization", "horqrux", "mlflow"]
107
+ features = ["pulser", "visualization", "horqrux", "mlflow"]
109
108
 
110
109
  [tool.hatch.envs.default.scripts]
111
110
  test = "pytest -n auto --cov-report lcov --cov-config=pyproject.toml --cov=qadence --cov=tests --ignore=./tests/test_examples.py {args}"
@@ -143,7 +142,7 @@ dependencies = [
143
142
  "markdown-exec",
144
143
  "mike",
145
144
  ]
146
- features = ["pulser", "braket", "horqrux", "visualization", "mlflow"]
145
+ features = ["pulser", "horqrux", "visualization", "mlflow"]
147
146
 
148
147
  [tool.hatch.envs.docs.scripts]
149
148
  build = "mkdocs build --clean --strict"
@@ -49,7 +49,7 @@ class RydbergDevice:
49
49
  )
50
50
 
51
51
  def _to_dict(self) -> dict:
52
- device_dict = {}
52
+ device_dict = dict()
53
53
  for field in fields(self):
54
54
  if field.name != "pattern":
55
55
  device_dict[field.name] = getattr(self, field.name)
@@ -23,7 +23,7 @@ from qadence.blocks.analog import ConstantAnalogRotation, InteractionBlock
23
23
  from qadence.circuit import QuantumCircuit
24
24
  from qadence.measurements import Measurements
25
25
  from qadence.mitigations import Mitigations
26
- from qadence.noise import Noise
26
+ from qadence.noise import NoiseHandler
27
27
  from qadence.parameters import stringify
28
28
  from qadence.types import ArrayLike, BackendName, DiffMode, Endianness, Engine, ParamDictType
29
29
 
@@ -240,7 +240,7 @@ class Backend(ABC):
240
240
  param_values: dict[str, Tensor] = {},
241
241
  n_shots: int = 1000,
242
242
  state: ArrayLike | None = None,
243
- noise: Noise | None = None,
243
+ noise: NoiseHandler | None = None,
244
244
  mitigation: Mitigations | None = None,
245
245
  endianness: Endianness = Endianness.BIG,
246
246
  ) -> list[Counter]:
@@ -290,7 +290,7 @@ class Backend(ABC):
290
290
  param_values: ParamDictType = {},
291
291
  state: ArrayLike | None = None,
292
292
  measurement: Measurements | None = None,
293
- noise: Noise | None = None,
293
+ noise: NoiseHandler | None = None,
294
294
  mitigation: Mitigations | None = None,
295
295
  endianness: Endianness = Endianness.BIG,
296
296
  ) -> ArrayLike:
@@ -21,7 +21,7 @@ from qadence.blocks import AbstractBlock
21
21
  from qadence.circuit import QuantumCircuit
22
22
  from qadence.measurements import Measurements
23
23
  from qadence.mitigations import Mitigations
24
- from qadence.noise import Noise
24
+ from qadence.noise import NoiseHandler
25
25
  from qadence.transpile import flatten, scale_primitive_blocks_only, transpile
26
26
  from qadence.types import BackendName, Endianness, Engine, ParamDictType
27
27
  from qadence.utils import int_to_basis
@@ -114,7 +114,7 @@ class Backend(BackendInterface):
114
114
  param_values: ParamDictType = {},
115
115
  state: ArrayLike | None = None,
116
116
  measurement: Measurements | None = None,
117
- noise: Noise | None = None,
117
+ noise: NoiseHandler | None = None,
118
118
  mitigation: Mitigations | None = None,
119
119
  endianness: Endianness = Endianness.BIG,
120
120
  ) -> ArrayLike:
@@ -163,7 +163,7 @@ class Backend(BackendInterface):
163
163
  param_values: ParamDictType = {},
164
164
  n_shots: int = 1,
165
165
  state: ArrayLike | None = None,
166
- noise: Noise | None = None,
166
+ noise: NoiseHandler | None = None,
167
167
  mitigation: Mitigations | None = None,
168
168
  endianness: Endianness = Endianness.BIG,
169
169
  ) -> list[Counter]:
@@ -24,12 +24,12 @@ from qadence.circuit import QuantumCircuit
24
24
  from qadence.measurements import Measurements
25
25
  from qadence.mitigations import Mitigations
26
26
  from qadence.mitigations.protocols import apply_mitigation
27
- from qadence.noise import Noise
28
- from qadence.noise.protocols import apply_noise
27
+ from qadence.noise import NoiseHandler
28
+ from qadence.noise.protocols import apply_readout_noise
29
29
  from qadence.overlap import overlap_exact
30
30
  from qadence.register import Register
31
31
  from qadence.transpile import transpile
32
- from qadence.types import BackendName, DeviceType, Endianness, Engine
32
+ from qadence.types import BackendName, DeviceType, Endianness, Engine, NoiseProtocol
33
33
 
34
34
  from .channels import GLOBAL_CHANNEL, LOCAL_CHANNEL
35
35
  from .cloud import get_client
@@ -187,7 +187,7 @@ class Backend(BackendInterface):
187
187
  param_values: dict[str, Tensor] = {},
188
188
  state: Tensor | None = None,
189
189
  endianness: Endianness = Endianness.BIG,
190
- noise: Noise | None = None,
190
+ noise: NoiseHandler | None = None,
191
191
  ) -> Tensor:
192
192
  vals = to_list_of_dicts(param_values)
193
193
 
@@ -235,27 +235,26 @@ class Backend(BackendInterface):
235
235
  def _run_noisy(
236
236
  self,
237
237
  circuit: ConvertedCircuit,
238
- noise: Noise,
238
+ noise: NoiseHandler,
239
239
  param_values: dict[str, Tensor] = dict(),
240
240
  state: Tensor | None = None,
241
241
  endianness: Endianness = Endianness.BIG,
242
242
  ) -> Tensor:
243
243
  vals = to_list_of_dicts(param_values)
244
- noise_probs = noise.options.get("noise_probs", None)
245
- if noise_probs is None:
246
- KeyError("A `noise probs` option should be passed to the <class QuantumModel>.")
247
- if not (isinstance(noise_probs, float) or isinstance(noise_probs, Iterable)):
248
- KeyError(
249
- "A single or a range of noise probabilities"
250
- " should be passed. Got {type(noise_probs)}."
251
- )
244
+ if not isinstance(noise.protocol[-1], NoiseProtocol.ANALOG):
245
+ raise TypeError("Noise must be of type `NoiseProtocol.ANALOG`.")
246
+ noise_probs = noise.options[-1].get("noise_probs", None)
252
247
 
253
248
  def run_noisy_sim(noise_prob: float) -> Tensor:
254
249
  batched_dm = np.zeros(
255
250
  (len(vals), 2**circuit.abstract.n_qubits, 2**circuit.abstract.n_qubits),
256
251
  dtype=np.complex128,
257
252
  )
258
- sim_config = {"noise": noise.protocol, noise.protocol + "_rate": noise_prob}
253
+ # pulser requires lower letters
254
+ sim_config = {
255
+ "noise": noise.protocol[-1].lower(),
256
+ noise.protocol[-1].lower() + "_rate": noise_prob,
257
+ }
259
258
  self.config.sim_config = SimConfig(**sim_config)
260
259
 
261
260
  for i, param_values_el in enumerate(vals):
@@ -289,7 +288,7 @@ class Backend(BackendInterface):
289
288
  param_values: dict[str, Tensor] = {},
290
289
  n_shots: int = 1,
291
290
  state: Tensor | None = None,
292
- noise: Noise | None = None,
291
+ noise: NoiseHandler | None = None,
293
292
  mitigation: Mitigations | None = None,
294
293
  endianness: Endianness = Endianness.BIG,
295
294
  ) -> list[Counter]:
@@ -313,7 +312,7 @@ class Backend(BackendInterface):
313
312
 
314
313
  samples = invert_endianness(samples)
315
314
  if noise is not None:
316
- samples = apply_noise(noise=noise, samples=samples)
315
+ samples = apply_readout_noise(noise=noise, samples=samples)
317
316
  if mitigation is not None:
318
317
  logger.warning(
319
318
  "Mitigation protocol is deprecated. Use qadence-protocols instead.",
@@ -329,7 +328,7 @@ class Backend(BackendInterface):
329
328
  param_values: dict[str, Tensor] = {},
330
329
  state: Tensor | None = None,
331
330
  measurement: Measurements | None = None,
332
- noise: Noise | None = None,
331
+ noise: NoiseHandler | None = None,
333
332
  mitigation: Mitigations | None = None,
334
333
  endianness: Endianness = Endianness.BIG,
335
334
  ) -> Tensor:
@@ -5,7 +5,7 @@ from typing import Sequence
5
5
  import torch
6
6
  from torch.nn import Module
7
7
 
8
- from qadence import Noise
8
+ from qadence import NoiseHandler
9
9
  from qadence.blocks import (
10
10
  AbstractBlock,
11
11
  )
@@ -40,7 +40,7 @@ class PulserObservable(Module):
40
40
  state: torch.Tensor,
41
41
  values: dict[str, torch.Tensor] = dict(),
42
42
  qubit_support: tuple | None = None,
43
- noise: Noise | None = None,
43
+ noise: NoiseHandler | None = None,
44
44
  endianness: Endianness = Endianness.BIG,
45
45
  ) -> torch.Tensor:
46
46
  if not self.block.is_parametric:
@@ -22,8 +22,8 @@ from qadence.blocks import AbstractBlock
22
22
  from qadence.circuit import QuantumCircuit
23
23
  from qadence.measurements import Measurements
24
24
  from qadence.mitigations.protocols import Mitigations, apply_mitigation
25
- from qadence.noise import Noise
26
- from qadence.noise.protocols import apply_noise
25
+ from qadence.noise import NoiseHandler
26
+ from qadence.noise.protocols import apply_readout_noise
27
27
  from qadence.transpile import (
28
28
  chain_single_qubit_ops,
29
29
  flatten,
@@ -113,7 +113,7 @@ class Backend(BackendInterface):
113
113
  param_values: dict[str, Tensor] = {},
114
114
  state: Tensor | None = None,
115
115
  measurement: Measurements | None = None,
116
- noise: Noise | None = None,
116
+ noise: NoiseHandler | None = None,
117
117
  endianness: Endianness = Endianness.BIG,
118
118
  ) -> Tensor:
119
119
  state = self.run(
@@ -138,7 +138,7 @@ class Backend(BackendInterface):
138
138
  param_values: dict[str, Tensor] = {},
139
139
  state: Tensor | None = None,
140
140
  measurement: Measurements | None = None,
141
- noise: Noise | None = None,
141
+ noise: NoiseHandler | None = None,
142
142
  endianness: Endianness = Endianness.BIG,
143
143
  ) -> Tensor:
144
144
  if state is None:
@@ -169,7 +169,7 @@ class Backend(BackendInterface):
169
169
  param_values: dict[str, Tensor] = {},
170
170
  state: Tensor | None = None,
171
171
  measurement: Measurements | None = None,
172
- noise: Noise | None = None,
172
+ noise: NoiseHandler | None = None,
173
173
  mitigation: Mitigations | None = None,
174
174
  endianness: Endianness = Endianness.BIG,
175
175
  ) -> Tensor:
@@ -196,7 +196,7 @@ class Backend(BackendInterface):
196
196
  param_values: dict[str, Tensor] = {},
197
197
  n_shots: int = 1,
198
198
  state: Tensor | None = None,
199
- noise: Noise | None = None,
199
+ noise: NoiseHandler | None = None,
200
200
  mitigation: Mitigations | None = None,
201
201
  endianness: Endianness = Endianness.BIG,
202
202
  pyqify_state: bool = True,
@@ -211,7 +211,7 @@ class Backend(BackendInterface):
211
211
  )
212
212
  samples = invert_endianness(samples) if endianness != Endianness.BIG else samples
213
213
  if noise is not None:
214
- samples = apply_noise(noise=noise, samples=samples)
214
+ samples = apply_readout_noise(noise=noise, samples=samples)
215
215
  if mitigation is not None:
216
216
  logger.warning(
217
217
  "Mitigation protocol is deprecated. Use qadence-protocols instead.",
@@ -0,0 +1,332 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from functools import partial, reduce
5
+ from itertools import chain as flatten
6
+ from typing import Any, Callable, Sequence
7
+
8
+ import pyqtorch as pyq
9
+ import sympy
10
+ import torch
11
+ from pyqtorch.embed import ConcretizedCallable
12
+ from torch import (
13
+ Tensor,
14
+ cdouble,
15
+ complex64,
16
+ float64,
17
+ tensor,
18
+ )
19
+ from torch.nn import Module
20
+
21
+ from qadence.blocks import (
22
+ AbstractBlock,
23
+ AddBlock,
24
+ ChainBlock,
25
+ CompositeBlock,
26
+ MatrixBlock,
27
+ ParametricBlock,
28
+ PrimitiveBlock,
29
+ ScaleBlock,
30
+ TimeEvolutionBlock,
31
+ )
32
+ from qadence.blocks.primitive import ProjectorBlock
33
+ from qadence.noise import NoiseHandler
34
+ from qadence.operations import (
35
+ U,
36
+ multi_qubit_gateset,
37
+ non_unitary_gateset,
38
+ single_qubit_gateset,
39
+ three_qubit_gateset,
40
+ two_qubit_gateset,
41
+ )
42
+ from qadence.types import NoiseProtocol, OpName
43
+
44
+ from .config import Configuration
45
+
46
+ SYMPY_TO_PYQ_MAPPING = {
47
+ sympy.Pow: "pow",
48
+ sympy.cos: "cos",
49
+ sympy.Add: "add",
50
+ sympy.Mul: "mul",
51
+ sympy.sin: "sin",
52
+ sympy.log: "log",
53
+ sympy.tan: "tan",
54
+ sympy.tanh: "tanh",
55
+ sympy.Heaviside: "hs",
56
+ sympy.Abs: "abs",
57
+ sympy.exp: "exp",
58
+ sympy.acos: "acos",
59
+ sympy.asin: "asin",
60
+ sympy.atan: "atan",
61
+ }
62
+
63
+
64
+ # Tdagger is not supported currently
65
+ supported_gates = list(set(OpName.list()) - set([OpName.TDAGGER]))
66
+ """The set of supported gates.
67
+
68
+ Tdagger is currently not supported.
69
+ """
70
+
71
+
72
+ def is_single_qubit_chain(block: AbstractBlock) -> bool:
73
+ return (
74
+ isinstance(block, (ChainBlock))
75
+ and block.n_supports == 1
76
+ and all([isinstance(b, (ParametricBlock, PrimitiveBlock)) for b in block])
77
+ and not any([isinstance(b, (ScaleBlock, U)) for b in block])
78
+ )
79
+
80
+
81
+ def extract_parameter(block: ScaleBlock | ParametricBlock, config: Configuration) -> str | Tensor:
82
+ """Extract the parameter as string or its tensor value.
83
+
84
+ Args:
85
+ block (ScaleBlock | ParametricBlock): Block to extract parameter from.
86
+ config (Configuration): Configuration instance.
87
+
88
+ Returns:
89
+ str | Tensor: Parameter value or symbol.
90
+ """
91
+ if not block.is_parametric:
92
+ tensor_val = tensor([block.parameters.parameter], dtype=complex64)
93
+ return (
94
+ tensor([block.parameters.parameter], dtype=float64)
95
+ if torch.all(tensor_val.imag == 0)
96
+ else tensor_val
97
+ )
98
+
99
+ return config.get_param_name(block)[0]
100
+
101
+
102
+ def replace_underscore_floats(s: str) -> str:
103
+ """Replace underscores with periods for all floats in given string.
104
+
105
+ Needed for correct parsing of string by sympy parser.
106
+
107
+ Args:
108
+ s (str): string expression
109
+
110
+ Returns:
111
+ str: transformed string expression
112
+ """
113
+
114
+ # Regular expression to match floats written with underscores instead of dots
115
+ float_with_underscore_pattern = r"""
116
+ (?<!\w) # Negative lookbehind to ensure not part of a word
117
+ -? # Optional negative sign
118
+ \d+ # One or more digits (before underscore)
119
+ _ # The underscore acting as decimal separator
120
+ \d+ # One or more digits (after underscore)
121
+ ([eE][-+]?\d+)? # Optional exponent part for scientific notation
122
+ (?!\w) # Negative lookahead to ensure not part of a word
123
+ """
124
+
125
+ # Function to replace the underscore with a dot
126
+ def underscore_to_dot(match: re.Match) -> Any:
127
+ return match.group(0).replace("_", ".")
128
+
129
+ # Compile the regular expression
130
+ pattern = re.compile(float_with_underscore_pattern, re.VERBOSE)
131
+
132
+ return pattern.sub(underscore_to_dot, s)
133
+
134
+
135
+ def sympy_to_pyq(expr: sympy.Expr) -> ConcretizedCallable | Tensor:
136
+ """Convert sympy expression to pyqtorch ConcretizedCallable object.
137
+
138
+ Args:
139
+ expr (sympy.Expr): sympy expression
140
+
141
+ Returns:
142
+ ConcretizedCallable: expression encoded as ConcretizedCallable
143
+ """
144
+
145
+ # base case - independent argument
146
+ if len(expr.args) == 0:
147
+ try:
148
+ res = torch.as_tensor(float(expr))
149
+ except Exception as e:
150
+ res = str(expr)
151
+
152
+ if "/" in res: # Found a rational
153
+ res = torch.as_tensor(float(sympy.Rational(res).evalf()))
154
+ return res
155
+
156
+ # Recursively iterate through current function arguments
157
+ all_results = []
158
+ for arg in expr.args:
159
+ res = sympy_to_pyq(arg)
160
+ all_results.append(res)
161
+
162
+ # deal with multi-argument (>2) sympy functions: converting to nested
163
+ # ConcretizedCallable objects
164
+ if len(all_results) > 2:
165
+
166
+ def fn(x: str | ConcretizedCallable, y: str | ConcretizedCallable) -> Callable:
167
+ return partial(ConcretizedCallable, call_name=SYMPY_TO_PYQ_MAPPING[expr.func])( # type: ignore [no-any-return]
168
+ abstract_args=[x, y]
169
+ )
170
+
171
+ concretized_callable = reduce(fn, all_results)
172
+ else:
173
+ concretized_callable = ConcretizedCallable(SYMPY_TO_PYQ_MAPPING[expr.func], all_results)
174
+ return concretized_callable
175
+
176
+
177
+ def convert_block(
178
+ block: AbstractBlock, n_qubits: int = None, config: Configuration = None
179
+ ) -> Sequence[Module | Tensor | str | sympy.Expr]:
180
+ if isinstance(block, (Tensor, str, sympy.Expr)): # case for hamevo generators
181
+ if isinstance(block, Tensor):
182
+ block = block.permute(1, 2, 0) # put batch size in the back
183
+ return [block]
184
+ qubit_support = block.qubit_support
185
+ if n_qubits is None:
186
+ n_qubits = max(qubit_support) + 1
187
+
188
+ if config is None:
189
+ config = Configuration()
190
+
191
+ noise: NoiseHandler | None = None
192
+ if hasattr(block, "noise") and block.noise:
193
+ noise = convert_digital_noise(block.noise)
194
+
195
+ if isinstance(block, ScaleBlock):
196
+ scaled_ops = convert_block(block.block, n_qubits, config)
197
+ scale = extract_parameter(block, config=config)
198
+
199
+ # replace underscore by dot when underscore is between two numbers in string
200
+ if isinstance(scale, str):
201
+ scale = replace_underscore_floats(scale)
202
+
203
+ if isinstance(scale, str) and not config._use_gate_params:
204
+ param = sympy_to_pyq(sympy.parse_expr(scale))
205
+ else:
206
+ param = scale
207
+
208
+ return [pyq.Scale(pyq.Sequence(scaled_ops), param)]
209
+
210
+ elif isinstance(block, TimeEvolutionBlock):
211
+ if getattr(block.generator, "is_time_dependent", False):
212
+ config._use_gate_params = False
213
+ generator = convert_block(block.generator, config=config)[0] # type: ignore [arg-type]
214
+ elif isinstance(block.generator, sympy.Basic):
215
+ generator = config.get_param_name(block)[1]
216
+
217
+ elif isinstance(block.generator, Tensor):
218
+ m = block.generator.to(dtype=cdouble)
219
+ generator = convert_block(
220
+ MatrixBlock(
221
+ m,
222
+ qubit_support=qubit_support,
223
+ check_unitary=False,
224
+ check_hermitian=True,
225
+ )
226
+ )[0]
227
+ else:
228
+ generator = convert_block(block.generator, n_qubits, config)[0] # type: ignore[arg-type]
229
+ time_param = config.get_param_name(block)[0]
230
+
231
+ return [
232
+ pyq.HamiltonianEvolution(
233
+ qubit_support=qubit_support,
234
+ generator=generator,
235
+ time=time_param,
236
+ cache_length=0,
237
+ )
238
+ ]
239
+
240
+ elif isinstance(block, MatrixBlock):
241
+ return [pyq.primitives.Primitive(block.matrix, block.qubit_support, noise=noise)]
242
+ elif isinstance(block, CompositeBlock):
243
+ ops = list(flatten(*(convert_block(b, n_qubits, config) for b in block.blocks)))
244
+ if isinstance(block, AddBlock):
245
+ return [pyq.Add(ops)] # add
246
+ elif is_single_qubit_chain(block) and config.use_single_qubit_composition:
247
+ return [pyq.Merge(ops)] # for chains of single qubit ops on the same qubit
248
+ else:
249
+ return [pyq.Sequence(ops)] # for kron and chain
250
+ elif isinstance(block, tuple(non_unitary_gateset)):
251
+ if isinstance(block, ProjectorBlock):
252
+ projector = getattr(pyq, block.name)
253
+ if block.name == OpName.N:
254
+ return [projector(target=qubit_support, noise=noise)]
255
+ else:
256
+ return [
257
+ projector(
258
+ qubit_support=qubit_support,
259
+ ket=block.ket,
260
+ bra=block.bra,
261
+ noise=noise,
262
+ )
263
+ ]
264
+ else:
265
+ return [getattr(pyq, block.name)(qubit_support[0])]
266
+ elif isinstance(block, tuple(single_qubit_gateset)):
267
+ pyq_cls = getattr(pyq, block.name)
268
+ if isinstance(block, ParametricBlock):
269
+ if isinstance(block, U):
270
+ op = pyq_cls(
271
+ qubit_support[0],
272
+ *config.get_param_name(block),
273
+ noise=noise,
274
+ )
275
+ else:
276
+ param = extract_parameter(block, config)
277
+ op = pyq_cls(qubit_support[0], param, noise=noise)
278
+ else:
279
+ op = pyq_cls(qubit_support[0], noise=noise) # type: ignore [attr-defined]
280
+ return [op]
281
+ elif isinstance(block, tuple(two_qubit_gateset)):
282
+ pyq_cls = getattr(pyq, block.name)
283
+ if isinstance(block, ParametricBlock):
284
+ op = pyq_cls(
285
+ qubit_support[0],
286
+ qubit_support[1],
287
+ extract_parameter(block, config),
288
+ noise=noise,
289
+ )
290
+ else:
291
+ op = pyq_cls(
292
+ qubit_support[0], qubit_support[1], noise=noise # type: ignore [attr-defined]
293
+ )
294
+ return [op]
295
+ elif isinstance(block, tuple(three_qubit_gateset) + tuple(multi_qubit_gateset)):
296
+ block_name = block.name[1:] if block.name.startswith("M") else block.name
297
+ pyq_cls = getattr(pyq, block_name)
298
+ if isinstance(block, ParametricBlock):
299
+ op = pyq_cls(
300
+ qubit_support[:-1],
301
+ qubit_support[-1],
302
+ extract_parameter(block, config),
303
+ noise=noise,
304
+ )
305
+ else:
306
+ if "CSWAP" in block_name:
307
+ op = pyq_cls(
308
+ qubit_support[:-2], qubit_support[-2:], noise=noise # type: ignore [attr-defined]
309
+ )
310
+ else:
311
+ op = pyq_cls(
312
+ qubit_support[:-1], qubit_support[-1], noise=noise # type: ignore [attr-defined]
313
+ )
314
+ return [op]
315
+ else:
316
+ raise NotImplementedError(
317
+ f"Non supported operation of type {type(block)}. "
318
+ "In case you are trying to run an `AnalogBlock`, make sure you "
319
+ "specify the `device_specs` in your `Register` first."
320
+ )
321
+
322
+
323
+ def convert_digital_noise(noise: NoiseHandler) -> pyq.noise.NoiseProtocol:
324
+ digital_part = noise.filter(NoiseProtocol.DIGITAL)
325
+ if digital_part is None:
326
+ return None
327
+ return pyq.noise.NoiseProtocol(
328
+ [
329
+ pyq.noise.NoiseProtocol(proto, option.get("error_probability"))
330
+ for proto, option in zip(digital_part.protocol, digital_part.options)
331
+ ]
332
+ )