Constructors for common quantum circuits
exp_fourier_feature_map(n_qubits, support=None, param='x', feature_range=None)
Exponential fourier feature map.
PARAMETER | DESCRIPTION |
---|---|
n_qubits |
number of qubits in the feature
TYPE:
|
support |
qubit support
TYPE:
|
param |
name of feature
TYPE:
|
feature_range |
min and max value of the feature, as floats in a Tuple
TYPE:
|
Source code in qadence/constructors/feature_maps.py
feature_map(n_qubits, support=None, param='phi', op=RX, fm_type=BasisSet.FOURIER, reupload_scaling=ReuploadScaling.CONSTANT, feature_range=None, target_range=None, multiplier=None, param_prefix=None)
Construct a feature map of a given type.
PARAMETER | DESCRIPTION |
---|---|
n_qubits |
Number of qubits the feature map covers. Results in
TYPE:
|
support |
Puts one feature-encoding rotation gate on every qubit in
TYPE:
|
param |
Parameter of the feature map; you can pass a string or Parameter; it will be set as non-trainable (FeatureParameter) regardless.
TYPE:
|
op |
Rotation operation of the feature map; choose from RX, RY, RZ or PHASE.
TYPE:
|
fm_type |
Basis set for data encoding; choose from |
reupload_scaling |
how the feature map scales the data that is re-uploaded for each qubit.
choose from
TYPE:
|
feature_range |
range of data that the input data provided comes from. Used to map input data to the correct domain of the feature-encoding function.
TYPE:
|
target_range |
range of data the data encoder assumes as the natural range. For example, in Chebyshev polynomials it is (-1, 1), while for Fourier it may be chosen as (0, 2*PI). Used to map data to the correct domain of the feature-encoding function.
TYPE:
|
multiplier |
overall multiplier; this is useful for reuploading the feature map serially with different scalings; can be a number or parameter/expression.
TYPE:
|
param_prefix |
string prefix to create trainable parameters multiplying the feature parameter inside the feature-encoding function. Note that currently this does not take into account the domain of the feature-encoding function.
TYPE:
|
Example:
from qadence import feature_map, BasisSet, ReuploadScaling
fm = feature_map(3, fm_type=BasisSet.FOURIER)
print(f"{fm = }")
fm = feature_map(3, fm_type=BasisSet.CHEBYSHEV)
print(f"{fm = }")
fm = feature_map(3, fm_type=BasisSet.FOURIER, reupload_scaling = ReuploadScaling.TOWER)
print(f"{fm = }")
fm = KronBlock(0,1,2) [tag: Constant Fourier FM]
├── RX(0) [params: ['phi']]
├── RX(1) [params: ['phi']]
└── RX(2) [params: ['phi']]
fm = KronBlock(0,1,2) [tag: Constant Chebyshev FM]
├── RX(0) [params: ['acos(phi)']]
├── RX(1) [params: ['acos(phi)']]
└── RX(2) [params: ['acos(phi)']]
fm = KronBlock(0,1,2) [tag: Tower Fourier FM]
├── RX(0) [params: ['1_0*phi']]
├── RX(1) [params: ['2_0*phi']]
└── RX(2) [params: ['3_0*phi']]
Source code in qadence/constructors/feature_maps.py
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
|
hea(n_qubits, depth=1, param_prefix='theta', support=None, strategy=Strategy.DIGITAL, **strategy_args)
Factory function for the Hardware Efficient Ansatz (HEA).
PARAMETER | DESCRIPTION |
---|---|
n_qubits |
number of qubits in the block
TYPE:
|
depth |
number of layers of the HEA
TYPE:
|
param_prefix |
the base name of the variational parameters
TYPE:
|
support |
qubit indexes where the HEA is applied
TYPE:
|
strategy |
Strategy.Digital or Strategy.DigitalAnalog |
**strategy_args |
see below
TYPE:
|
PARAMETER | DESCRIPTION |
---|---|
operations |
list of operations to cycle through in the digital single-qubit rotations of each layer. Valid for Digital and DigitalAnalog HEA.
TYPE:
|
periodic |
if the qubits should be linked periodically. periodic=False is not supported in emu-c. Valid for only for Digital HEA.
TYPE:
|
entangler |
TYPE:
|
Examples:
from qadence import RZ, RX
from qadence import hea
# create the circuit
n_qubits, depth = 2, 4
ansatz = hea(
n_qubits=n_qubits,
depth=depth,
strategy="sDAQC",
operations=[RZ,RX,RZ]
)
Source code in qadence/constructors/ansatze.py
hea_digital(n_qubits, depth=1, param_prefix='theta', periodic=False, operations=[RX, RY, RX], support=None, entangler=CNOT)
Construct the Digital Hardware Efficient Ansatz (HEA).
PARAMETER | DESCRIPTION |
---|---|
n_qubits |
number of qubits in the block.
TYPE:
|
depth |
number of layers of the HEA.
TYPE:
|
param_prefix |
the base name of the variational parameters
TYPE:
|
periodic |
if the qubits should be linked periodically. periodic=False is not supported in emu-c.
TYPE:
|
operations |
list of operations to cycle through in the digital single-qubit rotations of each layer. |
support |
qubit indexes where the HEA is applied.
TYPE:
|
entangler |
2-qubit entangling operation. Supports CNOT, CZ, CRX, CRY, CRZ. Controlld rotations will have variational parameters on the rotation angles.
TYPE:
|
Source code in qadence/constructors/ansatze.py
hea_sDAQC(n_qubits, depth=1, param_prefix='theta', operations=[RX, RY, RX], support=None, entangler=None)
Construct the Hardware Efficient Ansatz (HEA) with analog entangling layers.
It uses step-wise digital-analog computation.
PARAMETER | DESCRIPTION |
---|---|
n_qubits |
number of qubits in the block.
TYPE:
|
depth |
number of layers of the HEA.
TYPE:
|
param_prefix |
the base name of the variational parameters
TYPE:
|
operations |
list of operations to cycle through in the digital single-qubit rotations of each layer. |
support |
qubit indexes where the HEA is applied.
TYPE:
|
entangler |
Hamiltonian generator for the analog entangling layer. Defaults to global ZZ Hamiltonian. Time parameter is considered variational.
TYPE:
|
Source code in qadence/constructors/ansatze.py
ObservableConfig(detuning, scale=1.0, shift=0.0, transformation_type=ObservableTransform.NONE, trainable_transform=None)
dataclass
detuning: TDetuning
instance-attribute
Single qubit detuning of the observable Hamiltonian.
Accepts single-qubit operator N, X, Y, or Z.
scale: TParameter = 1.0
class-attribute
instance-attribute
The scale by which to multiply the output of the observable.
shift: TParameter = 0.0
class-attribute
instance-attribute
The shift to add to the output of the observable.
trainable_transform: bool | None = None
class-attribute
instance-attribute
Whether to have a trainable transformation on the output of the observable.
If None, the scale and shift are numbers. If True, the scale and shift are VariationalParameter. If False, the scale and shift are FeatureParameter.
transformation_type: ObservableTransform = ObservableTransform.NONE
class-attribute
instance-attribute
The type of transformation.
hamiltonian_factory(register, interaction=None, detuning=None, interaction_strength=None, detuning_strength=None, random_strength=False, use_all_node_pairs=False)
General Hamiltonian creation function.
Can be used to create Hamiltonians with 2-qubit interactions and single-qubit detunings, both with arbitrary strength or parameterized.
PARAMETER | DESCRIPTION |
---|---|
register |
register of qubits with a specific graph topology, or number of qubits. When passing a number of qubits a register with all-to-all connectivity is created.
TYPE:
|
interaction |
Interaction.ZZ, Interaction.NN, Interaction.XY, or Interacton.XYZ.
TYPE:
|
detuning |
single-qubit operator N, X, Y, or Z.
TYPE:
|
interaction_strength |
list of values to be used as the interaction strength for each
pair of qubits. Should be ordered following the order of
TYPE:
|
detuning_strength |
list of values to be used as the detuning strength for each qubit.
Alternatively, some string "x" can be passed, which will create a parameterized
detuning for each qubit, each labelled as
TYPE:
|
random_strength |
set random interaction and detuning strengths between -1 and 1.
TYPE:
|
use_all_node_pairs |
computes an interaction term for every pair of nodes in the graph, independent of the edge topology in the register. Useful for defining Hamiltonians where the interaction strength decays with the distance.
TYPE:
|
Examples:
from qadence import hamiltonian_factory, Interaction, Register, Z
n_qubits = 3
# Constant total magnetization observable:
observable = hamiltonian_factory(n_qubits, detuning = Z)
# Parameterized total magnetization observable:
observable = hamiltonian_factory(n_qubits, detuning = Z, detuning_strength = "z")
# Random all-to-all XY Hamiltonian generator:
generator = hamiltonian_factory(
n_qubits,
interaction = Interaction.XY,
random_strength = True,
)
# Parameterized NN Hamiltonian generator with a square grid interaction topology:
register = Register.square(qubits_side = n_qubits)
generator = hamiltonian_factory(
register,
interaction = Interaction.NN,
interaction_strength = "theta"
)
Source code in qadence/constructors/hamiltonians.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
|
interaction_nn(i, j)
interaction_xy(i, j)
interaction_xyz(i, j)
qft(n_qubits, support=None, inverse=False, reverse_in=False, swaps_out=False, strategy=Strategy.DIGITAL, gen_build=None)
The Quantum Fourier Transform.
Depending on the application, user should be careful with qubit ordering in the input and output. This can be controlled with reverse_in and swaps_out arguments.
PARAMETER | DESCRIPTION |
---|---|
n_qubits |
number of qubits in the QFT
TYPE:
|
support |
qubit support to use
TYPE:
|
inverse |
True performs the inverse QFT
TYPE:
|
reverse_in |
Reverses the input qubits to account for endianness
TYPE:
|
swaps_out |
Performs swaps on the output qubits to match the "textbook" QFT.
TYPE:
|
strategy |
Strategy.Digital or Strategy.sDAQC |
gen_build |
building block Ising Hamiltonian for the DAQC transform. Defaults to constant all-to-all Ising.
TYPE:
|
Examples:
Source code in qadence/constructors/qft.py
Hardware efficient ansatz for Rydberg atom arrays
rydberg_hea(register, n_layers=1, addressable_detuning=True, addressable_drive=False, tunable_phase=False, additional_prefix=None)
Hardware efficient ansatz for neutral atom (Rydberg) platforms.
This constructor implements a variational ansatz which is very close to what is implementable on 2nd generation PASQAL quantum devices. In particular, it implements evolution over a specific Hamiltonian which can be realized on the device. This Hamiltonian contains:
-
an interaction term given by the standard NN interaction and determined starting from the positions in the input register: Hᵢₙₜ = ∑ᵢⱼ C₆/rᵢⱼ⁶ nᵢnⱼ
-
a detuning term which corresponding to a n_i = (1+sigma_i^z)/2 applied to all the qubits. If the
addressable_detuning
flag is set to True, the routine effectively a local n_i = (1+sigma_i^z)/2 term in the evolved Hamiltonian with a different coefficient for each atom. These coefficients determine a local addressing pattern for the detuning on a subset of the qubits. In this routine, the coefficients are variational parameters and they will therefore be optimized at each optimizer step -
a drive term which corresponding to a sigma^x evolution operation applied to all the qubits. If the
addressable_drive
flag is set to True, the routine effectively a local sigma_i^x term in the evolved Hamiltonian with a different coefficient for each atom. These coefficients determine a local addressing pattern for the drive on a subset of the qubits. In this routine, the coefficients are variational parameters and they will therefore be optimized at each optimizer step -
if the
tunable_phase
flag is set to True, the drive term is modified in the following way: drive = cos(phi) * sigma^x - sin(phi) * sigma^y The addressable pattern above is maintained and the phase is considered just as an additional variational parameter which is optimized with the rest
Notice that, on real devices, the coefficients assigned to each qubit in both the detuning and drive patterns should be non-negative and they should always sum to 1. This is not the case for the implementation in this routine since the coefficients (weights) do not have any constraint. Therefore, this HEA is not completely realizable on neutral atom devices.
PARAMETER | DESCRIPTION |
---|---|
register |
the input atomic register with Cartesian coordinates.
TYPE:
|
n_layers |
number layers in the HEA, each layer includes a drive, detuning and pure interaction pulses whose is a variational parameter
TYPE:
|
addressable_detuning |
whether to turn on the trainable semi-local addressing pattern on the detuning (n_i terms in the Hamiltonian)
TYPE:
|
addressable_drive |
whether to turn on the trainable semi-local addressing pattern on the drive (sigma_i^x terms in the Hamiltonian)
TYPE:
|
tunable_phase |
whether to have a tunable phase to get both sigma^x and sigma^y rotations in the drive term. If False, only a sigma^x term will be included in the drive part of the Hamiltonian generator
TYPE:
|
additional_prefix |
an additional prefix to attach to the parameter names
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
ChainBlock
|
The Rydberg HEA block |
Source code in qadence/constructors/rydberg_hea.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
|
rydberg_hea_layer(register, tevo_drive, tevo_det, tevo_wait, phase=None, detunings=None, drives=None, drive_scaling=1.0)
A single layer of the Rydberg hardware efficient ansatz.
PARAMETER | DESCRIPTION |
---|---|
register |
the input register with atomic coordinates needed to build the interaction.
TYPE:
|
tevo_drive |
a variational parameter for the duration of the drive term of the Hamiltonian generator, including optional semi-local addressing
TYPE:
|
tevo_det |
a variational parameter for the duration of the detuning term of the Hamiltonian generator, including optional semi-local addressing
TYPE:
|
tevo_wait |
a variational parameter for the duration of the waiting time with interaction only
TYPE:
|
phase |
a variational parameter representing the global phase. If None, the global phase is set to 0 which results in a drive term in sigma^x only. Otherwise both sigma^x and sigma^y terms will be present
TYPE:
|
detunings |
a list of parameters with the weights of the locally addressed detuning terms. These are variational parameters which are tuned by the optimizer
TYPE:
|
drives |
a list of parameters with the weights of the locally addressed drive terms. These are variational parameters which are tuned by the optimizer
TYPE:
|
drive_scaling |
a scaling term to be added to the drive Hamiltonian generator
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
ChainBlock
|
A block with a single layer of Rydberg HEA |
Source code in qadence/constructors/rydberg_hea.py
The DAQC Transform
daqc_transform(n_qubits, gen_target, t_f, gen_build=None, zero_tol=1e-08, strategy=Strategy.SDAQC, ignore_global_phases=False)
Implements the DAQC transform for representing an arbitrary 2-body Hamiltonian.
The result is another fixed 2-body Hamiltonian.
Reference for universality of 2-body Hamiltonians:
-- https://arxiv.org/abs/quant-ph/0106064
Based on the transformation for Ising (ZZ) interactions, as described in the paper
-- https://arxiv.org/abs/1812.03637
The transform translates a target weighted generator of the type:
`gen_target = add(g_jk * kron(op(j), op(k)) for j < k)`
To a circuit using analog evolutions with a fixed building block generator:
`gen_build = add(f_jk * kron(op(j), op(k)) for j < k)`
where op = Z
or op = N
.
PARAMETER | DESCRIPTION |
---|---|
n_qubits |
total number of qubits to use.
TYPE:
|
gen_target |
target generator built with the structure above. The type of the generator will be automatically evaluated when parsing.
TYPE:
|
t_f |
total time for the gen_target evolution.
TYPE:
|
gen_build |
fixed generator to act as a building block. Defaults to constant NN: add(1.0 * kron(N(j), N(k)) for j < k). The type of the generator will be automatically evaluated when parsing.
TYPE:
|
zero_tol |
default "zero" for a missing interaction. Included for numerical reasons, see notes below.
TYPE:
|
strategy |
sDAQC or bDAQC, following definitions in the reference paper. |
ignore_global_phases |
if
TYPE:
|
Notes:
The paper follows an index convention of running from 1 to N. A few functions
here also use that convention to be consistent with the paper. However, for qadence
related things the indices are converted to [0, N-1].
The case for `n_qubits = 4` is an edge case where the sign matrix is not invertible.
There is a workaround for this described in the paper, but it is currently not implemented.
The current implementation may result in evolution times that are both positive or
negative. In practice, both can be represented by simply changing the signs of the
interactions. However, for a real implementation where the interactions should remain
fixed, the paper discusses a workaround that is not currently implemented.
The transformation works by representing each interaction in the target hamiltonian by
a set of evolutions using the build hamiltonian. As a consequence, some care must be
taken when choosing the build hamiltonian. Some cases:
- The target hamiltonian can have any interaction, as long as it is sufficiently
represented in the build hamiltonian. E.g., if the interaction `g_01 * kron(Z(0), Z(1))`
is in the target hamiltonian, the corresponding interaction `f_01 * kron(Z(0), Z(1))`
needs to be in the build hamiltonian. This is checked when the generators are parsed.
- The build hamiltonian can have any interaction, irrespectively of it being needed
for the target hamiltonian. This is especially useful for designing local operations
through the repeated evolution of a "global" hamiltonian.
- The parameter `zero_tol` controls what it means for an interaction to be "missing".
Any interaction strength smaller than `zero_tol` in the build hamiltonian will not be
considered, and thus that interaction is missing.
- The various ratios `g_jk / f_jk` will influence the time parameter for the various
evolution slices, meaning that if there is a big discrepancy in the interaction strength
for a given qubit pair (j, k), the output circuit may require the usage of hamiltonian
evolutions with very large times.
- A warning will be issued for evolution times larger than `1/sqrt(zero_tol)`. Evolution
times smaller than `zero_tol` will not be represented.
Examples:
from qadence import Z, N, daqc_transform
n_qubits = 3
gen_build = 0.5 * (N(0)@N(1)) + 0.7 * (N(1)@N(2)) + 0.2 * (N(0)@N(2))
gen_target = 0.1 * (Z(1)@Z(2))
t_f = 2.0
transformed_circuit = daqc_transform(
n_qubits = n_qubits,
gen_target = gen_target,
t_f = t_f,
gen_build = gen_build,
)
Source code in qadence/constructors/daqc/daqc.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
|
Some utility functions
build_idx_fms(basis, fm_pauli, fm_strategy, n_features, n_qubits, spectrum)
Builds the index feature maps based on the given parameters.
PARAMETER | DESCRIPTION |
---|---|
basis |
Type of basis chosen for the feature map.
TYPE:
|
fm_pauli |
The chosen Pauli rotation type.
TYPE:
|
fm_strategy |
The feature map strategy to be used. Possible values are 'parallel' or 'serial'.
TYPE:
|
n_features |
The number of features.
TYPE:
|
n_qubits |
The number of qubits.
TYPE:
|
spectrum |
The chosen spectrum.
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
list[KronBlock]
|
List[KronBlock]: The list of index feature maps. |
Source code in qadence/constructors/utils.py
generator_prefactor(spectrum, qubit_index)
Converts a spectrum string, e.g. tower or exponential.
The result is the correct generator prefactor.
Source code in qadence/constructors/utils.py
get_fm_qubits(fm_strategy, i, n_qubits, n_features)
Returns the list of target qubits for the given feature map strategy and feature index.
PARAMETER | DESCRIPTION |
---|---|
fm_strategy |
The feature map strategy to be used. Possible values are 'parallel' or 'serial'.
TYPE:
|
i |
The feature index.
TYPE:
|
n_qubits |
The number of qubits.
TYPE:
|
n_features |
The number of features.
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
Iterable
|
List[int]: The list of target qubits. |
RAISES | DESCRIPTION |
---|---|
ValueError
|
If the feature map strategy is not implemented. |