qadence 1.11.1__py3-none-any.whl → 1.11.2__py3-none-any.whl
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.
- qadence/backend.py +10 -3
- qadence/backends/agpsr_utils.py +96 -0
- qadence/backends/api.py +8 -1
- qadence/backends/horqrux/backend.py +6 -5
- qadence/backends/horqrux/config.py +17 -1
- qadence/backends/horqrux/convert_ops.py +20 -97
- qadence/backends/{gpsr.py → parameter_shift_rules.py} +48 -30
- qadence/backends/pulser/config.py +18 -0
- qadence/backends/pyqtorch/config.py +18 -0
- qadence/blocks/primitive.py +2 -3
- qadence/engines/torch/differentiable_backend.py +5 -8
- qadence/extensions.py +0 -10
- qadence/ml_tools/callbacks/callbackmanager.py +4 -2
- qadence/ml_tools/constructors.py +264 -4
- qadence/ml_tools/qcnn_model.py +158 -0
- qadence/model.py +19 -1
- qadence/parameters.py +2 -0
- qadence/serialization.py +1 -1
- qadence/types.py +1 -3
- qadence/utils.py +16 -7
- {qadence-1.11.1.dist-info → qadence-1.11.2.dist-info}/METADATA +11 -10
- {qadence-1.11.1.dist-info → qadence-1.11.2.dist-info}/RECORD +24 -22
- qadence-1.11.2.dist-info/licenses/LICENSE +13 -0
- qadence-1.11.1.dist-info/licenses/LICENSE +0 -202
- {qadence-1.11.1.dist-info → qadence-1.11.2.dist-info}/WHEEL +0 -0
@@ -115,8 +115,10 @@ class CallbacksManager:
|
|
115
115
|
self.add_callback("PlotMetrics", "train_end")
|
116
116
|
# only save the last checkpoint if not checkpoint_best_only
|
117
117
|
if not self.config.checkpoint_best_only:
|
118
|
-
self.
|
119
|
-
|
118
|
+
if self.config.checkpoint_every != 0:
|
119
|
+
self.add_callback("SaveCheckpoint", "train_end")
|
120
|
+
if self.config.write_every != 0:
|
121
|
+
self.add_callback("WriteMetrics", "train_end")
|
120
122
|
|
121
123
|
def add_callback(
|
122
124
|
self, callback: str | Callback, on: str | TrainingStage, called_every: int = 1
|
qadence/ml_tools/constructors.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from typing import Callable
|
3
|
+
from typing import Any, Callable
|
4
4
|
import numpy as np
|
5
5
|
from sympy import Basic
|
6
6
|
|
@@ -8,7 +8,8 @@ from qadence.backend import BackendConfiguration
|
|
8
8
|
from qadence.blocks import chain, kron
|
9
9
|
from qadence.blocks.abstract import AbstractBlock
|
10
10
|
from qadence.blocks.composite import ChainBlock, KronBlock
|
11
|
-
from qadence.blocks.utils import
|
11
|
+
from qadence.blocks.utils import tag, add
|
12
|
+
from qadence.parameters import Parameter
|
12
13
|
from qadence.circuit import QuantumCircuit
|
13
14
|
from qadence.constructors import (
|
14
15
|
analog_feature_map,
|
@@ -24,7 +25,7 @@ from qadence.constructors.hea import hea_digital, hea_sDAQC
|
|
24
25
|
from qadence.constructors.iia import iia
|
25
26
|
from qadence.measurements import Measurements
|
26
27
|
from qadence.noise import NoiseHandler
|
27
|
-
from qadence.operations import CNOT, RX, RY,
|
28
|
+
from qadence.operations import CNOT, RX, RY, RZ, I
|
28
29
|
from qadence.register import Register
|
29
30
|
from qadence.types import (
|
30
31
|
AnsatzType,
|
@@ -733,7 +734,6 @@ def create_observable(
|
|
733
734
|
interaction=config.interaction,
|
734
735
|
detuning=config.detuning,
|
735
736
|
)
|
736
|
-
|
737
737
|
obs: AbstractBlock = add(shifting_term, detuning_hamiltonian)
|
738
738
|
|
739
739
|
if isinstance(config.tag, str):
|
@@ -801,6 +801,7 @@ def build_qnn_from_configs(
|
|
801
801
|
if isinstance(observable_config, list)
|
802
802
|
else create_observable(register=register, config=observable_config)
|
803
803
|
)
|
804
|
+
|
804
805
|
ufa = QNN(
|
805
806
|
circ,
|
806
807
|
observable,
|
@@ -814,3 +815,262 @@ def build_qnn_from_configs(
|
|
814
815
|
)
|
815
816
|
|
816
817
|
return ufa
|
818
|
+
|
819
|
+
|
820
|
+
def _create_feature_map_qcnn(
|
821
|
+
n_qubits: int,
|
822
|
+
n_inputs: int,
|
823
|
+
fm_type: str = "Fourier",
|
824
|
+
op: Any = RX,
|
825
|
+
) -> Any:
|
826
|
+
"""
|
827
|
+
Creates a feature map (FM) by dividing qubits among inputs and applying.
|
828
|
+
|
829
|
+
the specified feature map type.
|
830
|
+
|
831
|
+
Args:
|
832
|
+
n_qubits (int): Total number of qubits.
|
833
|
+
n_inputs (int): Number of inputs.
|
834
|
+
fm_type (str): Type of feature map to use (e.g., "Fourier").
|
835
|
+
op (Any): Quantum operation to use in the feature map (e.g., RX).
|
836
|
+
|
837
|
+
Returns:
|
838
|
+
Any: The combined feature map as a kronecker product
|
839
|
+
of individual feature maps.
|
840
|
+
"""
|
841
|
+
fm_temp = []
|
842
|
+
qubits_per_input = n_qubits // n_inputs # Base number of qubits per input
|
843
|
+
exceeding_qubits = n_qubits % n_inputs # Number of exceeding qubits
|
844
|
+
start = 0 # Track current qubit index
|
845
|
+
|
846
|
+
for i in range(n_inputs):
|
847
|
+
# Assign base qubits + 1 extra if input has exceeding qubits
|
848
|
+
num_qubits = qubits_per_input + 1 if i < exceeding_qubits else qubits_per_input
|
849
|
+
end = start + num_qubits
|
850
|
+
|
851
|
+
# Create FM for this input
|
852
|
+
fm_temp.append(
|
853
|
+
feature_map(
|
854
|
+
n_qubits=num_qubits,
|
855
|
+
param=f"\u03C6_{i}", # Use phi_i as the parameter
|
856
|
+
op=op,
|
857
|
+
fm_type=fm_type,
|
858
|
+
support=tuple(range(start, end)),
|
859
|
+
)
|
860
|
+
)
|
861
|
+
start = end # Update starting index for next FM
|
862
|
+
|
863
|
+
# Combine all feature maps using kronecker product
|
864
|
+
return kron(*fm_temp)
|
865
|
+
|
866
|
+
|
867
|
+
def _get_block_params(
|
868
|
+
params: dict,
|
869
|
+
layer: int,
|
870
|
+
rep: int,
|
871
|
+
pos: int,
|
872
|
+
is_corr: bool = False,
|
873
|
+
) -> Any:
|
874
|
+
"""
|
875
|
+
Retrieves the parameter for a given operation.
|
876
|
+
|
877
|
+
Args:
|
878
|
+
params (dict): Dictionary to store and retrieve parameters.
|
879
|
+
layer (int): The index of the current layer.
|
880
|
+
rep (int): The index of the current repetition in the layer.
|
881
|
+
pos (int): Position of the qubit in the layer.
|
882
|
+
is_corr (bool): If True, uses correlated parameters for corresponding gates in W^opt_ij.
|
883
|
+
|
884
|
+
Returns:
|
885
|
+
Parameter: the retrieved parameter.
|
886
|
+
"""
|
887
|
+
if is_corr:
|
888
|
+
# Cycle pos from 0 to 8
|
889
|
+
key = f"θ_{layer}_{pos % 9}"
|
890
|
+
else:
|
891
|
+
key = f"θ_{layer}_{rep}_{pos}"
|
892
|
+
|
893
|
+
if key not in params:
|
894
|
+
params[key] = Parameter(key)
|
895
|
+
return params[key]
|
896
|
+
|
897
|
+
|
898
|
+
def _create_single_W(
|
899
|
+
params: dict,
|
900
|
+
operations: list[Any],
|
901
|
+
entangler: Any,
|
902
|
+
layer: int,
|
903
|
+
rep: int,
|
904
|
+
max_reps: int,
|
905
|
+
control: int,
|
906
|
+
target: int,
|
907
|
+
spacing: int,
|
908
|
+
n_qubits: int,
|
909
|
+
is_corr: bool = False,
|
910
|
+
) -> ChainBlock:
|
911
|
+
"""Creates a single convolutional cell W_ij."""
|
912
|
+
pad = [
|
913
|
+
I(q)
|
914
|
+
for q in range(control - spacing, control + spacing + 1)
|
915
|
+
if q != control and q != target and 0 <= q < n_qubits
|
916
|
+
]
|
917
|
+
gates = []
|
918
|
+
|
919
|
+
# Track per-layer repetition index for proper parameter continuity
|
920
|
+
key_param_counter = f"param_index_{layer}_{rep}"
|
921
|
+
if key_param_counter not in params:
|
922
|
+
params[key_param_counter] = 0 # Initialize if first time
|
923
|
+
|
924
|
+
param_index = params[key_param_counter] # Load index
|
925
|
+
single_params = {} # Store params for single RZ/RY gates
|
926
|
+
|
927
|
+
# Apply the first sequence of operations
|
928
|
+
for _, op in enumerate(operations):
|
929
|
+
param_control = _get_block_params(params, layer, rep, param_index, is_corr)
|
930
|
+
param_index += 1
|
931
|
+
param_target = _get_block_params(params, layer, rep, param_index, is_corr)
|
932
|
+
param_index += 1
|
933
|
+
gates.append(
|
934
|
+
kron(
|
935
|
+
*pad,
|
936
|
+
op(control, param_control),
|
937
|
+
op(target, param_target),
|
938
|
+
)
|
939
|
+
)
|
940
|
+
# entangling gate
|
941
|
+
gates.append(entangler(target, control))
|
942
|
+
|
943
|
+
# Apply RZ, RY and entangling gates for intermediate step
|
944
|
+
single_params["control_rz"] = _get_block_params(params, layer, rep, param_index, is_corr)
|
945
|
+
param_index += 1
|
946
|
+
single_params["target_ry"] = _get_block_params(params, layer, rep, param_index, is_corr)
|
947
|
+
param_index += 1
|
948
|
+
gates.append(
|
949
|
+
kron(
|
950
|
+
*pad,
|
951
|
+
RZ(control, single_params["control_rz"]),
|
952
|
+
RY(target, single_params["target_ry"]),
|
953
|
+
)
|
954
|
+
)
|
955
|
+
# entangling gate
|
956
|
+
gates.append(entangler(control, target))
|
957
|
+
|
958
|
+
intermediate_ry = _get_block_params(params, layer, rep, param_index, is_corr)
|
959
|
+
param_index += 1
|
960
|
+
gates.append(
|
961
|
+
kron(
|
962
|
+
*pad,
|
963
|
+
I(control),
|
964
|
+
RY(target, intermediate_ry),
|
965
|
+
)
|
966
|
+
)
|
967
|
+
# entangling gate
|
968
|
+
gates.append(entangler(target, control))
|
969
|
+
|
970
|
+
# Apply the first sequence of operations
|
971
|
+
for _, op in enumerate(operations):
|
972
|
+
param_control = _get_block_params(params, layer, rep, param_index, is_corr)
|
973
|
+
param_index += 1
|
974
|
+
param_target = _get_block_params(params, layer, rep, param_index, is_corr)
|
975
|
+
param_index += 1
|
976
|
+
gates.append(
|
977
|
+
kron(
|
978
|
+
*pad,
|
979
|
+
op(control, param_control),
|
980
|
+
op(target, param_target),
|
981
|
+
)
|
982
|
+
)
|
983
|
+
# Add final entangling gate (control -> target)
|
984
|
+
if rep == int(max_reps - 1):
|
985
|
+
gates.append(entangler(control, target))
|
986
|
+
|
987
|
+
# Update params dict with the last used index
|
988
|
+
params[key_param_counter] = param_index
|
989
|
+
|
990
|
+
return chain(*gates)
|
991
|
+
|
992
|
+
|
993
|
+
def _create_conv_layer(
|
994
|
+
layer_index: int,
|
995
|
+
max_reps: int,
|
996
|
+
current_indices: list[int],
|
997
|
+
params: dict,
|
998
|
+
operations: list[Any],
|
999
|
+
entangler: Any,
|
1000
|
+
n_qubits: int,
|
1001
|
+
is_corr: bool,
|
1002
|
+
) -> tuple[AbstractBlock, list[int]]:
|
1003
|
+
"""
|
1004
|
+
Function to create a single convolutional layer.
|
1005
|
+
|
1006
|
+
Args:
|
1007
|
+
layer_index (int): The index of the current layer.
|
1008
|
+
reps (int): Number of repetitions for this layer.
|
1009
|
+
current_indices (List[int]): Indices of qubits for the current layer.
|
1010
|
+
params (dict): Dictionary to store and retrieve parameters.
|
1011
|
+
operations (List[Any]): List of quantum operations to apply in the gates.
|
1012
|
+
entangler (Any): Entangling operation, such as CZ.
|
1013
|
+
n_qubits (int): Total number of qubits.
|
1014
|
+
|
1015
|
+
Returns:
|
1016
|
+
Tuple[AbstractBlock, List[int]]: A tuple containing the quantum block
|
1017
|
+
for the layer and the target indices for the next layer.
|
1018
|
+
"""
|
1019
|
+
current_layer = []
|
1020
|
+
next_indices = []
|
1021
|
+
spacing = layer_index
|
1022
|
+
|
1023
|
+
if layer_index in [0, 1]: # Special behavior for first two layers
|
1024
|
+
layer_reps = []
|
1025
|
+
for rep in range(max_reps):
|
1026
|
+
rep_kron = []
|
1027
|
+
# Define qubit pairs based on odd/even repetition
|
1028
|
+
if rep % 2 == 0: # Even d: regular behavior
|
1029
|
+
pairs = zip(current_indices[::2], current_indices[1::2])
|
1030
|
+
else: # Odd d: shift downward, leaving qubits 0 and 7 free
|
1031
|
+
pairs = zip(current_indices[1:-1:2], current_indices[2:-1:2])
|
1032
|
+
|
1033
|
+
# Build the gate sequence for each pair
|
1034
|
+
for control, target in pairs:
|
1035
|
+
W_pairs = _create_single_W(
|
1036
|
+
params,
|
1037
|
+
operations,
|
1038
|
+
entangler,
|
1039
|
+
layer_index,
|
1040
|
+
rep,
|
1041
|
+
max_reps,
|
1042
|
+
control,
|
1043
|
+
target,
|
1044
|
+
spacing,
|
1045
|
+
n_qubits,
|
1046
|
+
is_corr,
|
1047
|
+
)
|
1048
|
+
tag(W_pairs, f"W{control,target}")
|
1049
|
+
rep_kron.append(W_pairs)
|
1050
|
+
|
1051
|
+
layer_reps.append(kron(*rep_kron))
|
1052
|
+
|
1053
|
+
# Combine all repetitions using `chain`
|
1054
|
+
current_layer.append(chain(*layer_reps))
|
1055
|
+
|
1056
|
+
else: # Original behavior for other layers
|
1057
|
+
for rep in range(max_reps):
|
1058
|
+
for control, target in zip(current_indices[::2], current_indices[1::2]):
|
1059
|
+
W_pairs = _create_single_W(
|
1060
|
+
params,
|
1061
|
+
operations,
|
1062
|
+
entangler,
|
1063
|
+
layer_index,
|
1064
|
+
rep,
|
1065
|
+
max_reps,
|
1066
|
+
control,
|
1067
|
+
target,
|
1068
|
+
spacing,
|
1069
|
+
n_qubits,
|
1070
|
+
is_corr,
|
1071
|
+
)
|
1072
|
+
current_layer.append(W_pairs)
|
1073
|
+
|
1074
|
+
# Update `next_indices` with the **targets** of the current layer
|
1075
|
+
next_indices = current_indices[1::2]
|
1076
|
+
return chain(*current_layer), next_indices
|
@@ -0,0 +1,158 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import Any, Callable
|
4
|
+
from qadence.blocks import chain
|
5
|
+
from qadence.parameters import Parameter
|
6
|
+
from qadence.blocks.utils import add, tag
|
7
|
+
from qadence.operations import Z, RX, CZ
|
8
|
+
from qadence.circuit import QuantumCircuit
|
9
|
+
from qadence.types import BackendName, DiffMode
|
10
|
+
from qadence.blocks.abstract import AbstractBlock
|
11
|
+
|
12
|
+
from .models import QNN
|
13
|
+
from qadence.ml_tools.constructors import _create_conv_layer, _create_feature_map_qcnn
|
14
|
+
|
15
|
+
|
16
|
+
class QCNN(QNN):
|
17
|
+
def __init__(
|
18
|
+
self,
|
19
|
+
n_inputs: int,
|
20
|
+
n_qubits: int,
|
21
|
+
depth: list[int],
|
22
|
+
operations: list[Any],
|
23
|
+
entangler: Any = CZ,
|
24
|
+
random_meas: bool = True,
|
25
|
+
fm_basis: str = "Fourier",
|
26
|
+
fm_gate: Any = RX,
|
27
|
+
is_corr: bool = False,
|
28
|
+
**kwargs: Any,
|
29
|
+
) -> None:
|
30
|
+
"""
|
31
|
+
Creates a QCNN model.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
n_inputs (int): Number of input features.
|
35
|
+
n_qubits (int): Total number of qubits.
|
36
|
+
depth (list[int]): List defining the depth (repetitions) of each layer.
|
37
|
+
operations (list[Any]): List of quantum operations to apply
|
38
|
+
in the gates (e.g., [RX, RZ]).
|
39
|
+
entangler (Any): Entangling operation, such as CZ.
|
40
|
+
random_meas (bool): If True, applies random weighted measurements.
|
41
|
+
fm_basis (str): feature map basis.
|
42
|
+
fm_gate (Any): gate employed in the fm, such as.
|
43
|
+
**kwargs (Any): Additional keyword arguments for the parent QNN class.
|
44
|
+
"""
|
45
|
+
self.n_inputs = n_inputs
|
46
|
+
self.n_qubits = n_qubits
|
47
|
+
self.depth = depth
|
48
|
+
self.operations = operations
|
49
|
+
self.entangler = entangler
|
50
|
+
self.random_meas = random_meas
|
51
|
+
self.fm_basis = fm_basis
|
52
|
+
self.fm_gate = fm_gate
|
53
|
+
self.is_corr = is_corr
|
54
|
+
|
55
|
+
circuit = self.qcnn_circuit(
|
56
|
+
self.n_inputs,
|
57
|
+
self.n_qubits,
|
58
|
+
self.depth,
|
59
|
+
self.operations,
|
60
|
+
self.entangler,
|
61
|
+
self.fm_basis,
|
62
|
+
self.fm_gate,
|
63
|
+
self.is_corr,
|
64
|
+
)
|
65
|
+
|
66
|
+
obs = self.qcnn_deferred_obs(self.n_qubits, self.random_meas)
|
67
|
+
|
68
|
+
super().__init__(
|
69
|
+
circuit=circuit,
|
70
|
+
observable=obs,
|
71
|
+
backend=BackendName.PYQTORCH,
|
72
|
+
diff_mode=DiffMode.AD,
|
73
|
+
inputs=[f"\u03C6_{i}" for i in range(self.n_inputs)],
|
74
|
+
**kwargs,
|
75
|
+
)
|
76
|
+
|
77
|
+
def qcnn_circuit(
|
78
|
+
self,
|
79
|
+
n_inputs: int,
|
80
|
+
n_qubits: int,
|
81
|
+
depth: list[int],
|
82
|
+
operations: list[Any],
|
83
|
+
entangler: AbstractBlock,
|
84
|
+
fm_basis: str,
|
85
|
+
fm_gate: AbstractBlock,
|
86
|
+
is_corr: bool,
|
87
|
+
) -> QuantumCircuit:
|
88
|
+
"""Defines the QCNN circuit."""
|
89
|
+
# Validate qubit count
|
90
|
+
if n_qubits < 4:
|
91
|
+
raise ValueError(
|
92
|
+
f"Invalid number of qubits: {n_qubits}. " "At least 4 qubits are required."
|
93
|
+
)
|
94
|
+
if n_qubits % 2 != 0:
|
95
|
+
raise ValueError(
|
96
|
+
f"Invalid number of qubits: {n_qubits}. " "The number of qubits must be even."
|
97
|
+
)
|
98
|
+
|
99
|
+
# Validate that all values in `depth` are odd
|
100
|
+
even_depths = [d for d in depth if d % 2 == 0]
|
101
|
+
if even_depths:
|
102
|
+
raise ValueError(
|
103
|
+
f"Invalid depth values: '{even_depths[0]}'. " "All the conv layer 'r's must be odd."
|
104
|
+
)
|
105
|
+
|
106
|
+
# Feature map (FM)
|
107
|
+
fm = _create_feature_map_qcnn(n_qubits, n_inputs, fm_basis, fm_gate)
|
108
|
+
tag(fm, "FM")
|
109
|
+
|
110
|
+
# Conv and Pool layer definition
|
111
|
+
conv_layers = []
|
112
|
+
params: dict[str, Parameter] = {}
|
113
|
+
|
114
|
+
# Define layer all the 2-qubit patterns based on depth
|
115
|
+
layer_patterns = [(2**layer_index, depth[layer_index]) for layer_index in range(len(depth))]
|
116
|
+
|
117
|
+
# Initialize all qubits for the current layer
|
118
|
+
current_indices = list(range(n_qubits))
|
119
|
+
|
120
|
+
# Build the circuit layer by layer using the helper
|
121
|
+
for layer_index, (_, reps) in enumerate(layer_patterns):
|
122
|
+
if reps == 0:
|
123
|
+
raise ValueError(f"Invalid layer {layer_index}: zero repetitions (reps = {reps}).")
|
124
|
+
if len(current_indices) < 2:
|
125
|
+
raise RuntimeError(
|
126
|
+
f"Layer {layer_index} requires at least 2 qubits, "
|
127
|
+
f"but found {len(current_indices)}."
|
128
|
+
)
|
129
|
+
|
130
|
+
layer_block, next_indices = _create_conv_layer(
|
131
|
+
layer_index, reps, current_indices, params, operations, entangler, n_qubits, is_corr
|
132
|
+
)
|
133
|
+
tag(layer_block, f"C+P layer {layer_index}")
|
134
|
+
conv_layers.append(layer_block)
|
135
|
+
|
136
|
+
# Update `current_indices` for the next layer
|
137
|
+
current_indices = next_indices
|
138
|
+
|
139
|
+
# Combine all layers for the final ansatz
|
140
|
+
ansatz = chain(*conv_layers)
|
141
|
+
|
142
|
+
return QuantumCircuit(n_qubits, fm, ansatz)
|
143
|
+
|
144
|
+
def qcnn_deferred_obs(
|
145
|
+
self, n_qubits: int, random_meas: bool
|
146
|
+
) -> AbstractBlock | list[AbstractBlock]:
|
147
|
+
"""
|
148
|
+
Defines the measurements to be performedthe traced out.
|
149
|
+
|
150
|
+
and remaining qubits.
|
151
|
+
"""
|
152
|
+
if random_meas:
|
153
|
+
w1 = [Parameter(f"w{i}") for i in range(n_qubits)]
|
154
|
+
obs = add(Z(i) * w for i, w in zip(range(n_qubits), w1))
|
155
|
+
else:
|
156
|
+
obs = add(Z(i) for i in range(n_qubits))
|
157
|
+
|
158
|
+
return obs
|
qadence/model.py
CHANGED
@@ -154,6 +154,11 @@ class QuantumModel(nn.Module):
|
|
154
154
|
"""Variational parameters."""
|
155
155
|
return OrderedDict({k: v.data for k, v in self._params.items() if v.requires_grad})
|
156
156
|
|
157
|
+
@property
|
158
|
+
def params(self) -> OrderedDict:
|
159
|
+
"""All parameters."""
|
160
|
+
return OrderedDict({k: v.data for k, v in self._params.items()})
|
161
|
+
|
157
162
|
@property
|
158
163
|
def vals_vparams(self) -> Tensor:
|
159
164
|
"""Dictionary with parameters which are actually updated during optimization."""
|
@@ -176,6 +181,19 @@ class QuantumModel(nn.Module):
|
|
176
181
|
"""The number of variational parameters."""
|
177
182
|
return len(self.vals_vparams)
|
178
183
|
|
184
|
+
@property
|
185
|
+
def show_config(self) -> str:
|
186
|
+
"""Attain current quantum model configurations."""
|
187
|
+
if isinstance(self.backend, DifferentiableBackend):
|
188
|
+
current_config = self.backend.backend.config
|
189
|
+
return BackendConfiguration.available_options(current_config)
|
190
|
+
|
191
|
+
def change_config(self, new_config: dict) -> None:
|
192
|
+
"""Change configuration with the input."""
|
193
|
+
if isinstance(self.backend, DifferentiableBackend):
|
194
|
+
current_config = self.backend.backend.config
|
195
|
+
BackendConfiguration.change_config(current_config, new_config)
|
196
|
+
|
179
197
|
def circuit(self, circuit: QuantumCircuit) -> ConvertedCircuit:
|
180
198
|
"""Get backend-converted circuit.
|
181
199
|
|
@@ -520,7 +538,7 @@ class QuantumModel(nn.Module):
|
|
520
538
|
file_path = file_path / get_latest_checkpoint_name(file_path, "model")
|
521
539
|
|
522
540
|
try:
|
523
|
-
qm_pt = torch.load(file_path, map_location=map_location)
|
541
|
+
qm_pt = torch.load(file_path, map_location=map_location, weights_only=False)
|
524
542
|
except Exception as e:
|
525
543
|
logger.error(f"Unable to load QuantumModel due to {e}")
|
526
544
|
return cls._from_dict(qm_pt, as_torch)
|
qadence/parameters.py
CHANGED
qadence/serialization.py
CHANGED
@@ -226,7 +226,7 @@ def save_json(d: dict, file_path: str | Path) -> None:
|
|
226
226
|
|
227
227
|
|
228
228
|
def load_pt(file_path: str | Path, map_location: str) -> Any:
|
229
|
-
return torch.load(file_path, map_location=map_location)
|
229
|
+
return torch.load(file_path, map_location=map_location, weights_only=False)
|
230
230
|
|
231
231
|
|
232
232
|
def load_json(file_path: str | Path, map_location: str) -> Any:
|
qadence/types.py
CHANGED
@@ -180,7 +180,7 @@ class AnsatzType(StrEnum):
|
|
180
180
|
"""Alternating Layer Ansatz."""
|
181
181
|
|
182
182
|
|
183
|
-
class
|
183
|
+
class DiffMode(StrEnum):
|
184
184
|
"""Differentiation modes to choose from."""
|
185
185
|
|
186
186
|
GPSR = "gpsr"
|
@@ -246,11 +246,9 @@ class _Engine(StrEnum):
|
|
246
246
|
try:
|
247
247
|
module = importlib.import_module("qadence_extensions.types")
|
248
248
|
BackendName = getattr(module, "BackendName")
|
249
|
-
DiffMode = getattr(module, "DiffMode")
|
250
249
|
Engine = getattr(module, "Engine")
|
251
250
|
except ModuleNotFoundError:
|
252
251
|
BackendName = _BackendName
|
253
|
-
DiffMode = _DiffMode
|
254
252
|
Engine = _Engine
|
255
253
|
|
256
254
|
|
qadence/utils.py
CHANGED
@@ -318,14 +318,23 @@ def block_to_mathematical_expression(block: Tree | AbstractBlock) -> str:
|
|
318
318
|
[block_to_mathematical_expression(block_child) for block_child in block_tree.children]
|
319
319
|
)
|
320
320
|
if "mul" in block_title:
|
321
|
-
block_title = re.findall("\
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
321
|
+
block_title = re.findall("\[mul:\s*(.+?)\]", block_title)[0]
|
322
|
+
|
323
|
+
try:
|
324
|
+
if "." in block_title:
|
325
|
+
coeff = float(block_title)
|
326
|
+
else:
|
327
|
+
coeff = int(block_title)
|
328
|
+
if coeff == 0:
|
329
|
+
block_title = ""
|
330
|
+
elif coeff == 1:
|
331
|
+
block_title = block_to_mathematical_expression(block_tree.children[0])
|
332
|
+
else:
|
333
|
+
block_title += " * " + block_to_mathematical_expression(block_tree.children[0])
|
334
|
+
|
335
|
+
except ValueError: # In case block_title is a non-numeric str (e.g. parameter name)
|
328
336
|
block_title += " * " + block_to_mathematical_expression(block_tree.children[0])
|
337
|
+
|
329
338
|
first_part = block_title[:3]
|
330
339
|
if first_part in [" + ", " ⊗ ", " * "]:
|
331
340
|
block_title = block_title[3:]
|
@@ -1,17 +1,18 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qadence
|
3
|
-
Version: 1.11.
|
3
|
+
Version: 1.11.2
|
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>, Pim Venderbosch <pim.venderbosch@pasqal.com>, Manu Lahariya <manu.lahariya@pasqal.com>
|
6
|
-
License:
|
6
|
+
License: PASQAL OPEN-SOURCE SOFTWARE LICENSE (MIT-derived)
|
7
7
|
License-File: LICENSE
|
8
|
-
Classifier: License ::
|
8
|
+
Classifier: License :: Other/Proprietary License
|
9
9
|
Classifier: Programming Language :: Python
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
11
11
|
Classifier: Programming Language :: Python :: 3.9
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
15
16
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
16
17
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
17
18
|
Requires-Python: >=3.9
|
@@ -23,11 +24,11 @@ Requires-Dist: nevergrad
|
|
23
24
|
Requires-Dist: numpy
|
24
25
|
Requires-Dist: openfermion
|
25
26
|
Requires-Dist: pasqal-cloud
|
26
|
-
Requires-Dist: pyqtorch==1.7.
|
27
|
+
Requires-Dist: pyqtorch==1.7.5
|
27
28
|
Requires-Dist: pyyaml
|
28
29
|
Requires-Dist: rich
|
29
30
|
Requires-Dist: scipy
|
30
|
-
Requires-Dist: sympy<1.13
|
31
|
+
Requires-Dist: sympy<1.13.4
|
31
32
|
Requires-Dist: sympytorch>=0.1.2
|
32
33
|
Requires-Dist: tensorboard>=2.12.0
|
33
34
|
Requires-Dist: torch
|
@@ -43,7 +44,7 @@ Requires-Dist: nvidia-pyindex; extra == 'dlprof'
|
|
43
44
|
Provides-Extra: horqrux
|
44
45
|
Requires-Dist: einops; extra == 'horqrux'
|
45
46
|
Requires-Dist: flax; extra == 'horqrux'
|
46
|
-
Requires-Dist: horqrux==0.
|
47
|
+
Requires-Dist: horqrux==0.8.0; extra == 'horqrux'
|
47
48
|
Requires-Dist: jax; extra == 'horqrux'
|
48
49
|
Requires-Dist: jaxopt; extra == 'horqrux'
|
49
50
|
Requires-Dist: optax; extra == 'horqrux'
|
@@ -56,8 +57,8 @@ Provides-Extra: protocols
|
|
56
57
|
Requires-Dist: qadence-protocols; extra == 'protocols'
|
57
58
|
Provides-Extra: pulser
|
58
59
|
Requires-Dist: pasqal-cloud==0.20.2; extra == 'pulser'
|
59
|
-
Requires-Dist: pulser-core==1.
|
60
|
-
Requires-Dist: pulser-simulation==1.
|
60
|
+
Requires-Dist: pulser-core==1.4.0; extra == 'pulser'
|
61
|
+
Requires-Dist: pulser-simulation==1.4.0; extra == 'pulser'
|
61
62
|
Provides-Extra: visualization
|
62
63
|
Requires-Dist: graphviz; extra == 'visualization'
|
63
64
|
Description-Content-Type: text/markdown
|
@@ -84,7 +85,7 @@ programs** with tunable qubit interactions and arbitrary register topologies rea
|
|
84
85
|
[](https://github.com/pasqal-io/qadence/actions/workflows/test_fast.yml)
|
85
86
|
[](https://pasqal-io.github.io/qadence/latest)
|
86
87
|
[](https://pypi.org/project/qadence/)
|
87
|
-
[](https://opensource.org/licenses/MIT)
|
88
89
|

|
89
90
|
|
90
91
|
|
@@ -215,4 +216,4 @@ doi = {10.1109/MS.2025.3536607}
|
|
215
216
|
```
|
216
217
|
|
217
218
|
## License
|
218
|
-
Qadence is a free and open source software package, released under the
|
219
|
+
Qadence is a free and open source software package, released under the PASQAL OPEN-SOURCE SOFTWARE LICENSE (MIT-derived).
|