Quantum
The quantum
subpackage encapsulates the concepts that are specific to quantum
information. It includes defining quantum instructions at the circuit and Hamiltonian
levels as well as the quantum-specific types that are stored in metadata.
Holds a map from aliases to quantum objects. |
|
Represents a unitary quantum gate. |
|
A class representing a Hamiltonian. |
|
Represents a measurement of a qudit in the computational basis. |
|
A grouping of multi-qudit targets of the same size. |
|
Represents a parameterized gate. |
|
Represents a parameterized family of |
|
Holds a map from aliases to quantum objects. |
|
A register of qudits to target. |
|
Represents a reset of a qudit into the ground state of the computational basis. |
|
A class that enumerate the available dynamical decoupling sequences. |
Decoupling sequence construction functions and sequence types
- class keysight.qcs.quantum.SequenceType(value)
A class that enumerate the available dynamical decoupling sequences.
- keysight.qcs.quantum.concatenated_decoupling_sequence(pulse_interval: float | keysight.qcs.variables.variable.Variable, order: int = 1, base_sequence: ~typing.Callable = <function xy4_sequence>, pulse_operation: keysight.qcs.operations.base_operation.BaseOperation | collections.abc.Iterable[keysight.qcs.operations.base_operation.BaseOperation] = Gate(matrix=[[0j, (1+0j)], [(1+0j), 0j]], name=X), **kwargs) Iterable[BaseOperation]
Generates a concatenated dynamical decoupling (CDD) sequence using a given base sequence with keyword arguments.
This will insert the base sequence multiple times into itself depending on the concatenation order. For example, the concatenated version of the XY4 sequence is of the form:
\(CDD_1 = XY4\) \(CDD_n = XY4[CDD_n-1] = Y - CDD_n-1 - X - CDD_n-1 - Y - CDD_n-1 - X\),
where n denotes the concatenation order.
- Parameters:
pulse_interval – The delay in seconds to insert between pulses.
order – The concatenation order. If set to 1, this returns the base sequence.
base_sequence – The base sequence to concatenate. Defaults to the XY4 sequence.
kwargs – Any keyword arguments passed to the base sequence.
- keysight.qcs.quantum.constant_decoupling_sequence(pulse_interval: float | keysight.qcs.variables.variable.Variable, number_of_pulses: int = 2, pulse_operation: BaseOperation = Gate(matrix=[[0j, 1 + 0j], [1 + 0j, 0j]], name=X)) Iterable[BaseOperation]
Generates a basic dynamical decoupling sequence with constant pulse interval.
The sequence is of the form:
\(\tau - X - \tau\),
where \(\tau\) denotes the pulse interval or free evolution time between pulses.
- Parameters:
pulse_interval – The delay in seconds to insert between pulses.
number_of_pulses – The number of pulses in the sequence. Note that only even numbers of pulses will preserve the original quantum state.
pulse_operation – Which operation to perform as decoupling pulse.
- keysight.qcs.quantum.cpmg_sequence(pulse_interval: float | keysight.qcs.variables.variable.Variable, number_of_pulses: int = 2, pulse_operation: BaseOperation = Gate(matrix=[[0j, 1 + 0j], [1 + 0j, 0j]], name=X)) Iterable[BaseOperation]
Generates the Carr-Purcell-Meiboom-Gill (CPMG) dynamical decoupling sequence.
The sequence is of the form:
\(\tau/2 - [X - \tau - X] - \tau/2\),
where \(\tau\) denotes the pulse interval or free evolution time between pulses and the sequence enlosed in square brackets is repeated when the number of pulses increases.
- Parameters:
pulse_interval – The delay in seconds to insert between pulses.
number_of_pulses – The number of pulses in the sequence. Note that only even numbers of pulses will preserve the original quantum state.
pulse_operation – Which operation to perform as decoupling pulse.
- keysight.qcs.quantum.make_decoupling_sequence(total_duration: Optional[Union[float, Variable]] = None, number_of_pulses: Optional[int] = None, pulse_interval: Optional[Union[float, Variable]] = None, sequence_type: SequenceType = SequenceType.DD, enforce_even_pulse_number: bool = True, pulse_operation: keysight.qcs.operations.base_operation.BaseOperation | collections.abc.Iterable[keysight.qcs.operations.base_operation.BaseOperation] = Gate(matrix=[[0j, 1 + 0j], [1 + 0j, 0j]], name=X), pulse_duration: float | keysight.qcs.variables.variable.Variable = 0) Iterable[BaseOperation]
Creates a list of operations representing a dynamical decoupling sequence implemented through X and Y gates and delays.
Available decoupling sequence types are:
Standard decoupling with fixed pulse interval
The Carr-Purcell-Meiboom-Gill (CPMG) sequence
The XY4 sequence
Concatenated decoupling using XY4
The Uhrig decoupling sequence
Note
Note that the generated sequence might not exactly contain the number of pulses or pulse intervals requested if there are constraints posed by the sequence type or if even numbers of pulses are enforced. For example, the XY4 sequence only allows multiples of four pulses. For more fine-grained control, users may construct the desired sequence directly.
- Parameters:
total_duration – The total sequence duration in seconds.
number_of_pulses – The number of pulses (optional). Note that for most sequences, the total_duration will determine the number of pulses.
pulse_interval – The interval between pulses in seconds (optional). Can be specified instead of the number of pulses or the total duration.
sequence_type – The sequence type. Possible values are “DD”, “CPMG”, “XY4”, “CDD”, and “Uhrig”.
enforce_even_pulse_number – Whether to require an even number of pulses.
pulse_operation – Which operation to perform as decoupling pulse.
pulse_duration – The duration of the pulses, required to determine the full length of the sequence. Note that if
pulse_operation
has a duration attribute, this value will be used instead.- Raises:
ValueError – If no sequence parameters are specified.
ValueError – If the sequence parameters are incompatible.
- keysight.qcs.quantum.uhrig_sequence(maximum_pulse_interval: float | keysight.qcs.variables.variable.Variable, number_of_pulses: int = 4, pulse_operation: BaseOperation = Gate(matrix=[[0j, 1 + 0j], [1 + 0j, 0j]], name=X), pulse_duration: int | keysight.qcs.variables.variable.Variable = 0)
Generates the Uhrig (or quadratic) dynamical decoupling sequence using only X gates.
The pulse location for each pulse k out of n pulses in total is defined via:
\(\sin(\pi * (k + 1) / (2 * n + 2)) ^ 2\),
and the intervals between the pulses are padded with delays.
- Parameters:
maximum_pulse_interval – The maximum delay in seconds to insert between pulses. All other delays required by the sequence will be scaled to this.
number_of_pulses – The number of pulses in the sequence. Note that only even numbers of pulses will preserve the original quantum state.
pulse_operation – Which operation to perform as decoupling pulse.
pulse_duration – The finite duration of the actual operation, which when greater than zero will reduce the pulse intervals to position the center of the pulses at the required locations.
- Raises:
ValueError – When the input parameter result in negative delays being required.
- keysight.qcs.quantum.xy4_sequence(pulse_interval: float | keysight.qcs.variables.variable.Variable, repetitions: int = 1, pulse_operation: Iterable[BaseOperation] = [Gate(matrix=[[0j, -1j], [1j, 0j]], name=Y), Gate(matrix=[[0j, 1 + 0j], [1 + 0j, 0j]], name=X)]) Iterable[BaseOperation]
Generates an XY4 dynamical decoupling sequence consisting of Y and X gates interleaved by delays.
The sequence is of the form:
\(\tau - Y - \tau - X - \tau - Y - \tau - X - \tau\),
where tau denotes the pulse interval or free evolution time between pulses.
- Parameters:
pulse_interval – The delay in seconds to insert between pulses.
repetitions – How often to repeat the four pulse sequence.
pulse_operation – Which operations to perform as decoupling pulse.
Gates
- class keysight.qcs.quantum.Gate(mat: ArrayLike, name: Optional[str] = None)
Bases:
BaseOperation
Represents a unitary quantum gate.
import keysight.qcs as qcs qcs.Gate([[0, 1], [1, 0]])Gate([[0j, (1+0j)], [(1+0j), 0j]])
- Parameters:
matrix – A unitary matrix in the computational basis.
name – An optional name for this.
- Raises:
ValueError – If the matrix is not square.
ValueError – If the determinant of the matrix is zero.
ValueError – If the matrix is not proportional to a unitary.
- property dim: int
The dimension of the space this matrix acts on.
- property mat: ndarray
The matrix in the standard basis.
- property is_diagonal: bool
Whether this matrix is diagonal or not.
- property is_hermitian: bool
Whether this matrix is Hermitian or not to numerical precision.
- static x(power: int = 1, dim: Optional[int] = None)
Make a generalized Pauli X gate to a specified power.
- Parameters:
power – The power to raise the X gate to.
dim – The dimension of the qudit the gate acts on.
- infidelity_to(other: Gate) float
Computes the process infidelity of this gate to another gate.
The process infidelity between two \(d\)-dimensional gates \(U\) and \(V\) is
\[r(U, V) = 1 - |\tr(U^\dagger V) / d|^2.\]
- Parameters:
other – The gate to compute the process infidelity to.
- Raises:
ValueError – If
other
has a different dimension to this gate.
- class keysight.qcs.quantum.Hamiltonian(mat: ArrayLike, name: Optional[str] = None)
Bases:
CsWrapper
A class representing a Hamiltonian.
import keysight.qcs as qcs # initializing a Hamiltonian qcs.Hamiltonian([[0, 1], [1, 0]])Hamiltonian([[(-1.1102230246251565e-16+0j), (0.9999999999999994+0j)], [(0.9999999999999994+0j), (-5.551115123125783e-17+0j)]]))
- Parameters:
matrix – A Hermitian matrix in the computational basis.
name – An optional name for this.
- Raises:
ValueError – If the matrix is not Hermitian.
- property adj: Hamiltonian
A new
Hamiltonian
instance which generates the inverse (negative) evolution of this Hamiltonian.
- property dim: int
The dimension of the space this Hamiltonian acts on.
- property mat: ndarray
The matrix in the standard basis.
- property name: str | None
The name of this.
- gate(angle: float, in_radians: bool = True) Gate
Returns the gate corresponding to the exponential of this Hamiltonian by a fixed angle.
The returned gate \(G(\theta)\) as a function of the angle \(\theta\) in radians is
\[G(\theta) = e^{-i \theta H / 2},\]where \(H\) is the matrix for this Hamiltonian. The factor of two is included by convention so that if the eigenvalues of \(H\) are in \({-1, 0, 1}\), then \(G(\theta + 2 \pi) = -G(\theta)\), which corresponds to the same physical transformation up to the global phase.
import numpy as np import keysight.qcs as qcs z90 = qcs.PAULIS.sigma_z.gate(np.pi / 2) # we can specify the angle in either radians or degrees assert z90 == qcs.PAULIS.sigma_z.gate(90, False) # up to a global phase, the z90 is equivalent to a phase gate assert z90.infidelity_to(qcs.Gate(np.diag([1, 1j]))) < 1e-8
- Parameters:
angle – The angle in the matrix exponential.
in_radians – Whether the angle is in radians (
True
) or degrees (False
).
- class keysight.qcs.quantum.ParameterizedGate(gate: ParametricGate, parameters: Variable[float] | Iterable[Variable[float]], name: str | None = None)
Bases:
BaseOperation
Represents a parameterized gate.
- Parameters:
gate – The parametric gate.
parameters – The parameters of
gate
.name – An optional name for this.
- Raises:
ValueError – If any parameters have inconsistent or multi-dimensional shapes.
- property dim: int
The dimension of the space this gate acts on.
- property gate: ParametricGate
The gate.
- class keysight.qcs.quantum.ParametricGate(layers: Iterable[keysight.qcs.quantum.gate.Gate | keysight.qcs.quantum.hamiltonian.Hamiltonian], parameters: Iterable[str], name: Optional[str] = None)
Bases:
CsWrapper
Represents a parameterized family of
Gate
s.import numpy as np import keysight.qcs as qcs # create a parametrized gate corresponding to the matrix exponential # e^{-i phi sigma_x} of the sigma_x Hamiltonian with a coefficient phi par_gate = qcs.ParametricGate([qcs.PAULIS.sigma_x], ["phi"])A
Gate
with specified values can be created by calling the parameterized gate (or thegate()
method) using either positional or keyword arguments.assert par_gate(phi=np.pi / 4) == par_gate(np.pi / 4)Layers are assumed to be in chronological order and may depend on common variables
# initialize a parametric gate layers = [qcs.PAULIS.sigma_z, qcs.PAULIS.sigma_x, -qcs.PAULIS.sigma_z] parameters = ["phi", "theta", "phi"] p_gate = qcs.ParametricGate(layers, parameters) # specify values for phi and theta phi = np.pi / 6 theta = np.pi / 7 # compute the value of p_gate for given phi and theta gate = p_gate(phi=phi, theta=theta) rx = qcs.PAULIS.rx rz = qcs.PAULIS.rz assert gate.infidelity_to(rz(-phi) @ rx(theta) @ rz(phi)) < 1e-8
- Parameters:
layers – An iterable of
Gate
s orHamiltonian
s in chronological order.parameters – A list of the parameters for the
Hamiltonian
s in the order they appear inlayers
. May contain repeated elements to indicate common variables.name – An optional name for this.
- property adj: ParametricGate
A new
ParametricGate
instance which is the conjugate transpose of this parametrized gate.
- property dim: int
The dimension of the space this parametric gate acts on.
- property layers: tuple[keysight.qcs.quantum.gate.Gate | keysight.qcs.quantum.hamiltonian.Hamiltonian, ...]
The layers in this parametric gate in chronological order.
- property name: str | None
The name of this.
- property parameters: tuple[str, ...]
The parameters for the layers in this parametric gate.
- gate(*args: Iterable[float], **kwargs: any) Gate
Returns the gate for specific parameter values.
The values of the parameters can be specified as an iterable of floats in the same order as in
parameters()
, a dictionary mapping parameter names to values, or a combination thereof.Additionally, the keyword argument
in_radians
can be used to specify whether the parameters should be interpreted as being in radians (True
by default) or in degrees (False
).This method is also aliased to the call method for convenience.
import numpy as np import keysight.qcs as qcs # make a parametric gate corresponding to a rotation about Z, a rotation # about X, and then the inverse of the first rotation about Z layers = [qcs.PAULIS.sigma_z, qcs.PAULIS.sigma_x, qcs.PAULIS.sigma_z.adj] parameters = ["phi", "theta", "phi"] p_gate = qcs.ParametricGate(layers, parameters) # specify values in radians using positional arguments p_gate.gate(np.pi / 4, np.pi / 2) # specify values in radians using keyword arguments p_gate.gate(phi=np.pi / 4, theta=np.pi / 2) # specify values in radians using keyword arguments in the call function p_gate(phi=np.pi / 4, theta=np.pi / 2) # specify values in degrees using keyword arguments in the call function p_gate(phi=45, theta=90, in_radians=False)Gate([[(0.7071067811865474+5.551115123125783e-17j), (0.5-0.49999999999999983j)], [(-0.4999999999999999-0.4999999999999999j), (0.7071067811865479+5.551115123125783e-17j)]])
- Raises:
ValueError – If a value is specified with a position and a keyword argument.
ValueError – If the value of a parameter is not specified.
ValueError – If the value of a parameter that is not in this parametric gate is specified.
- rename(**kwargs: dict[str, str]) ParametricGate
Return a new parametric gate whose variables have been renamed.
- Parameters:
kwargs – The map of variable names to the new names.
State Preparation and Measurement
- class keysight.qcs.quantum.Measure(dim: Optional[int] = None, register: Optional[Register] = None, name: Optional[str] = None)
Bases:
BaseOperation
Represents a measurement of a qudit in the computational basis.
- Parameters:
dim – The dimension of the qudit. If
None
, it is automatically set withget_dim()
.register – The register to write the results to for use in future conditional operations.
name – An optional name for this.
- property dim: int
The dimension of the qudit to be measured.
- property register: keysight.qcs.channels.register.Register | None
The register to write the results to.
- class keysight.qcs.quantum.Reset(name: Optional[str] = None)
Bases:
BaseOperation
Represents a reset of a qudit into the ground state of the computational basis.
QuantumAliasMap
- class keysight.qcs.quantum.QuantumAliasMap(**kwargs: dict[str, any])
Bases:
AliasMap
Holds a map from aliases to quantum objects.
- Parameters:
kwargs – a map from aliases to quantum objects.
- QuantumClasses = (<class 'keysight.qcs.channels.channels.Channels'>, <class 'keysight.qcs.quantum.gate.Gate'>, <class 'keysight.qcs.quantum.hamiltonian.Hamiltonian'>, <class 'keysight.qcs.quantum.parametric_gate.ParametricGate'>, <class 'keysight.qcs.quantum.qudits.Qudits'>)
The types of objects that can be held in a
QuantumAliasMap
.
- add_aliases(**kwargs: dict[str, any]) None
Adds an object to this alias map with a given alias.
- Parameters:
kwargs – The map from names to objects.
- Raises:
AttributeError – If any key in
kwargs
is already an attribute of this alias map.AttributeError – If the type of any value in
kwargs
is not inQuantumClasses
.
- classmethod from_yaml(filename: pathlib.Path | str) QuantumAliasMap
Loads the aliases defined in a YAML file.
- Parameters:
filename – The name of the file.
- quantum.PAULIS = QuantumAliasMap(rx,ry,rz,sigma_x,sigma_y,sigma_z,zxz)
- quantum.GATES = QuantumAliasMap(cx,cy,cz,h,id,iswap,swap,x,x90,y,y90,z,z90)
Qudits
- class keysight.qcs.quantum.MultiQudits(labels: int | collections.abc.Iterable[int], qudits: Iterable[tuple[keysight.qcs.quantum.qudits.Qudits, ...]], name: Optional[str] = None)
A grouping of multi-qudit targets of the same size.
import keysight.qcs as qcs # initialize 4 qudits qudits = qcs.Qudits(range(4), name="q") # create two-qudit pairs from the qudits mqs = qcs.MultiQudits.from_qudits(qudits=(qudits[:2], qudits[2:])) assert mqs.dim == qudits.dim assert mqs.qudits == [ ( qcs.Qudits(dim=2, labels=(0,), name="q"), qcs.Qudits(dim=2, labels=(2,), name="q"), ), ( qcs.Qudits(dim=2, labels=(1,), name="q"), qcs.Qudits(dim=2, labels=(3,), name="q"), ), ]
- Parameters:
labels – The label for each multi-qudit target.
qudits – The multi-qudit targets.
name – The name of these targets. If
None
, it is automatically set tocouplings
.- Raises:
ValueError – If the number of labels and multi-qudit targets is different.
ValueError – If the number of qudits in any multi-qudit target are different.
ValueError – If the qudits have different dimensions.
ValueError – If the qudits have an invalid multi-qudit target.
ValueError – If the qudits have a duplicate multi-qudit target.
- property dim
The dimension of the individual quantum systems.
- property qudit_registers: list[keysight.qcs.quantum.qudits.Qudits]
The distinct qudit registers in this.
- property qudits: list[tuple[keysight.qcs.quantum.qudits.Qudits, ...]]
The multi-qudit targets.
- property total_dim
The combined dimension of the individual quantum systems.
- static from_qudits(qudits: Iterable[tuple[keysight.qcs.quantum.qudits.Qudits, ...]], name: Optional[str] = None) MultiQudits
Returns a new
MultiQudits
with labels starting from0
.
- Parameters:
qudits – The multi-qudit targets.
name – The name of these targets.
- class keysight.qcs.quantum.Qudits(labels: int | collections.abc.Iterable[int], name: Optional[str] = None, dim: Optional[int] = None)
A register of qudits to target.
import keysight.qcs as qcs # the qudits can be specified with an integer q = qcs.Qudits(0) # or with an iterable of integers q = qcs.Qudits(range(3)) # or by specifying their labels q = qcs.Qudits([4, 5, 6]) # additionally, a dimension can be specified one_qubit = qcs.Qudits(1, dim=2) five_qutrits = qcs.Qudits(5, dim=3)
- Parameters:
labels – An iterable of qudit labels, or an integer representing a single label.
name – The name of these qudits. If
None
, it is automatically set toqudits
.dim – The subsystem dimension of these qudits. If
None
, it is automatically set to 2.
- property dim: int
The dimension of the individual quantum systems.
- make_connectivity(connections: ArrayLike[int], name: str | None = None) MultiQudits
Make a MultiQudit object specifying connections between the elements of this.
import keysight.qcs as qcs from itertools import permutations # create a register with 3 qudits labeled [2, 5, 6] qudits = qcs.Qudits([2, 5, 6]) # create specific connections qudits.make_connectivity([[2, 6]], "specific") # create all pairwise connections qudits.make_connectivity(permutations(qudits.labels, 2), "all_pairs")MultiQudits(labels=[0, 1, 2, ...], name=all_pairs, dim=2)
- Parameters:
connections – A list of the labels to be connected.
name – The name to assign to the returned MultiQudits. The default will assign the name
couplings
.- Raises:
ValueError – If
connections
cannot be treated as a two-dimensional array.