squlearn 0.11.0__tar.gz → 0.11.2__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 (265) hide show
  1. {squlearn-0.11.0 → squlearn-0.11.2}/PKG-INFO +1 -1
  2. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/__init__.py +1 -1
  3. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/fidelity_kernel_statevector.py +70 -30
  4. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/base_qnn.py +26 -0
  5. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/lowlevel_qnn/lowlevel_qnn_pennylane.py +15 -1
  6. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/lowlevel_kernel/test_fidelity_kernel_statevector.py +58 -0
  7. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/lowlevel_qnn/test_lowlevel_qnn.py +26 -1
  8. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/test_qnnc.py +70 -2
  9. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/test_qnnr.py +74 -3
  10. {squlearn-0.11.0 → squlearn-0.11.2}/.github/CODE_OF_CONDUCT.md +0 -0
  11. {squlearn-0.11.0 → squlearn-0.11.2}/.github/CONTRIBUTING.md +0 -0
  12. {squlearn-0.11.0 → squlearn-0.11.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  13. {squlearn-0.11.0 → squlearn-0.11.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  14. {squlearn-0.11.0 → squlearn-0.11.2}/.github/workflows/doc_checks.yml +0 -0
  15. {squlearn-0.11.0 → squlearn-0.11.2}/.github/workflows/elaborate_tests.yaml +0 -0
  16. {squlearn-0.11.0 → squlearn-0.11.2}/.github/workflows/format.yml +0 -0
  17. {squlearn-0.11.0 → squlearn-0.11.2}/.github/workflows/publish.yml +0 -0
  18. {squlearn-0.11.0 → squlearn-0.11.2}/.github/workflows/publish_docs.yml +0 -0
  19. {squlearn-0.11.0 → squlearn-0.11.2}/.github/workflows/quick_tests.yaml +0 -0
  20. {squlearn-0.11.0 → squlearn-0.11.2}/.github/workflows/stale.yml +0 -0
  21. {squlearn-0.11.0 → squlearn-0.11.2}/.gitignore +0 -0
  22. {squlearn-0.11.0 → squlearn-0.11.2}/CITATION.cff +0 -0
  23. {squlearn-0.11.0 → squlearn-0.11.2}/LICENSE.txt +0 -0
  24. {squlearn-0.11.0 → squlearn-0.11.2}/README.md +0 -0
  25. {squlearn-0.11.0 → squlearn-0.11.2}/docs/Makefile +0 -0
  26. {squlearn-0.11.0 → squlearn-0.11.2}/docs/README.md +0 -0
  27. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/css/custom.css +0 -0
  28. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/favicon.png +0 -0
  29. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/logo.png +0 -0
  30. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/qkm/QKM_scheme_pic.jpg +0 -0
  31. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/qnn/qnn.svg +0 -0
  32. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/qrc/QRC_user_guide.png +0 -0
  33. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/qrc/qrc_classification_transparent.png +0 -0
  34. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/qrc/qrc_regression_transparent.png +0 -0
  35. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/schematic.png +0 -0
  36. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_static/util/executor.png +0 -0
  37. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_templates/class.rst +0 -0
  38. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_templates/class_with_call.rst +0 -0
  39. {squlearn-0.11.0 → squlearn-0.11.2}/docs/_templates/function.rst +0 -0
  40. {squlearn-0.11.0 → squlearn-0.11.2}/docs/conf.py +0 -0
  41. {squlearn-0.11.0 → squlearn-0.11.2}/docs/examples/example_kernel_digit_classification.nblink +0 -0
  42. {squlearn-0.11.0 → squlearn-0.11.2}/docs/examples/example_kernel_grid_search.nblink +0 -0
  43. {squlearn-0.11.0 → squlearn-0.11.2}/docs/examples/example_ode_solver.nblink +0 -0
  44. {squlearn-0.11.0 → squlearn-0.11.2}/docs/examples/example_qnn_backend_mitigation.nblink +0 -0
  45. {squlearn-0.11.0 → squlearn-0.11.2}/docs/examples/example_quantum_bayesian_optimization.nblink +0 -0
  46. {squlearn-0.11.0 → squlearn-0.11.2}/docs/examples/examples_index.rst +0 -0
  47. {squlearn-0.11.0 → squlearn-0.11.2}/docs/index.rst +0 -0
  48. {squlearn-0.11.0 → squlearn-0.11.2}/docs/install/install.rst +0 -0
  49. {squlearn-0.11.0 → squlearn-0.11.2}/docs/make.bat +0 -0
  50. {squlearn-0.11.0 → squlearn-0.11.2}/docs/modules/classes.rst +0 -0
  51. {squlearn-0.11.0 → squlearn-0.11.2}/docs/qiskit_settings.conf +0 -0
  52. {squlearn-0.11.0 → squlearn-0.11.2}/docs/spelling_wordlist.txt +0 -0
  53. {squlearn-0.11.0 → squlearn-0.11.2}/docs/user_guide/encoding_circuits.rst +0 -0
  54. {squlearn-0.11.0 → squlearn-0.11.2}/docs/user_guide/executor.rst +0 -0
  55. {squlearn-0.11.0 → squlearn-0.11.2}/docs/user_guide/kernel_methods.rst +0 -0
  56. {squlearn-0.11.0 → squlearn-0.11.2}/docs/user_guide/observables.rst +0 -0
  57. {squlearn-0.11.0 → squlearn-0.11.2}/docs/user_guide/quantum_neural_networks.rst +0 -0
  58. {squlearn-0.11.0 → squlearn-0.11.2}/docs/user_guide/quantum_reservoir_computing.rst +0 -0
  59. {squlearn-0.11.0 → squlearn-0.11.2}/docs/user_guide/user_guide_index.rst +0 -0
  60. {squlearn-0.11.0 → squlearn-0.11.2}/examples/encoding_circuits/layered_encoding_circuit.ipynb +0 -0
  61. {squlearn-0.11.0 → squlearn-0.11.2}/examples/encoding_circuits/pruning_example.ipynb +0 -0
  62. {squlearn-0.11.0 → squlearn-0.11.2}/examples/encoding_circuits/various_encoding_circuit.ipynb +0 -0
  63. {squlearn-0.11.0 → squlearn-0.11.2}/examples/executor/example_executor_qiskit.ipynb +0 -0
  64. {squlearn-0.11.0 → squlearn-0.11.2}/examples/integration/mlflow.ipynb +0 -0
  65. {squlearn-0.11.0 → squlearn-0.11.2}/examples/kernel/example_fidelity_kernel.ipynb +0 -0
  66. {squlearn-0.11.0 → squlearn-0.11.2}/examples/kernel/example_projected_kernel.ipynb +0 -0
  67. {squlearn-0.11.0 → squlearn-0.11.2}/examples/kernel/example_qkode.ipynb +0 -0
  68. {squlearn-0.11.0 → squlearn-0.11.2}/examples/kernel/example_regularization_mitigation.ipynb +0 -0
  69. {squlearn-0.11.0 → squlearn-0.11.2}/examples/kernel/qgpc_workflow.ipynb +0 -0
  70. {squlearn-0.11.0 → squlearn-0.11.2}/examples/kernel/qgpr_optimization_workflow.ipynb +0 -0
  71. {squlearn-0.11.0 → squlearn-0.11.2}/examples/kernel/qgpr_workflow.ipynb +0 -0
  72. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qnn/classification_example.ipynb +0 -0
  73. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qnn/example_adam.ipynb +0 -0
  74. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qnn/example_minibatch.ipynb +0 -0
  75. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qnn/example_qcnn_encoding_circuit.ipynb +0 -0
  76. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qnn/multiclass_classification.ipynb +0 -0
  77. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qnn/ode_example.ipynb +0 -0
  78. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qnn/regression_example.ipynb +0 -0
  79. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qnn/regression_with_variance.ipynb +0 -0
  80. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qrc/qrc_classification.ipynb +0 -0
  81. {squlearn-0.11.0 → squlearn-0.11.2}/examples/qrc/qrc_regression.ipynb +0 -0
  82. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/images/QK_ode_circ_workflow.png +0 -0
  83. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/images/QNN_ode_workflow.png +0 -0
  84. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/images/encoding_circuit.png +0 -0
  85. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/images/pipeline.png +0 -0
  86. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/images/projected_quantum_kernel.png +0 -0
  87. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/images/quantum_bo.png +0 -0
  88. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/kernel_digit_classification.ipynb +0 -0
  89. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/kernel_grid_search.ipynb +0 -0
  90. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/kernel_regression.ipynb +0 -0
  91. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/ode_solver.ipynb +0 -0
  92. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/qnn_backend_mitigation.ipynb +0 -0
  93. {squlearn-0.11.0 → squlearn-0.11.2}/examples/tutorials/quantum_bayesian_optimization.ipynb +0 -0
  94. {squlearn-0.11.0 → squlearn-0.11.2}/install_lowest_dependencies.py +0 -0
  95. {squlearn-0.11.0 → squlearn-0.11.2}/output.png +0 -0
  96. {squlearn-0.11.0 → squlearn-0.11.2}/pyproject.toml +0 -0
  97. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/__init__.py +0 -0
  98. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/__init__.py +0 -0
  99. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/chebyshev_pqc.py +0 -0
  100. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/chebyshev_rx.py +0 -0
  101. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/chebyshev_tower.py +0 -0
  102. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/highdim_encoding_circuit.py +0 -0
  103. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/hubregtsen_encoding_circuit.py +0 -0
  104. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/kyriienko_nonlinear_encoding_circuit.py +0 -0
  105. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/multi_control_encoding_circuit.py +0 -0
  106. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/param_z_feature_map.py +0 -0
  107. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/qcnn_encoding_circuit.py +0 -0
  108. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/qiskit_encoding_circuit.py +0 -0
  109. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/random_encoding_circuit.py +0 -0
  110. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/random_layered_encoding_circuit.py +0 -0
  111. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/circuit_library/yz_cx_encoding_circuit.py +0 -0
  112. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/encoding_circuit_base.py +0 -0
  113. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/encoding_circuit_derivatives.py +0 -0
  114. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/layered_encoding_circuit.py +0 -0
  115. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/pruned_encoding_circuit.py +0 -0
  116. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/encoding_circuit/transpiled_encoding_circuit.py +0 -0
  117. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/__init__.py +0 -0
  118. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/loss/__init__.py +0 -0
  119. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/loss/kernel_loss_base.py +0 -0
  120. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/loss/negative_log_likelihood.py +0 -0
  121. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/loss/ode_loss.py +0 -0
  122. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/loss/target_alignment.py +0 -0
  123. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/__init__.py +0 -0
  124. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/fidelity_kernel.py +0 -0
  125. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/fidelity_kernel_expectation_value.py +0 -0
  126. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/kernel_matrix_base.py +0 -0
  127. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/kernel_optimizer.py +0 -0
  128. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/kernel_util.py +0 -0
  129. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/projected_quantum_kernel.py +0 -0
  130. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/lowlevel_kernel/regularization.py +0 -0
  131. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/qgpc.py +0 -0
  132. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/qgpr.py +0 -0
  133. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/qkode.py +0 -0
  134. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/qkrr.py +0 -0
  135. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/qsvc.py +0 -0
  136. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/kernel/qsvr.py +0 -0
  137. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/__init__.py +0 -0
  138. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_base.py +0 -0
  139. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_derivatives.py +0 -0
  140. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_implemented/__init__.py +0 -0
  141. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_implemented/custom_observable.py +0 -0
  142. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_implemented/ising_hamiltonian.py +0 -0
  143. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_implemented/single_pauli.py +0 -0
  144. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_implemented/single_probability.py +0 -0
  145. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_implemented/summed_paulis.py +0 -0
  146. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/observables/observable_implemented/summed_probabilities.py +0 -0
  147. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/optimizers/__init__.py +0 -0
  148. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/optimizers/adam.py +0 -0
  149. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/optimizers/approximated_gradients.py +0 -0
  150. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/optimizers/optimizer_base.py +0 -0
  151. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/optimizers/optimizers_wrapper.py +0 -0
  152. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/optimizers/sglbo.py +0 -0
  153. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/__init__.py +0 -0
  154. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/loss/__init__.py +0 -0
  155. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/loss/cross_entropy_loss.py +0 -0
  156. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/loss/mean_squared_error.py +0 -0
  157. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/loss/ode_loss.py +0 -0
  158. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/loss/parameter_regularization_loss.py +0 -0
  159. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/loss/qnn_loss_base.py +0 -0
  160. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/loss/squared_loss.py +0 -0
  161. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/loss/variance_loss.py +0 -0
  162. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/lowlevel_qnn/__init__.py +0 -0
  163. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/lowlevel_qnn/evaluation_classes.py +0 -0
  164. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/lowlevel_qnn/lowlevel_qnn.py +0 -0
  165. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/lowlevel_qnn/lowlevel_qnn_base.py +0 -0
  166. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/lowlevel_qnn/lowlevel_qnn_qiskit.py +0 -0
  167. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/lowlevel_qnn/lowlevel_qnn_qulacs.py +0 -0
  168. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/qnnc.py +0 -0
  169. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/qnnr.py +0 -0
  170. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/util/__init__.py +0 -0
  171. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/util/barren_plateau_analysis.py +0 -0
  172. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qnn/util/training.py +0 -0
  173. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qrc/__init__.py +0 -0
  174. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qrc/base_qrc.py +0 -0
  175. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qrc/qrc_classifier.py +0 -0
  176. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qrc/qrc_regressor.py +0 -0
  177. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qrc/util/__init__.py +0 -0
  178. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/qrc/util/random_pauli_list.py +0 -0
  179. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/__init__.py +0 -0
  180. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/data_preprocessing.py +0 -0
  181. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/decompose_to_std.py +0 -0
  182. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/execution/__init__.py +0 -0
  183. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/execution/automatic_backend_selection.py +0 -0
  184. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/execution/hqaa/__init__.py +0 -0
  185. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/execution/hqaa/heuristic.py +0 -0
  186. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/execution/hqaa/parser.py +0 -0
  187. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/execution/parallel_estimator.py +0 -0
  188. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/execution/parallel_sampler.py +0 -0
  189. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/executor.py +0 -0
  190. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/optree/__init__.py +0 -0
  191. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/optree/optree.py +0 -0
  192. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/optree/optree_derivative.py +0 -0
  193. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/optree/optree_evaluate.py +0 -0
  194. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/pennylane/__init__.py +0 -0
  195. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/pennylane/pennylane_circuit.py +0 -0
  196. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/pennylane/pennylane_gates.py +0 -0
  197. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/qfi.py +0 -0
  198. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/qulacs/__init__.py +0 -0
  199. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/qulacs/qulacs_circuit.py +0 -0
  200. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/qulacs/qulacs_execution.py +0 -0
  201. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/qulacs/qulacs_gates.py +0 -0
  202. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/serialization/__init__.py +0 -0
  203. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/serialization/model_pickler.py +0 -0
  204. {squlearn-0.11.0 → squlearn-0.11.2}/src/squlearn/util/serialization/serializable_model_mixin.py +0 -0
  205. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_chebyshev_pqc.py +0 -0
  206. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_chebyshev_rx.py +0 -0
  207. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_chebyshev_tower.py +0 -0
  208. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_high_dim_encoding_circuit.py +0 -0
  209. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_hubregtsen_encoding_circuit.py +0 -0
  210. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_kyriienko_encoding_circuit.py +0 -0
  211. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_multi_control_encoding_circuit.py +0 -0
  212. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_param_z_feature_map.py +0 -0
  213. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_qcnn_encoding_circuit.py +0 -0
  214. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_qiskit_encoding_circuit.py +0 -0
  215. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_random_encoding_circuit.py +0 -0
  216. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_random_layered_encoding_circuit.py +0 -0
  217. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/circuit_library/test_yz_cx_encoding_circuit.py +0 -0
  218. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/test_encoding_circuit_base.py +0 -0
  219. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/test_encoding_circuit_derivatives.py +0 -0
  220. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/test_layered_encoding_circuit.py +0 -0
  221. {squlearn-0.11.0 → squlearn-0.11.2}/tests/encoding_circuit/test_pruned_encoding_circuit.py +0 -0
  222. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/loss/test_ode_loss.py +0 -0
  223. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/lowlevel_kernel/test_fidelity_kernel.py +0 -0
  224. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/lowlevel_kernel/test_fidelity_kernel_expectation_value.py +0 -0
  225. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/lowlevel_kernel/test_fidelity_quantum_kernel.py +0 -0
  226. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/lowlevel_kernel/test_kernel_optimizer.py +0 -0
  227. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/lowlevel_kernel/test_projected_quantum_kernel.py +0 -0
  228. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/ml/test_qkode.py +0 -0
  229. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/test_qgpc.py +0 -0
  230. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/test_qgpr.py +0 -0
  231. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/test_qkrr.py +0 -0
  232. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/test_qsvc.py +0 -0
  233. {squlearn-0.11.0 → squlearn-0.11.2}/tests/kernel/test_qsvr.py +0 -0
  234. {squlearn-0.11.0 → squlearn-0.11.2}/tests/observables/observable_implemented/test_custom_observable.py +0 -0
  235. {squlearn-0.11.0 → squlearn-0.11.2}/tests/observables/observable_implemented/test_ising_hamiltonian.py +0 -0
  236. {squlearn-0.11.0 → squlearn-0.11.2}/tests/observables/observable_implemented/test_single_pauli.py +0 -0
  237. {squlearn-0.11.0 → squlearn-0.11.2}/tests/observables/observable_implemented/test_single_probability.py +0 -0
  238. {squlearn-0.11.0 → squlearn-0.11.2}/tests/observables/observable_implemented/test_summed_paulis.py +0 -0
  239. {squlearn-0.11.0 → squlearn-0.11.2}/tests/observables/observable_implemented/test_summed_probability.py +0 -0
  240. {squlearn-0.11.0 → squlearn-0.11.2}/tests/observables/test_observable_base.py +0 -0
  241. {squlearn-0.11.0 → squlearn-0.11.2}/tests/optimizers/test_adam.py +0 -0
  242. {squlearn-0.11.0 → squlearn-0.11.2}/tests/optimizers/test_approximated_gradients.py +0 -0
  243. {squlearn-0.11.0 → squlearn-0.11.2}/tests/optimizers/test_optimizers_wrapper.py +0 -0
  244. {squlearn-0.11.0 → squlearn-0.11.2}/tests/optimizers/test_sglbo.py +0 -0
  245. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qiskit_circuit_equivalence.py +0 -0
  246. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/loss/test_cross_entropy_loss.py +0 -0
  247. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/loss/test_mean_squared_error.py +0 -0
  248. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/loss/test_ode_loss.py +0 -0
  249. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/loss/test_parameter_regularization_loss.py +0 -0
  250. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/loss/test_squared_loss.py +0 -0
  251. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/loss/test_variance_loss.py +0 -0
  252. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/test_base_qnn.py +0 -0
  253. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/test_loss.py +0 -0
  254. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qnn/test_training.py +0 -0
  255. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qrc/test_base_qrc.py +0 -0
  256. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qrc/test_qrc_classifier.py +0 -0
  257. {squlearn-0.11.0 → squlearn-0.11.2}/tests/qrc/test_qrc_regressor.py +0 -0
  258. {squlearn-0.11.0 → squlearn-0.11.2}/tests/util/execution/test_automatic_backend_selection.py +0 -0
  259. {squlearn-0.11.0 → squlearn-0.11.2}/tests/util/execution/test_parallel_primitives.py +0 -0
  260. {squlearn-0.11.0 → squlearn-0.11.2}/tests/util/optree/test_optree_derivative.py +0 -0
  261. {squlearn-0.11.0 → squlearn-0.11.2}/tests/util/optree/test_optree_evaluate.py +0 -0
  262. {squlearn-0.11.0 → squlearn-0.11.2}/tests/util/serialization/test_model_pickler.py +0 -0
  263. {squlearn-0.11.0 → squlearn-0.11.2}/tests/util/test_executor.py +0 -0
  264. {squlearn-0.11.0 → squlearn-0.11.2}/tests/util/test_pennylane_circuit.py +0 -0
  265. {squlearn-0.11.0 → squlearn-0.11.2}/tests/util/test_transpiler_target_aliases.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: squlearn
3
- Version: 0.11.0
3
+ Version: 0.11.2
4
4
  Summary: A library for quantum machine learning following the scikit-learn standard.
5
5
  Keywords: quantum,machine learning,qml
6
6
  Author-email: David Kreplin <david.kreplin@ipa.fraunhofer.de>, Moritz Willmann <moritz.willmann@ipa.fraunhofer.de>, Jan Schnabel <jan.schnabel@ipa.fraunhofer.de>, Frederic Rapp <frederic.rapp@ipa.fraunhofer.de>, Manuel Hagelüken <manuel.hagelueken@ipa.fraunhofer.de>, Marco Roth <marco.roth@ipa.fraunhofer.de>
@@ -3,7 +3,7 @@
3
3
  from .util import Executor
4
4
  from . import observables, encoding_circuit, kernel, optimizers, qnn, util
5
5
 
6
- __version__ = "0.11.0"
6
+ __version__ = "0.11.2"
7
7
 
8
8
  __all__ = [
9
9
  "Executor",
@@ -74,47 +74,19 @@ class FidelityKernelStatevector:
74
74
  circuit = transpile(enc_circ, target=qiskit_pennylane_target, optimization_level=0)
75
75
  self._pennylane_circuit = PennyLaneCircuit(circuit, "state")
76
76
 
77
- @lru_cache(maxsize=self._cache_size)
78
- def pennylane_circuit_executor(*args, **kwargs):
79
- args_numpy = [np.array(arg) for arg in args]
80
- return self._executor.pennylane_execute(
81
- self._pennylane_circuit, *args_numpy, **kwargs
82
- )
83
-
84
- self._cached_execution = pennylane_circuit_executor
85
-
86
77
  elif self._executor.quantum_framework == "qulacs":
87
78
 
88
79
  enc_circ = self._encoding_circuit.get_circuit(x, self._parameter_vector)
89
80
  self._qulacs_circuit = QulacsCircuit(enc_circ, None)
90
81
 
91
- @lru_cache(maxsize=self._cache_size)
92
- def qulacs_circuit_executor(*args):
93
- args_numpy = [np.array(arg) for arg in args]
94
- if len(args_numpy) == 0:
95
- return self._executor.qulacs_execute(
96
- qulacs_evaluate_statevector, self._qulacs_circuit
97
- )
98
- elif len(args_numpy) == 1:
99
- return self._executor.qulacs_execute(
100
- qulacs_evaluate_statevector, self._qulacs_circuit, x=args_numpy[0]
101
- )
102
- elif len(args_numpy) == 2:
103
- return self._executor.qulacs_execute(
104
- qulacs_evaluate_statevector,
105
- self._qulacs_circuit,
106
- p=args_numpy[0],
107
- x=args_numpy[1],
108
- )
109
-
110
- self._cached_execution = qulacs_circuit_executor
111
-
112
82
  else:
113
83
  raise RuntimeError(
114
84
  "Quantum framework not supported for FidelityKernelStatevector: "
115
85
  f"{self._executor.quantum_framework}"
116
86
  )
117
87
 
88
+ self._build_cached_execution()
89
+
118
90
  else:
119
91
 
120
92
  # Mode 2 for shot based: calculate the |0> probabilities
@@ -144,6 +116,74 @@ class FidelityKernelStatevector:
144
116
  f"{self._executor.quantum_framework}"
145
117
  )
146
118
 
119
+ def _build_cached_execution(self) -> None:
120
+ """(Re)create the ``lru_cache``-wrapped circuit executor.
121
+
122
+ Only statevector kernels use a cached executor (shot-based kernels do
123
+ not). The closure is rebuilt from the already-constructed circuit
124
+ object rather than from the executor's framework, so it survives being
125
+ deserialized onto a different backend executor (see
126
+ :meth:`__getstate__`/:meth:`__setstate__`).
127
+ """
128
+ if not self._executor.is_statevector:
129
+ return
130
+
131
+ if getattr(self, "_qulacs_circuit", None) is not None:
132
+
133
+ @lru_cache(maxsize=self._cache_size)
134
+ def qulacs_circuit_executor(*args):
135
+ args_numpy = [np.array(arg) for arg in args]
136
+ if len(args_numpy) == 0:
137
+ return self._executor.qulacs_execute(
138
+ qulacs_evaluate_statevector, self._qulacs_circuit
139
+ )
140
+ elif len(args_numpy) == 1:
141
+ return self._executor.qulacs_execute(
142
+ qulacs_evaluate_statevector, self._qulacs_circuit, x=args_numpy[0]
143
+ )
144
+ elif len(args_numpy) == 2:
145
+ return self._executor.qulacs_execute(
146
+ qulacs_evaluate_statevector,
147
+ self._qulacs_circuit,
148
+ p=args_numpy[0],
149
+ x=args_numpy[1],
150
+ )
151
+
152
+ self._cached_execution = qulacs_circuit_executor
153
+
154
+ elif getattr(self, "_pennylane_circuit", None) is not None:
155
+
156
+ @lru_cache(maxsize=self._cache_size)
157
+ def pennylane_circuit_executor(*args, **kwargs):
158
+ args_numpy = [np.array(arg) for arg in args]
159
+ return self._executor.pennylane_execute(
160
+ self._pennylane_circuit, *args_numpy, **kwargs
161
+ )
162
+
163
+ self._cached_execution = pennylane_circuit_executor
164
+
165
+ def __getstate__(self) -> dict:
166
+ """Return a picklable copy of the kernel's state.
167
+
168
+ ``self._cached_execution`` is a local closure wrapped in
169
+ :func:`functools.lru_cache`. Such objects are not picklable by
170
+ reference: pickle/cloudpickle serialize them via the wrapped function's
171
+ ``<locals>`` qualname
172
+ (``FidelityKernelStatevector.__init__.<locals>.qulacs_circuit_executor``),
173
+ which cannot be resolved on load -> ``AttributeError: Can't get local
174
+ object ...``. It is a pure memoization cache, so we drop it here and
175
+ rebuild it in :meth:`__setstate__`; every other attribute (including the
176
+ circuit objects) is preserved unchanged.
177
+ """
178
+ state = self.__dict__.copy()
179
+ state.pop("_cached_execution", None)
180
+ return state
181
+
182
+ def __setstate__(self, state: dict) -> None:
183
+ """Restore the kernel and rebuild the dropped executor closure."""
184
+ self.__dict__.update(state)
185
+ self._build_cached_execution()
186
+
147
187
  @property
148
188
  def num_parameters(self) -> int:
149
189
  """Returns the number of trainable parameters."""
@@ -118,6 +118,7 @@ class BaseQNN(BaseEstimator, SerializableModelMixin, ABC):
118
118
  self.shuffle = shuffle
119
119
 
120
120
  self.opt_param_op = opt_param_op
121
+ self._maybe_disable_opt_param_op()
121
122
 
122
123
  self.caching = caching
123
124
  self.pretrained = pretrained
@@ -301,8 +302,33 @@ class BaseQNN(BaseEstimator, SerializableModelMixin, ABC):
301
302
  self._is_fitted = False
302
303
  self._is_lowlevel_qnn_initialized = not initialize_qnn
303
304
 
305
+ self._maybe_disable_opt_param_op()
306
+
304
307
  return self
305
308
 
309
+ def _maybe_disable_opt_param_op(self) -> None:
310
+ """Force ``opt_param_op`` off when the observable has no trainable params.
311
+
312
+ Optimizing zero parameters is a no-op. Worse, for multi-output QNNs
313
+ (operator passed as a list), letting the training loop request
314
+ ``dfdop`` returns an empty (1, 0) sentinel from
315
+ ``LowLevelQNNPennyLane._evaluate_todo_all_x`` that downstream
316
+ ``_evaluate`` cannot reshape, crashing with
317
+ ``ValueError: cannot reshape array of size 0 into shape (k, 1)``.
318
+
319
+ Only the ``True -> False`` direction is auto-applied; if the user
320
+ explicitly disabled observable-parameter optimization, that choice is
321
+ respected even if the observable does have trainable parameters.
322
+ """
323
+ if not self.opt_param_op:
324
+ return
325
+ if isinstance(self.operator, list):
326
+ num_op_parameters = sum(op.num_parameters for op in self.operator)
327
+ else:
328
+ num_op_parameters = self.operator.num_parameters
329
+ if num_op_parameters == 0:
330
+ self.opt_param_op = False
331
+
306
332
  def _predict(self, X: np.ndarray) -> np.ndarray:
307
333
  """Predict using the QNN.
308
334
 
@@ -498,7 +498,14 @@ class LowLevelQNNPennyLane(LowLevelQNNBase):
498
498
  value = self._executor.pennylane_execute(deriv, *(eval_tuple))
499
499
 
500
500
  # Convert back to numpy array
501
- return np.real_if_close(np.array(value))
501
+ values = np.array(value)
502
+ # PennyLane collapses the leading "observable" axis when a multi-output
503
+ # QNN has only one observable. Restore it so downstream shape logic
504
+ # (swap_list in _evaluate) sees the (num_obs, ...) layout consistent
505
+ # with the multi-observable case.
506
+ if self.multiple_output and self.num_operator == 1:
507
+ values = values.reshape((1,) + values.shape)
508
+ return np.real_if_close(values)
502
509
 
503
510
  def _evaluate_todo_all_x(
504
511
  self, todo_class: DirectEvaluation, x: np.array, param: np.array, param_obs: np.array
@@ -584,6 +591,13 @@ class LowLevelQNNPennyLane(LowLevelQNNBase):
584
591
 
585
592
  # Convert back to numpy format
586
593
  values = np.array(value)
594
+ # PennyLane collapses the leading "observable" axis when a multi-output
595
+ # QNN has only one observable. Restore it so the sum_t bookkeeping below
596
+ # (which assumes ioff=1 for multiple_output) and the downstream swap_list
597
+ # in _evaluate see the (num_obs, ...) layout consistent with the
598
+ # multi-observable case.
599
+ if self.multiple_output and self.num_operator == 1:
600
+ values = values.reshape((1,) + values.shape)
587
601
  # sum over zero values entries due to dx differentiation
588
602
  if todo_class.return_grad_x:
589
603
  sum_t = tuple()
@@ -1,7 +1,10 @@
1
+ import pickle
1
2
  from unittest.mock import MagicMock
2
3
  import numpy as np
3
4
  import pytest
5
+ from squlearn.encoding_circuit import ChebyshevPQC
4
6
  from squlearn.kernel.lowlevel_kernel.fidelity_kernel_statevector import FidelityKernelStatevector
7
+ from squlearn.util import Executor
5
8
 
6
9
 
7
10
  def make_executor(is_statevector=True, framework="pennylane", shots=None):
@@ -298,3 +301,58 @@ class TestFidelityKernelStatevector:
298
301
  x = np.array([[0.1]])
299
302
  with pytest.raises(ValueError):
300
303
  k.evaluate_kernel_sv(x, x)
304
+
305
+
306
+ def _make_statevector_kernel(framework):
307
+ executor = Executor(framework)
308
+ encoding_circuit = ChebyshevPQC(num_qubits=2, num_features=2, num_layers=1)
309
+ kernel = FidelityKernelStatevector(
310
+ encoding_circuit=encoding_circuit, executor=executor, num_features=2
311
+ )
312
+ rng = np.random.default_rng(0)
313
+ if kernel.num_parameters > 0:
314
+ kernel.assign_training_parameters(rng.random(kernel.num_parameters))
315
+ return kernel
316
+
317
+
318
+ def test_pickle_roundtrip_preserves_kernel_qulacs():
319
+ """A qulacs statevector kernel must survive stdlib pickling.
320
+
321
+ ``_cached_execution`` is an ``lru_cache``-wrapped local closure that cannot
322
+ be pickled by reference (the original ``AttributeError: Can't get local
323
+ object ...``); ``__getstate__``/``__setstate__`` drop and rebuild it. The
324
+ pennylane circuit holds a sympy lambda that stdlib pickle cannot handle
325
+ regardless, so that framework is covered by the dill-based ModelPickler
326
+ serialization tests and by ``test_getstate_setstate_rebuilds_executor``.
327
+ """
328
+ kernel = _make_statevector_kernel("qulacs")
329
+ x = np.random.default_rng(0).random((4, 2))
330
+ expected = kernel.evaluate(x, x)
331
+
332
+ restored = pickle.loads(pickle.dumps(kernel))
333
+
334
+ assert "_cached_execution" in vars(restored)
335
+ np.testing.assert_allclose(restored.evaluate(x, x), expected)
336
+
337
+
338
+ @pytest.mark.parametrize("framework", ["qulacs", "pennylane"])
339
+ def test_getstate_setstate_rebuilds_executor(framework):
340
+ """__getstate__ drops the unpicklable closure; __setstate__ rebuilds it.
341
+
342
+ Exercises the mechanism directly (no pickling), so it covers pennylane too,
343
+ and confirms the rebuilt kernel reproduces the original kernel matrix.
344
+ """
345
+ kernel = _make_statevector_kernel(framework)
346
+ x = np.random.default_rng(0).random((4, 2))
347
+ expected = kernel.evaluate(x, x)
348
+
349
+ state = kernel.__getstate__()
350
+ assert "_cached_execution" not in state
351
+
352
+ restored = FidelityKernelStatevector.__new__(FidelityKernelStatevector)
353
+ restored.__setstate__(state)
354
+
355
+ assert "_cached_execution" in vars(restored)
356
+ np.testing.assert_allclose(restored.evaluate(x, x), expected)
357
+ if kernel._parameters is not None:
358
+ np.testing.assert_allclose(restored._parameters, kernel._parameters)
@@ -4,7 +4,7 @@ import numpy as np
4
4
 
5
5
  from squlearn import Executor
6
6
  from squlearn.encoding_circuit import ParamZFeatureMap
7
- from squlearn.observables import SummedPaulis
7
+ from squlearn.observables import SinglePauli, SummedPaulis
8
8
  from squlearn.qnn.lowlevel_qnn import LowLevelQNN
9
9
 
10
10
 
@@ -63,3 +63,28 @@ def test_backends_consistency():
63
63
  values_qiskit[qiskit_param_op_key], values_pennylane[pennylane_param_op_key]
64
64
  )
65
65
  assert np.allclose(values_qiskit[qiskit_param_op_key], values_qulacs[qulacs_param_op_key])
66
+
67
+
68
+ @pytest.mark.parametrize("framework", ["pennylane", "qiskit", "qulacs"])
69
+ @pytest.mark.parametrize("n_obs", [1, 2])
70
+ def test_multiple_output_shape_with_n_observables(framework, n_obs):
71
+ """Regression: a list-of-one observable must produce the same shape contract
72
+ as a list of multiple observables. PennyLane otherwise collapses the leading
73
+ "observable" axis when only one measurement is returned, which previously
74
+ crashed ProjectedQuantumKernel for num_qubits=1 with a single-Pauli measurement.
75
+ """
76
+ pqc = ParamZFeatureMap(4, 2)
77
+ obs = [SinglePauli(4, i, op_str="X") for i in range(n_obs)]
78
+ llqnn = LowLevelQNN(pqc, obs, executor=Executor(framework), num_features=2)
79
+
80
+ np.random.seed(42)
81
+ x = np.random.rand(5, 2)
82
+ param = np.random.rand(llqnn.num_parameters)
83
+
84
+ assert llqnn.evaluate(x, param, [], "f")["f"].shape == (5, n_obs)
85
+ assert llqnn.evaluate(x, param, [], "dfdx")["dfdx"].shape == (5, n_obs, 2)
86
+ assert llqnn.evaluate(x, param, [], "dfdp")["dfdp"].shape == (
87
+ 5,
88
+ n_obs,
89
+ llqnn.num_parameters,
90
+ )
@@ -8,10 +8,10 @@ from sklearn.datasets import make_blobs
8
8
  from sklearn.preprocessing import LabelBinarizer, MinMaxScaler
9
9
 
10
10
  from squlearn import Executor
11
- from squlearn.observables import SummedPaulis
11
+ from squlearn.observables import SinglePauli, SummedPaulis
12
12
  from squlearn.encoding_circuit import ChebyshevPQC
13
13
  from squlearn.optimizers import SLSQP, Adam
14
- from squlearn.qnn import CrossEntropyLoss, QNNClassifier
14
+ from squlearn.qnn import CrossEntropyLoss, QNNClassifier, SquaredLoss
15
15
 
16
16
 
17
17
  class TestQNNClassifier:
@@ -240,3 +240,71 @@ class TestQNNClassifier:
240
240
  assert instance_loaded._is_fitted
241
241
  assert np.allclose(instance_loaded.param, qnn_classifier.param)
242
242
  assert np.allclose(instance_loaded.param_op, qnn_classifier.param_op)
243
+
244
+ def _make_opt_param_op_qnnc(self, operator, **overrides) -> QNNClassifier:
245
+ """QNNClassifier with a parameterless-observable-friendly setup.
246
+
247
+ Used by the ``opt_param_op`` auto-correction regression tests below.
248
+ ``ChebyshevPQC`` carries trainable circuit params (so training would
249
+ request ``dfdp`` and reach the empty-``dfdop`` early-return on the
250
+ PennyLane backend), and ``Adam`` exercises the SGD/``train_mini_batch``
251
+ path where the bug originally surfaced.
252
+ """
253
+ kwargs = dict(
254
+ encoding_circuit=ChebyshevPQC(num_qubits=2, num_features=2, num_layers=2),
255
+ operator=operator,
256
+ executor=Executor("pennylane"),
257
+ loss=SquaredLoss(),
258
+ optimizer=Adam(options={"lr": 0.05}),
259
+ batch_size=5,
260
+ epochs=1,
261
+ shuffle=False,
262
+ parameter_seed=0,
263
+ )
264
+ kwargs.update(overrides)
265
+ return QNNClassifier(**kwargs)
266
+
267
+ @pytest.mark.parametrize(
268
+ "operator",
269
+ [
270
+ [SinglePauli(2, 0, op_str="X")],
271
+ [SinglePauli(2, 0, op_str="X"), SinglePauli(2, 1, op_str="X")],
272
+ ],
273
+ ids=["list_of_1", "list_of_2"],
274
+ )
275
+ def test_opt_param_op_auto_disabled_at_init(self, data, operator):
276
+ """Regression: ``opt_param_op`` auto-flips to ``False`` at construction
277
+ when the observable has no trainable parameters.
278
+
279
+ Otherwise training requests ``dfdop`` and crashes with
280
+ ``ValueError: cannot reshape array of size 0 into shape (k, 1)`` for
281
+ any multi-output QNN (operator passed as a list).
282
+ """
283
+ qnnc = self._make_opt_param_op_qnnc(operator)
284
+ assert qnnc.opt_param_op is False # at __init__, not deferred to fit
285
+ X, y = data
286
+ qnnc.fit(X, y)
287
+ assert qnnc.predict(X).shape == y.shape
288
+
289
+ def test_opt_param_op_left_alone_when_obs_has_params(self, data):
290
+ qnnc = self._make_opt_param_op_qnnc(SummedPaulis(num_qubits=2))
291
+ assert qnnc.opt_param_op is True
292
+ X, y = data
293
+ qnnc.fit(X, y)
294
+ assert qnnc.opt_param_op is True
295
+
296
+ def test_opt_param_op_explicit_false_is_respected(self):
297
+ """Observable has trainable params, but user explicitly opted out:
298
+ auto-correction must only ever flip ``True -> False``, never the
299
+ other direction."""
300
+ qnnc = self._make_opt_param_op_qnnc(SummedPaulis(num_qubits=2), opt_param_op=False)
301
+ assert qnnc.opt_param_op is False
302
+
303
+ def test_opt_param_op_re_evaluates_in_set_params(self):
304
+ """Swap a parameterized observable for one with no params via
305
+ ``set_params``: ``opt_param_op`` must re-evaluate immediately, not
306
+ wait for the next ``fit``."""
307
+ qnnc = self._make_opt_param_op_qnnc(SummedPaulis(num_qubits=2))
308
+ assert qnnc.opt_param_op is True
309
+ qnnc.set_params(operator=[SinglePauli(2, 0, op_str="X")])
310
+ assert qnnc.opt_param_op is False
@@ -8,10 +8,10 @@ from sklearn.datasets import make_regression
8
8
  from sklearn.preprocessing import MinMaxScaler
9
9
 
10
10
  from squlearn import Executor
11
- from squlearn.observables import SummedPaulis
12
- from squlearn.encoding_circuit import ChebyshevRx
11
+ from squlearn.observables import SinglePauli, SummedPaulis
12
+ from squlearn.encoding_circuit import ChebyshevPQC, ChebyshevRx
13
13
  from squlearn.optimizers import SLSQP, Adam
14
- from squlearn.qnn import QNNRegressor, MeanSquaredError
14
+ from squlearn.qnn import QNNRegressor, MeanSquaredError, SquaredLoss
15
15
 
16
16
 
17
17
  class TestQNNRegressor:
@@ -241,3 +241,74 @@ class TestQNNRegressor:
241
241
  assert instance_loaded._is_fitted
242
242
  assert np.allclose(instance_loaded.param, qnn_regressor.param)
243
243
  assert np.allclose(instance_loaded.param_op, qnn_regressor.param_op)
244
+
245
+ def _make_opt_param_op_qnnr(self, operator, **overrides) -> QNNRegressor:
246
+ """QNNRegressor with a parameterless-observable-friendly setup.
247
+
248
+ Used by the ``opt_param_op`` auto-correction regression tests below.
249
+ ``ChebyshevPQC`` carries trainable circuit params (so training would
250
+ request ``dfdp`` and reach the empty-``dfdop`` early-return on the
251
+ PennyLane backend), and ``Adam`` exercises the SGD/``train_mini_batch``
252
+ path where the bug originally surfaced.
253
+ """
254
+ kwargs = dict(
255
+ encoding_circuit=ChebyshevPQC(num_qubits=2, num_features=1, num_layers=2),
256
+ operator=operator,
257
+ executor=Executor("pennylane"),
258
+ loss=SquaredLoss(),
259
+ optimizer=Adam(options={"lr": 0.05}),
260
+ batch_size=3,
261
+ epochs=1,
262
+ shuffle=False,
263
+ parameter_seed=0,
264
+ )
265
+ kwargs.update(overrides)
266
+ return QNNRegressor(**kwargs)
267
+
268
+ @pytest.mark.parametrize(
269
+ "operator",
270
+ [
271
+ [SinglePauli(2, 0, op_str="X")],
272
+ [SinglePauli(2, 0, op_str="X"), SinglePauli(2, 1, op_str="X")],
273
+ ],
274
+ ids=["list_of_1", "list_of_2"],
275
+ )
276
+ def test_opt_param_op_auto_disabled_at_init(self, data, operator):
277
+ """Regression: ``opt_param_op`` auto-flips to ``False`` at construction
278
+ when the observable has no trainable parameters.
279
+
280
+ Otherwise training requests ``dfdop`` and crashes with
281
+ ``ValueError: cannot reshape array of size 0 into shape (k, 1)`` for
282
+ any multi-output QNN (operator passed as a list).
283
+ """
284
+ qnnr = self._make_opt_param_op_qnnr(operator)
285
+ assert qnnr.opt_param_op is False # at __init__, not deferred to fit
286
+ X, y = data
287
+ # Multi-output regression needs y with matching shape; broadcast the
288
+ # 1D target across the observable list so fit doesn't fail upstream.
289
+ y_multi = np.broadcast_to(y[:, None], (y.shape[0], len(operator)))
290
+ qnnr.fit(X, y_multi)
291
+ assert qnnr.predict(X).shape == y_multi.shape
292
+
293
+ def test_opt_param_op_left_alone_when_obs_has_params(self, data):
294
+ qnnr = self._make_opt_param_op_qnnr(SummedPaulis(num_qubits=2))
295
+ assert qnnr.opt_param_op is True
296
+ X, y = data
297
+ qnnr.fit(X, y)
298
+ assert qnnr.opt_param_op is True
299
+
300
+ def test_opt_param_op_explicit_false_is_respected(self):
301
+ """Observable has trainable params, but user explicitly opted out:
302
+ auto-correction must only ever flip ``True -> False``, never the
303
+ other direction."""
304
+ qnnr = self._make_opt_param_op_qnnr(SummedPaulis(num_qubits=2), opt_param_op=False)
305
+ assert qnnr.opt_param_op is False
306
+
307
+ def test_opt_param_op_re_evaluates_in_set_params(self):
308
+ """Swap a parameterized observable for one with no params via
309
+ ``set_params``: ``opt_param_op`` must re-evaluate immediately, not
310
+ wait for the next ``fit``."""
311
+ qnnr = self._make_opt_param_op_qnnr(SummedPaulis(num_qubits=2))
312
+ assert qnnr.opt_param_op is True
313
+ qnnr.set_params(operator=[SinglePauli(2, 0, op_str="X")])
314
+ assert qnnr.opt_param_op is False
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes