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.

keysight.qcs.quantum.GATES

Holds a map from aliases to quantum objects.

keysight.qcs.quantum.Gate

Represents a unitary quantum gate.

keysight.qcs.quantum.Hamiltonian

A class representing a Hamiltonian.

keysight.qcs.quantum.Measure

Represents a measurement of a qudit in the computational basis.

keysight.qcs.quantum.MultiQudits

A grouping of multi-qudit targets of the same size.

keysight.qcs.quantum.ParameterizedGate

Represents a parameterized gate.

keysight.qcs.quantum.ParametricGate

Represents a parameterized family of Gates.

keysight.qcs.quantum.QuantumAliasMap

Holds a map from aliases to quantum objects.

keysight.qcs.quantum.Qudits

A register of qudits to target.

keysight.qcs.quantum.Reset

Represents a reset of a qudit into the ground state of the computational basis.

keysight.qcs.quantum.SequenceType

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 | Variable, order: int = 1, base_sequence: Callable = <function xy4_sequence>, pulse_operation: BaseOperation | Iterable[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 | 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 | 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: float | Variable | None = None, number_of_pulses: int | None = None, pulse_interval: float | Variable | None = None, sequence_type: SequenceType = SequenceType.DD, enforce_even_pulse_number: bool = True, pulse_operation: BaseOperation | Iterable[BaseOperation] = Gate(matrix=[[0j, 1 + 0j], [1 + 0j, 0j]], name=X), pulse_duration: float | 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 | Variable, number_of_pulses: int = 4, pulse_operation: BaseOperation = Gate(matrix=[[0j, 1 + 0j], [1 + 0j, 0j]], name=X), pulse_duration: int | 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 | 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: str | None = 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 adj: Gate

A new Gate instance which is the conjugate transpose of this gate.

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: int | None = 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: str | None = 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.

property parameters: tuple[Variable[float], ...]

The parameters.

class keysight.qcs.quantum.ParametricGate(layers: Iterable[Gate | Hamiltonian], parameters: Iterable[str], name: str | None = None)

Bases: CsWrapper

Represents a parameterized family of Gates.

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 the gate() 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 Gates or Hamiltonians in chronological order.

  • parameters – A list of the parameters for the Hamiltonians in the order they appear in layers. 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[Gate | 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: int | None = None, register: Register | None = None, name: str | None = 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 with get_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: Register | None

The register to write the results to.

class keysight.qcs.quantum.Reset(name: str | None = 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 in QuantumClasses.

classmethod from_yaml(filename: 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 | Iterable[int], qudits: Iterable[tuple[Qudits, ...]], name: str | None = 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 to couplings.

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 from 0.

Parameters:
  • qudits – The multi-qudit targets.

  • name – The name of these targets.

class keysight.qcs.quantum.Qudits(labels: int | Iterable[int], name: str | None = None, dim: int | None = 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 to qudits.

  • 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.

On this page