qadence 1.7.2__tar.gz → 1.7.3__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 (154) hide show
  1. {qadence-1.7.2 → qadence-1.7.3}/.gitignore +4 -0
  2. {qadence-1.7.2 → qadence-1.7.3}/PKG-INFO +6 -3
  3. {qadence-1.7.2 → qadence-1.7.3}/pyproject.toml +7 -6
  4. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pyqtorch/convert_ops.py +10 -3
  5. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/matrix.py +13 -5
  6. {qadence-1.7.2 → qadence-1.7.3}/qadence/engines/torch/differentiable_expectation.py +2 -1
  7. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/config.py +102 -6
  8. qadence-1.7.3/qadence/ml_tools/printing.py +145 -0
  9. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/train_grad.py +65 -18
  10. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/train_no_grad.py +47 -8
  11. {qadence-1.7.2 → qadence-1.7.3}/qadence/types.py +12 -0
  12. {qadence-1.7.2 → qadence-1.7.3}/renovate.json +2 -1
  13. qadence-1.7.2/qadence/ml_tools/printing.py +0 -24
  14. {qadence-1.7.2 → qadence-1.7.3}/.coveragerc +0 -0
  15. {qadence-1.7.2 → qadence-1.7.3}/.github/dependabot.yml +0 -0
  16. {qadence-1.7.2 → qadence-1.7.3}/.github/workflows/build_docs.yml +0 -0
  17. {qadence-1.7.2 → qadence-1.7.3}/.github/workflows/dependabot.yml +0 -0
  18. {qadence-1.7.2 → qadence-1.7.3}/.github/workflows/lint.yml +0 -0
  19. {qadence-1.7.2 → qadence-1.7.3}/.github/workflows/test_all.yml +0 -0
  20. {qadence-1.7.2 → qadence-1.7.3}/.github/workflows/test_examples.yml +0 -0
  21. {qadence-1.7.2 → qadence-1.7.3}/.github/workflows/test_fast.yml +0 -0
  22. {qadence-1.7.2 → qadence-1.7.3}/.pre-commit-config.yaml +0 -0
  23. {qadence-1.7.2 → qadence-1.7.3}/LICENSE +0 -0
  24. {qadence-1.7.2 → qadence-1.7.3}/MANIFEST.in +0 -0
  25. {qadence-1.7.2 → qadence-1.7.3}/README.md +0 -0
  26. {qadence-1.7.2 → qadence-1.7.3}/mkdocs.yml +0 -0
  27. {qadence-1.7.2 → qadence-1.7.3}/qadence/__init__.py +0 -0
  28. {qadence-1.7.2 → qadence-1.7.3}/qadence/analog/__init__.py +0 -0
  29. {qadence-1.7.2 → qadence-1.7.3}/qadence/analog/addressing.py +0 -0
  30. {qadence-1.7.2 → qadence-1.7.3}/qadence/analog/constants.py +0 -0
  31. {qadence-1.7.2 → qadence-1.7.3}/qadence/analog/device.py +0 -0
  32. {qadence-1.7.2 → qadence-1.7.3}/qadence/analog/hamiltonian_terms.py +0 -0
  33. {qadence-1.7.2 → qadence-1.7.3}/qadence/analog/parse_analog.py +0 -0
  34. {qadence-1.7.2 → qadence-1.7.3}/qadence/backend.py +0 -0
  35. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/__init__.py +0 -0
  36. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/api.py +0 -0
  37. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/braket/__init__.py +0 -0
  38. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/braket/backend.py +0 -0
  39. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/braket/config.py +0 -0
  40. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/braket/convert_ops.py +0 -0
  41. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/gpsr.py +0 -0
  42. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/horqrux/__init__.py +0 -0
  43. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/horqrux/backend.py +0 -0
  44. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/horqrux/config.py +0 -0
  45. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/horqrux/convert_ops.py +0 -0
  46. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/jax_utils.py +0 -0
  47. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/__init__.py +0 -0
  48. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/backend.py +0 -0
  49. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/channels.py +0 -0
  50. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/cloud.py +0 -0
  51. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/config.py +0 -0
  52. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/convert_ops.py +0 -0
  53. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/devices.py +0 -0
  54. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/pulses.py +0 -0
  55. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pulser/waveforms.py +0 -0
  56. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pyqtorch/__init__.py +0 -0
  57. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pyqtorch/backend.py +0 -0
  58. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/pyqtorch/config.py +0 -0
  59. {qadence-1.7.2 → qadence-1.7.3}/qadence/backends/utils.py +0 -0
  60. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/__init__.py +0 -0
  61. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/abstract.py +0 -0
  62. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/analog.py +0 -0
  63. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/block_to_tensor.py +0 -0
  64. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/composite.py +0 -0
  65. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/embedding.py +0 -0
  66. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/manipulate.py +0 -0
  67. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/primitive.py +0 -0
  68. {qadence-1.7.2 → qadence-1.7.3}/qadence/blocks/utils.py +0 -0
  69. {qadence-1.7.2 → qadence-1.7.3}/qadence/circuit.py +0 -0
  70. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/__init__.py +0 -0
  71. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/ansatze.py +0 -0
  72. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/daqc/__init__.py +0 -0
  73. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/daqc/daqc.py +0 -0
  74. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/daqc/gen_parser.py +0 -0
  75. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/daqc/utils.py +0 -0
  76. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/feature_maps.py +0 -0
  77. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/hamiltonians.py +0 -0
  78. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/iia.py +0 -0
  79. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/qft.py +0 -0
  80. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/rydberg_feature_maps.py +0 -0
  81. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/rydberg_hea.py +0 -0
  82. {qadence-1.7.2 → qadence-1.7.3}/qadence/constructors/utils.py +0 -0
  83. {qadence-1.7.2 → qadence-1.7.3}/qadence/decompose.py +0 -0
  84. {qadence-1.7.2 → qadence-1.7.3}/qadence/divergences.py +0 -0
  85. {qadence-1.7.2 → qadence-1.7.3}/qadence/draw/__init__.py +0 -0
  86. {qadence-1.7.2 → qadence-1.7.3}/qadence/draw/assets/dark/measurement.png +0 -0
  87. {qadence-1.7.2 → qadence-1.7.3}/qadence/draw/assets/dark/measurement.svg +0 -0
  88. {qadence-1.7.2 → qadence-1.7.3}/qadence/draw/assets/light/measurement.png +0 -0
  89. {qadence-1.7.2 → qadence-1.7.3}/qadence/draw/assets/light/measurement.svg +0 -0
  90. {qadence-1.7.2 → qadence-1.7.3}/qadence/draw/themes.py +0 -0
  91. {qadence-1.7.2 → qadence-1.7.3}/qadence/draw/utils.py +0 -0
  92. {qadence-1.7.2 → qadence-1.7.3}/qadence/draw/vizbackend.py +0 -0
  93. {qadence-1.7.2 → qadence-1.7.3}/qadence/engines/__init__.py +0 -0
  94. {qadence-1.7.2 → qadence-1.7.3}/qadence/engines/differentiable_backend.py +0 -0
  95. {qadence-1.7.2 → qadence-1.7.3}/qadence/engines/jax/__init__.py +0 -0
  96. {qadence-1.7.2 → qadence-1.7.3}/qadence/engines/jax/differentiable_backend.py +0 -0
  97. {qadence-1.7.2 → qadence-1.7.3}/qadence/engines/jax/differentiable_expectation.py +0 -0
  98. {qadence-1.7.2 → qadence-1.7.3}/qadence/engines/torch/__init__.py +0 -0
  99. {qadence-1.7.2 → qadence-1.7.3}/qadence/engines/torch/differentiable_backend.py +0 -0
  100. {qadence-1.7.2 → qadence-1.7.3}/qadence/exceptions/__init__.py +0 -0
  101. {qadence-1.7.2 → qadence-1.7.3}/qadence/exceptions/exceptions.py +0 -0
  102. {qadence-1.7.2 → qadence-1.7.3}/qadence/execution.py +0 -0
  103. {qadence-1.7.2 → qadence-1.7.3}/qadence/extensions.py +0 -0
  104. {qadence-1.7.2 → qadence-1.7.3}/qadence/libs.py +0 -0
  105. {qadence-1.7.2 → qadence-1.7.3}/qadence/log_config.yaml +0 -0
  106. {qadence-1.7.2 → qadence-1.7.3}/qadence/logger.py +0 -0
  107. {qadence-1.7.2 → qadence-1.7.3}/qadence/measurements/__init__.py +0 -0
  108. {qadence-1.7.2 → qadence-1.7.3}/qadence/measurements/protocols.py +0 -0
  109. {qadence-1.7.2 → qadence-1.7.3}/qadence/measurements/samples.py +0 -0
  110. {qadence-1.7.2 → qadence-1.7.3}/qadence/measurements/shadow.py +0 -0
  111. {qadence-1.7.2 → qadence-1.7.3}/qadence/measurements/tomography.py +0 -0
  112. {qadence-1.7.2 → qadence-1.7.3}/qadence/measurements/utils.py +0 -0
  113. {qadence-1.7.2 → qadence-1.7.3}/qadence/mitigations/__init__.py +0 -0
  114. {qadence-1.7.2 → qadence-1.7.3}/qadence/mitigations/analog_zne.py +0 -0
  115. {qadence-1.7.2 → qadence-1.7.3}/qadence/mitigations/protocols.py +0 -0
  116. {qadence-1.7.2 → qadence-1.7.3}/qadence/mitigations/readout.py +0 -0
  117. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/__init__.py +0 -0
  118. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/constructors.py +0 -0
  119. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/data.py +0 -0
  120. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/models.py +0 -0
  121. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/optimize_step.py +0 -0
  122. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/parameters.py +0 -0
  123. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/saveload.py +0 -0
  124. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/tensors.py +0 -0
  125. {qadence-1.7.2 → qadence-1.7.3}/qadence/ml_tools/utils.py +0 -0
  126. {qadence-1.7.2 → qadence-1.7.3}/qadence/model.py +0 -0
  127. {qadence-1.7.2 → qadence-1.7.3}/qadence/noise/__init__.py +0 -0
  128. {qadence-1.7.2 → qadence-1.7.3}/qadence/noise/protocols.py +0 -0
  129. {qadence-1.7.2 → qadence-1.7.3}/qadence/noise/readout.py +0 -0
  130. {qadence-1.7.2 → qadence-1.7.3}/qadence/operations/__init__.py +0 -0
  131. {qadence-1.7.2 → qadence-1.7.3}/qadence/operations/analog.py +0 -0
  132. {qadence-1.7.2 → qadence-1.7.3}/qadence/operations/control_ops.py +0 -0
  133. {qadence-1.7.2 → qadence-1.7.3}/qadence/operations/ham_evo.py +0 -0
  134. {qadence-1.7.2 → qadence-1.7.3}/qadence/operations/parametric.py +0 -0
  135. {qadence-1.7.2 → qadence-1.7.3}/qadence/operations/primitive.py +0 -0
  136. {qadence-1.7.2 → qadence-1.7.3}/qadence/overlap.py +0 -0
  137. {qadence-1.7.2 → qadence-1.7.3}/qadence/parameters.py +0 -0
  138. {qadence-1.7.2 → qadence-1.7.3}/qadence/protocols.py +0 -0
  139. {qadence-1.7.2 → qadence-1.7.3}/qadence/py.typed +0 -0
  140. {qadence-1.7.2 → qadence-1.7.3}/qadence/qubit_support.py +0 -0
  141. {qadence-1.7.2 → qadence-1.7.3}/qadence/register.py +0 -0
  142. {qadence-1.7.2 → qadence-1.7.3}/qadence/serial_expr_grammar.peg +0 -0
  143. {qadence-1.7.2 → qadence-1.7.3}/qadence/serialization.py +0 -0
  144. {qadence-1.7.2 → qadence-1.7.3}/qadence/states.py +0 -0
  145. {qadence-1.7.2 → qadence-1.7.3}/qadence/transpile/__init__.py +0 -0
  146. {qadence-1.7.2 → qadence-1.7.3}/qadence/transpile/apply_fn.py +0 -0
  147. {qadence-1.7.2 → qadence-1.7.3}/qadence/transpile/block.py +0 -0
  148. {qadence-1.7.2 → qadence-1.7.3}/qadence/transpile/circuit.py +0 -0
  149. {qadence-1.7.2 → qadence-1.7.3}/qadence/transpile/digitalize.py +0 -0
  150. {qadence-1.7.2 → qadence-1.7.3}/qadence/transpile/flatten.py +0 -0
  151. {qadence-1.7.2 → qadence-1.7.3}/qadence/transpile/invert.py +0 -0
  152. {qadence-1.7.2 → qadence-1.7.3}/qadence/transpile/transpile.py +0 -0
  153. {qadence-1.7.2 → qadence-1.7.3}/qadence/utils.py +0 -0
  154. {qadence-1.7.2 → qadence-1.7.3}/setup.py +0 -0
@@ -75,3 +75,7 @@ events.out.tfevents.*
75
75
  *.dvi
76
76
 
77
77
  *.gv
78
+
79
+ # mlflow
80
+ mlruns/
81
+ mlartifacts/
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qadence
3
- Version: 1.7.2
3
+ Version: 1.7.3
4
4
  Summary: Pasqal interface for circuit-based quantum computing SDKs
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>
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>
6
6
  License: Apache 2.0
7
7
  License-File: LICENSE
8
8
  Classifier: License :: OSI Approved :: Apache Software License
@@ -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.2.5
25
+ Requires-Dist: pyqtorch==1.3.2
26
26
  Requires-Dist: pyyaml
27
27
  Requires-Dist: rich
28
28
  Requires-Dist: scipy
@@ -33,6 +33,7 @@ Requires-Dist: torch
33
33
  Provides-Extra: all
34
34
  Requires-Dist: braket; extra == 'all'
35
35
  Requires-Dist: libs; extra == 'all'
36
+ Requires-Dist: mlflow; extra == 'all'
36
37
  Requires-Dist: protocols; extra == 'all'
37
38
  Requires-Dist: pulser; extra == 'all'
38
39
  Requires-Dist: visualization; extra == 'all'
@@ -51,6 +52,8 @@ Requires-Dist: optax; extra == 'horqrux'
51
52
  Requires-Dist: sympy2jax; extra == 'horqrux'
52
53
  Provides-Extra: libs
53
54
  Requires-Dist: qadence-libs; extra == 'libs'
55
+ Provides-Extra: mlflow
56
+ Requires-Dist: mlflow; extra == 'mlflow'
54
57
  Provides-Extra: protocols
55
58
  Requires-Dist: qadence-protocols; extra == 'protocols'
56
59
  Provides-Extra: pulser
@@ -21,10 +21,11 @@ authors = [
21
21
  { name = "Smit Chaudhary", email = "smit.chaudhary@pasqal.com" },
22
22
  { name = "Ignacio Fernández Graña", email = "ignacio.fernandez-grana@pasqal.com" },
23
23
  { name = "Charles Moussa", email = "charles.moussa@pasqal.com" },
24
+ { name = "Giorgio Tosti Balducci", email = "giorgio.tosti-balducci@pasqal.com" },
24
25
  ]
25
26
  requires-python = ">=3.9"
26
27
  license = { text = "Apache 2.0" }
27
- version = "1.7.2"
28
+ version = "1.7.3"
28
29
  classifiers = [
29
30
  "License :: OSI Approved :: Apache Software License",
30
31
  "Programming Language :: Python",
@@ -48,7 +49,7 @@ dependencies = [
48
49
  "jsonschema",
49
50
  "nevergrad",
50
51
  "scipy",
51
- "pyqtorch==1.2.5",
52
+ "pyqtorch==1.3.2",
52
53
  "pyyaml",
53
54
  "matplotlib",
54
55
  "Arpeggio==2.0.2",
@@ -83,8 +84,8 @@ horqrux = [
83
84
  protocols = ["qadence-protocols"]
84
85
  libs = ["qadence-libs"]
85
86
  dlprof = ["nvidia-pyindex", "nvidia-dlprof[pytorch]"]
86
- all = ["pulser", "braket", "visualization", "protocols", "libs"]
87
-
87
+ mlflow = ["mlflow"]
88
+ all = ["pulser", "braket", "visualization", "protocols", "libs", "mlflow"]
88
89
 
89
90
  [tool.hatch.envs.default]
90
91
  dependencies = [
@@ -102,7 +103,7 @@ dependencies = [
102
103
  "ruff",
103
104
  "pydocstringformatter",
104
105
  ]
105
- features = ["pulser", "braket", "visualization", "horqrux"]
106
+ features = ["pulser", "braket", "visualization", "horqrux", "mlflow"]
106
107
 
107
108
  [tool.hatch.envs.default.scripts]
108
109
  test = "pytest -n auto --cov-report lcov --cov-config=pyproject.toml --cov=qadence --cov=tests --ignore=./tests/test_examples.py {args}"
@@ -139,7 +140,7 @@ dependencies = [
139
140
  "markdown-exec",
140
141
  "mike",
141
142
  ]
142
- features = ["pulser", "braket", "horqrux", "visualization"]
143
+ features = ["pulser", "braket", "horqrux", "visualization", "mlflow"]
143
144
 
144
145
  [tool.hatch.envs.docs.scripts]
145
146
  build = "mkdocs build --clean --strict"
@@ -8,6 +8,7 @@ import pyqtorch as pyq
8
8
  import sympy
9
9
  import torch
10
10
  from pyqtorch.apply import apply_operator
11
+ from pyqtorch.embed import Embedding
11
12
  from pyqtorch.matrices import _dagger
12
13
  from pyqtorch.time_dependent.sesolve import sesolve
13
14
  from pyqtorch.utils import is_diag
@@ -24,7 +25,7 @@ from torch import (
24
25
  )
25
26
  from torch import device as torch_device
26
27
  from torch import dtype as torch_dtype
27
- from torch.nn import Module
28
+ from torch.nn import Module, ParameterDict
28
29
 
29
30
  from qadence.backends.utils import (
30
31
  finitediff,
@@ -200,7 +201,12 @@ class PyQHamiltonianEvolution(Module):
200
201
  elif isinstance(block.generator, Tensor):
201
202
  m = block.generator.to(dtype=cdouble)
202
203
  hmat = block_to_tensor(
203
- MatrixBlock(m, qubit_support=block.qubit_support),
204
+ MatrixBlock(
205
+ m,
206
+ qubit_support=block.qubit_support,
207
+ check_unitary=False,
208
+ check_hermitian=True,
209
+ ),
204
210
  qubit_support=self.qubit_support,
205
211
  use_full_support=False,
206
212
  )
@@ -313,7 +319,8 @@ class PyQHamiltonianEvolution(Module):
313
319
  def forward(
314
320
  self,
315
321
  state: Tensor,
316
- values: dict[str, Tensor],
322
+ values: dict[str, Tensor] | ParameterDict = dict(),
323
+ embedding: Embedding | None = None,
317
324
  ) -> Tensor:
318
325
  if getattr(self.block.generator, "is_time_dependent", False): # type: ignore [union-attr]
319
326
 
@@ -60,7 +60,13 @@ class MatrixBlock(PrimitiveBlock):
60
60
  name = "MatrixBlock"
61
61
  matrix: torch.Tensor
62
62
 
63
- def __init__(self, matrix: torch.Tensor | np.ndarray, qubit_support: tuple[int, ...]) -> None:
63
+ def __init__(
64
+ self,
65
+ matrix: torch.Tensor | np.ndarray,
66
+ qubit_support: tuple[int, ...],
67
+ check_unitary: bool = True,
68
+ check_hermitian: bool = False,
69
+ ) -> None:
64
70
  if isinstance(matrix, np.ndarray):
65
71
  matrix = torch.tensor(matrix)
66
72
  if matrix.ndim == 3 and matrix.size(0) == 1:
@@ -69,10 +75,12 @@ class MatrixBlock(PrimitiveBlock):
69
75
  raise TypeError("Please provide a 2D matrix.")
70
76
  if not self.is_square(matrix):
71
77
  raise TypeError("Please provide a square matrix.")
72
- if not self.is_hermitian(matrix):
73
- logger.warning("Provided matrix is not hermitian.")
74
- if not self.is_unitary(matrix):
75
- logger.warning("Provided matrix is not unitary.")
78
+ if check_hermitian:
79
+ if not self.is_hermitian(matrix):
80
+ logger.warning("Provided matrix is not hermitian.")
81
+ if check_unitary:
82
+ if not self.is_unitary(matrix):
83
+ logger.warning("Provided matrix is not unitary.")
76
84
  self.matrix = matrix.clone()
77
85
  super().__init__(qubit_support)
78
86
 
@@ -151,8 +151,9 @@ class DifferentiableExpectation:
151
151
  return (
152
152
  AdjointExpectation.apply(
153
153
  self.circuit.native,
154
- self.observable[0].native, # Currently, adjoint only supports a single observable.
155
154
  self.state,
155
+ self.observable[0].native, # Currently, adjoint only supports a single observable.
156
+ None,
156
157
  self.param_values.keys(),
157
158
  *self.param_values.values(),
158
159
  )
@@ -5,15 +5,25 @@ import os
5
5
  from dataclasses import dataclass, field, fields
6
6
  from logging import getLogger
7
7
  from pathlib import Path
8
- from typing import Callable, Optional, Type
8
+ from typing import Callable, Type
9
+ from uuid import uuid4
9
10
 
10
11
  from sympy import Basic
12
+ from torch import Tensor
11
13
 
12
14
  from qadence.blocks.analog import AnalogBlock
13
15
  from qadence.blocks.primitive import ParametricBlock
14
16
  from qadence.operations import RX, AnalogRX
15
17
  from qadence.parameters import Parameter
16
- from qadence.types import AnsatzType, BasisSet, MultivariateStrategy, ReuploadScaling, Strategy
18
+ from qadence.types import (
19
+ AnsatzType,
20
+ BasisSet,
21
+ ExperimentTrackingTool,
22
+ LoggablePlotFunction,
23
+ MultivariateStrategy,
24
+ ReuploadScaling,
25
+ Strategy,
26
+ )
17
27
 
18
28
  logger = getLogger(__file__)
19
29
 
@@ -37,10 +47,14 @@ class TrainConfig:
37
47
  print_every: int = 1000
38
48
  """Print loss/metrics."""
39
49
  write_every: int = 50
40
- """Write tensorboard logs."""
50
+ """Write loss and metrics with the tracking tool."""
41
51
  checkpoint_every: int = 5000
42
52
  """Write model/optimizer checkpoint."""
43
- folder: Optional[Path] = None
53
+ plot_every: int = 5000
54
+ """Write figures."""
55
+ log_model: bool = False
56
+ """Logs a serialised version of the model."""
57
+ folder: Path | None = None
44
58
  """Checkpoint/tensorboard logs folder."""
45
59
  create_subfolder_per_run: bool = False
46
60
  """Checkpoint/tensorboard logs stored in subfolder with name `<timestamp>_<PID>`.
@@ -59,14 +73,38 @@ class TrainConfig:
59
73
 
60
74
  validation loss across previous iterations.
61
75
  """
62
- validation_criterion: Optional[Callable] = None
76
+ validation_criterion: Callable | None = None
63
77
  """A boolean function which evaluates a given validation metric is satisfied."""
64
- trainstop_criterion: Optional[Callable] = None
78
+ trainstop_criterion: Callable | None = None
65
79
  """A boolean function which evaluates a given training stopping metric is satisfied."""
66
80
  batch_size: int = 1
67
81
  """The batch_size to use when passing a list/tuple of torch.Tensors."""
68
82
  verbose: bool = True
69
83
  """Whether or not to print out metrics values during training."""
84
+ tracking_tool: ExperimentTrackingTool = ExperimentTrackingTool.TENSORBOARD
85
+ """The tracking tool of choice."""
86
+ hyperparams: dict = field(default_factory=dict)
87
+ """Hyperparameters to track."""
88
+ plotting_functions: tuple[LoggablePlotFunction, ...] = field(default_factory=tuple) # type: ignore
89
+ """Functions for in-train plotting."""
90
+
91
+ # tensorboard only allows for certain types as hyperparameters
92
+ _tb_allowed_hyperparams_types: tuple = field(
93
+ default=(int, float, str, bool, Tensor), init=False, repr=False
94
+ )
95
+
96
+ def _filter_tb_hyperparams(self) -> None:
97
+ keys_to_remove = [
98
+ key
99
+ for key, value in self.hyperparams.items()
100
+ if not isinstance(value, TrainConfig._tb_allowed_hyperparams_types)
101
+ ]
102
+ if keys_to_remove:
103
+ logger.warning(
104
+ f"Tensorboard cannot log the following hyperparameters: {keys_to_remove}."
105
+ )
106
+ for key in keys_to_remove:
107
+ self.hyperparams.pop(key)
70
108
 
71
109
  def __post_init__(self) -> None:
72
110
  if self.folder:
@@ -81,6 +119,64 @@ class TrainConfig:
81
119
  self.trainstop_criterion = lambda x: x <= self.max_iter
82
120
  if self.validation_criterion is None:
83
121
  self.validation_criterion = lambda *x: False
122
+ if self.hyperparams and self.tracking_tool == ExperimentTrackingTool.TENSORBOARD:
123
+ self._filter_tb_hyperparams()
124
+ if self.tracking_tool == ExperimentTrackingTool.MLFLOW:
125
+ self._mlflow_config = MLFlowConfig()
126
+ if self.plotting_functions and self.tracking_tool != ExperimentTrackingTool.MLFLOW:
127
+ logger.warning("In-training plots are only available with mlflow tracking.")
128
+ if not self.plotting_functions and self.tracking_tool == ExperimentTrackingTool.MLFLOW:
129
+ logger.warning("Tracking with mlflow, but no plotting functions provided.")
130
+
131
+ @property
132
+ def mlflow_config(self) -> MLFlowConfig:
133
+ if self.tracking_tool == ExperimentTrackingTool.MLFLOW:
134
+ return self._mlflow_config
135
+ else:
136
+ raise AttributeError(
137
+ "mlflow_config is available only for with the mlflow tracking tool."
138
+ )
139
+
140
+
141
+ class MLFlowConfig:
142
+ """
143
+ Configuration for mlflow tracking.
144
+
145
+ Example:
146
+
147
+ export MLFLOW_TRACKING_URI=tracking_uri
148
+ export MLFLOW_EXPERIMENT=experiment_name
149
+ export MLFLOW_RUN_NAME=run_name
150
+ """
151
+
152
+ def __init__(self) -> None:
153
+ import mlflow
154
+
155
+ self.tracking_uri: str = os.getenv("MLFLOW_TRACKING_URI", "")
156
+ """The URI of the mlflow tracking server.
157
+
158
+ An empty string, or a local file path, prefixed with file:/.
159
+ Data is stored locally at the provided file (or ./mlruns if empty).
160
+ """
161
+
162
+ self.experiment_name: str = os.getenv("MLFLOW_EXPERIMENT", str(uuid4()))
163
+ """The name of the experiment.
164
+
165
+ If None or empty, a new experiment is created with a random UUID.
166
+ """
167
+
168
+ self.run_name: str = os.getenv("MLFLOW_RUN_NAME", str(uuid4()))
169
+ """The name of the run."""
170
+
171
+ mlflow.set_tracking_uri(self.tracking_uri)
172
+
173
+ # activate existing or create experiment
174
+ exp_filter_string = f"name = '{self.experiment_name}'"
175
+ if not mlflow.search_experiments(filter_string=exp_filter_string):
176
+ mlflow.create_experiment(name=self.experiment_name)
177
+
178
+ self.experiment = mlflow.set_experiment(self.experiment_name)
179
+ self.run = mlflow.start_run(run_name=self.run_name, nested=False)
84
180
 
85
181
 
86
182
  @dataclass
@@ -0,0 +1,145 @@
1
+ from __future__ import annotations
2
+
3
+ from logging import getLogger
4
+ from typing import Any, Callable, Union
5
+
6
+ from matplotlib.figure import Figure
7
+ from mlflow.models import infer_signature
8
+ from torch import Tensor
9
+ from torch.nn import Module
10
+ from torch.utils.data import DataLoader
11
+ from torch.utils.tensorboard import SummaryWriter
12
+
13
+ from qadence.ml_tools.data import DictDataLoader
14
+ from qadence.types import ExperimentTrackingTool
15
+
16
+ logger = getLogger(__name__)
17
+
18
+ PlottingFunction = Callable[[Module, int], tuple[str, Figure]]
19
+ InputData = Union[Tensor, dict[str, Tensor]]
20
+
21
+
22
+ def print_metrics(loss: float | None, metrics: dict, iteration: int) -> None:
23
+ msg = " ".join(
24
+ [f"Iteration {iteration: >7} | Loss: {loss:.7f} -"]
25
+ + [f"{k}: {v.item():.7f}" for k, v in metrics.items()]
26
+ )
27
+ print(msg)
28
+
29
+
30
+ def write_tensorboard(
31
+ writer: SummaryWriter, loss: float = None, metrics: dict = {}, iteration: int = 0
32
+ ) -> None:
33
+ if loss is not None:
34
+ writer.add_scalar("loss", loss, iteration)
35
+ for key, arg in metrics.items():
36
+ writer.add_scalar(key, arg, iteration)
37
+
38
+
39
+ def log_hyperparams_tensorboard(writer: SummaryWriter, hyperparams: dict, metrics: dict) -> None:
40
+ writer.add_hparams(hyperparams, metrics)
41
+
42
+
43
+ def plot_tensorboard(
44
+ writer: SummaryWriter,
45
+ model: Module,
46
+ iteration: int,
47
+ plotting_functions: tuple[PlottingFunction],
48
+ ) -> None:
49
+ for pf in plotting_functions:
50
+ descr, fig = pf(model, iteration)
51
+ writer.add_figure(descr, fig, global_step=iteration)
52
+
53
+
54
+ def log_model_tensorboard(
55
+ writer: SummaryWriter,
56
+ model: Module,
57
+ dataloader: Union[None, DataLoader, DictDataLoader],
58
+ ) -> None:
59
+ logger.warning("Model logging is not supported by tensorboard. No model will be logged.")
60
+
61
+
62
+ def write_mlflow(writer: Any, loss: float | None, metrics: dict, iteration: int) -> None:
63
+ writer.log_metrics({"loss": float(loss)}, step=iteration) # type: ignore
64
+ writer.log_metrics(metrics, step=iteration) # logs the single metrics
65
+
66
+
67
+ def log_hyperparams_mlflow(writer: Any, hyperparams: dict, metrics: dict) -> None:
68
+ writer.log_params(hyperparams) # type: ignore
69
+
70
+
71
+ def plot_mlflow(
72
+ writer: Any,
73
+ model: Module,
74
+ iteration: int,
75
+ plotting_functions: tuple[PlottingFunction],
76
+ ) -> None:
77
+ for pf in plotting_functions:
78
+ descr, fig = pf(model, iteration)
79
+ writer.log_figure(fig, descr)
80
+
81
+
82
+ def log_model_mlflow(
83
+ writer: Any, model: Module, dataloader: DataLoader | DictDataLoader | None
84
+ ) -> None:
85
+ if dataloader is not None:
86
+ xs: InputData
87
+ xs, *_ = next(iter(dataloader))
88
+ preds = model(xs)
89
+ if isinstance(xs, Tensor):
90
+ xs = xs.numpy()
91
+ preds = preds.detach().numpy()
92
+ elif isinstance(xs, dict):
93
+ for key, val in xs.items():
94
+ xs[key] = val.numpy()
95
+ for key, val in preds.items():
96
+ preds[key] = val.detach.numpy()
97
+ signature = infer_signature(xs, preds)
98
+ else:
99
+ signature = None
100
+ writer.pytorch.log_model(model, artifact_path="model", signature=signature)
101
+
102
+
103
+ TRACKER_MAPPING: dict[ExperimentTrackingTool, Callable[..., None]] = {
104
+ ExperimentTrackingTool.TENSORBOARD: write_tensorboard,
105
+ ExperimentTrackingTool.MLFLOW: write_mlflow,
106
+ }
107
+
108
+ LOGGER_MAPPING: dict[ExperimentTrackingTool, Callable[..., None]] = {
109
+ ExperimentTrackingTool.TENSORBOARD: log_hyperparams_tensorboard,
110
+ ExperimentTrackingTool.MLFLOW: log_hyperparams_mlflow,
111
+ }
112
+
113
+ PLOTTER_MAPPING: dict[ExperimentTrackingTool, Callable[..., None]] = {
114
+ ExperimentTrackingTool.TENSORBOARD: plot_tensorboard,
115
+ ExperimentTrackingTool.MLFLOW: plot_mlflow,
116
+ }
117
+
118
+ MODEL_LOGGER_MAPPING: dict[ExperimentTrackingTool, Callable[..., None]] = {
119
+ ExperimentTrackingTool.TENSORBOARD: log_model_tensorboard,
120
+ ExperimentTrackingTool.MLFLOW: log_model_mlflow,
121
+ }
122
+
123
+
124
+ def write_tracker(
125
+ *args: Any, tracking_tool: ExperimentTrackingTool = ExperimentTrackingTool.TENSORBOARD
126
+ ) -> None:
127
+ return TRACKER_MAPPING[tracking_tool](*args)
128
+
129
+
130
+ def log_tracker(
131
+ *args: Any, tracking_tool: ExperimentTrackingTool = ExperimentTrackingTool.TENSORBOARD
132
+ ) -> None:
133
+ return LOGGER_MAPPING[tracking_tool](*args)
134
+
135
+
136
+ def plot_tracker(
137
+ *args: Any, tracking_tool: ExperimentTrackingTool = ExperimentTrackingTool.TENSORBOARD
138
+ ) -> None:
139
+ return PLOTTER_MAPPING[tracking_tool](*args)
140
+
141
+
142
+ def log_model_tracker(
143
+ *args: Any, tracking_tool: ExperimentTrackingTool = ExperimentTrackingTool.TENSORBOARD
144
+ ) -> None:
145
+ return MODEL_LOGGER_MAPPING[tracking_tool](*args)
@@ -1,10 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import importlib
3
4
  import math
4
5
  from logging import getLogger
5
6
  from typing import Callable, Union
6
7
 
7
- from rich.progress import BarColumn, Progress, TaskProgressColumn, TextColumn, TimeRemainingColumn
8
+ from rich.progress import (
9
+ BarColumn,
10
+ Progress,
11
+ TaskProgressColumn,
12
+ TextColumn,
13
+ TimeRemainingColumn,
14
+ )
8
15
  from torch import complex128, float32, float64
9
16
  from torch import device as torch_device
10
17
  from torch import dtype as torch_dtype
@@ -16,8 +23,15 @@ from torch.utils.tensorboard import SummaryWriter
16
23
  from qadence.ml_tools.config import TrainConfig
17
24
  from qadence.ml_tools.data import DictDataLoader, data_to_device
18
25
  from qadence.ml_tools.optimize_step import optimize_step
19
- from qadence.ml_tools.printing import print_metrics, write_tensorboard
26
+ from qadence.ml_tools.printing import (
27
+ log_model_tracker,
28
+ log_tracker,
29
+ plot_tracker,
30
+ print_metrics,
31
+ write_tracker,
32
+ )
20
33
  from qadence.ml_tools.saveload import load_checkpoint, write_checkpoint
34
+ from qadence.types import ExperimentTrackingTool
21
35
 
22
36
  logger = getLogger(__name__)
23
37
 
@@ -30,7 +44,6 @@ def train(
30
44
  loss_fn: Callable,
31
45
  device: torch_device = None,
32
46
  optimize_step: Callable = optimize_step,
33
- write_tensorboard: Callable = write_tensorboard,
34
47
  dtype: torch_dtype = None,
35
48
  ) -> tuple[Module, Optimizer]:
36
49
  """Runs the training loop with gradient-based optimizer.
@@ -48,15 +61,11 @@ def train(
48
61
  the model
49
62
  optimizer: The optimizer to use.
50
63
  config: `TrainConfig` with additional training options.
51
- loss_fn: Loss function returning (loss: float, metrics: dict[str, float])
64
+ loss_fn: Loss function returning (loss: float, metrics: dict[str, float], ...)
52
65
  device: String defining device to train on, pass 'cuda' for GPU.
53
66
  optimize_step: Customizable optimization callback which is called at every iteration.=
54
67
  The function must have the signature `optimize_step(model,
55
68
  optimizer, loss_fn, xs, device="cpu")`.
56
- write_tensorboard: Customizable tensorboard logging callback which is
57
- called every `config.write_every` iterations. The function must have
58
- the signature `write_tensorboard(writer, loss, metrics, iteration)`
59
- (see the example below).
60
69
  dtype: The dtype to use for the data.
61
70
 
62
71
  Example:
@@ -122,8 +131,11 @@ def train(
122
131
  model = model.module.to(device=device, dtype=dtype)
123
132
  else:
124
133
  model = model.to(device=device, dtype=dtype)
125
- # initialize tensorboard
126
- writer = SummaryWriter(config.folder, purge_step=init_iter)
134
+ # initialize tracking tool
135
+ if config.tracking_tool == ExperimentTrackingTool.TENSORBOARD:
136
+ writer = SummaryWriter(config.folder, purge_step=init_iter)
137
+ else:
138
+ writer = importlib.import_module("mlflow")
127
139
 
128
140
  perform_val = isinstance(config.val_every, int)
129
141
  if perform_val:
@@ -166,7 +178,7 @@ def train(
166
178
  best_val_loss, metrics = loss_fn(model, xs_to_device)
167
179
 
168
180
  metrics["val_loss"] = best_val_loss
169
- write_tensorboard(writer, None, metrics, init_iter)
181
+ write_tracker(writer, None, metrics, init_iter, tracking_tool=config.tracking_tool)
170
182
 
171
183
  if config.folder:
172
184
  if config.checkpoint_best_only:
@@ -174,6 +186,14 @@ def train(
174
186
  else:
175
187
  write_checkpoint(config.folder, model, optimizer, init_iter)
176
188
 
189
+ plot_tracker(
190
+ writer,
191
+ model,
192
+ init_iter,
193
+ config.plotting_functions,
194
+ tracking_tool=config.tracking_tool,
195
+ )
196
+
177
197
  except KeyboardInterrupt:
178
198
  logger.info("Terminating training gracefully after the current iteration.")
179
199
 
@@ -218,19 +238,31 @@ def train(
218
238
  print_metrics(loss, metrics, iteration - 1)
219
239
 
220
240
  if iteration % config.write_every == 0:
221
- write_tensorboard(writer, loss, metrics, iteration - 1)
241
+ write_tracker(
242
+ writer, loss, metrics, iteration, tracking_tool=config.tracking_tool
243
+ )
222
244
 
245
+ if iteration % config.plot_every == 0:
246
+ plot_tracker(
247
+ writer,
248
+ model,
249
+ iteration,
250
+ config.plotting_functions,
251
+ tracking_tool=config.tracking_tool,
252
+ )
223
253
  if perform_val:
224
254
  if iteration % config.val_every == 0:
225
255
  xs = next(dl_iter_val)
226
256
  xs_to_device = data_to_device(xs, device=device, dtype=data_dtype)
227
- val_loss, _ = loss_fn(model, xs_to_device)
257
+ val_loss, *_ = loss_fn(model, xs_to_device)
228
258
  if config.validation_criterion(val_loss, best_val_loss, config.val_epsilon): # type: ignore[misc]
229
259
  best_val_loss = val_loss
230
260
  if config.folder and config.checkpoint_best_only:
231
261
  write_checkpoint(config.folder, model, optimizer, iteration="best")
232
262
  metrics["val_loss"] = val_loss
233
- write_tensorboard(writer, None, metrics, iteration)
263
+ write_tracker(
264
+ writer, loss, metrics, iteration, tracking_tool=config.tracking_tool
265
+ )
234
266
 
235
267
  if config.folder:
236
268
  if iteration % config.checkpoint_every == 0 and not config.checkpoint_best_only:
@@ -245,17 +277,32 @@ def train(
245
277
  try:
246
278
  xs = next(dl_iter) if dataloader is not None else None # type: ignore[arg-type]
247
279
  xs_to_device = data_to_device(xs, device=device, dtype=data_dtype)
248
- loss, metrics = loss_fn(model, xs_to_device)
280
+ loss, metrics, *_ = loss_fn(model, xs_to_device)
281
+ if dataloader is None:
282
+ loss = loss.item()
249
283
  if iteration % config.print_every == 0 and config.verbose:
250
284
  print_metrics(loss, metrics, iteration)
251
285
 
252
286
  except KeyboardInterrupt:
253
287
  logger.info("Terminating training gracefully after the current iteration.")
254
288
 
255
- # Final printing, writing and checkpointing
289
+ # Final checkpointing and writing
256
290
  if config.folder and not config.checkpoint_best_only:
257
291
  write_checkpoint(config.folder, model, optimizer, iteration)
258
- write_tensorboard(writer, loss, metrics, iteration)
259
- writer.close()
292
+ write_tracker(writer, loss, metrics, iteration, tracking_tool=config.tracking_tool)
293
+
294
+ # writing hyperparameters
295
+ if config.hyperparams:
296
+ log_tracker(writer, config.hyperparams, metrics, tracking_tool=config.tracking_tool)
297
+
298
+ # logging the model
299
+ if config.log_model:
300
+ log_model_tracker(writer, model, dataloader, tracking_tool=config.tracking_tool)
301
+
302
+ # close tracker
303
+ if config.tracking_tool == ExperimentTrackingTool.TENSORBOARD:
304
+ writer.close()
305
+ elif config.tracking_tool == ExperimentTrackingTool.MLFLOW:
306
+ writer.end_run()
260
307
 
261
308
  return model, optimizer