Gates

The state of a quantum system is modified by means of quantum gates.

Constructing gates

DQCsim provides four types of gates.

  • Unitary gates: these apply a gate matrix on one or more qubits.
  • Measurement gates: these cause the state of a qubit to be collapsed along and measured in some basis.
  • Prep gates: these set the state of a qubit to some value.
  • Custom gates: anything else that the downstream plugin supports.

These are constructed using the following functions. The predefined gates are as described earlier.

dqcs_gate_new_predef()

Constructs a new predefined unitary gate.

dqcs_handle_t dqcs_gate_new_predef(
    dqcs_predefined_gate_t gate_type,
    dqcs_handle_t qubits,
    dqcs_handle_t param_data
)

gate_type specifies which kind of gate should be constructed.

targets must be a handle to a non-empty qubit set, containing at least as many qubits as needed for the specified gate type. If more qubits are specified, the rightmost qubits become the targets, and the remaining qubits become control qubits to make a controlled gate.

param_data takes an optional ArbData object used to parameterize the gate if necessary. If not specified, an empty object is used. Some of the gate types are parameterized, and use values from this ArbData as defined in the docs for dqcs_predefined_gate_t. Anything remaining in the ArbData afterwards is placed in the gate object.

This function returns the handle to the gate, or 0 to indicate failure. The qubit set and parameterization data (if specified) are consumed/deleted by this function if and only if it succeeds.

dqcs_gate_new_predef_one()

Constructs a new predefined unitary one-qubit gate.

dqcs_handle_t dqcs_gate_new_predef_one(
    dqcs_predefined_gate_t gate_type,
    dqcs_qubit_t qa,
    dqcs_handle_t param_data
)

This function is simply a shorthand for dqcs_gate_new_predef() with one qubit in the qubits set, to make constructing one-qubit gates more ergonomic. Refer to its documentation for more information.

dqcs_gate_new_predef_two()

Constructs a new predefined unitary two-qubit gate.

dqcs_handle_t dqcs_gate_new_predef_two(
    dqcs_predefined_gate_t gate_type,
    dqcs_qubit_t qa,
    dqcs_qubit_t qb,
    dqcs_handle_t param_data
)

This function is simply a shorthand for dqcs_gate_new_predef() with two qubit in the qubits set, to make constructing two-qubit gates more ergonomic. Refer to its documentation for more information.

dqcs_gate_new_predef_three()

Constructs a new predefined unitary three-qubit gate.

dqcs_handle_t dqcs_gate_new_predef_three(
    dqcs_predefined_gate_t gate_type,
    dqcs_qubit_t qa,
    dqcs_qubit_t qb,
    dqcs_qubit_t qc,
    dqcs_handle_t param_data
)

This function is simply a shorthand for dqcs_gate_new_predef() with three qubit in the qubits set, to make constructing three-qubit gates more ergonomic. Refer to its documentation for more information.

dqcs_gate_new_unitary()

Constructs a new unitary gate.

dqcs_handle_t dqcs_gate_new_unitary(
    dqcs_handle_t targets,
    dqcs_handle_t controls,
    dqcs_handle_t matrix
)

targets must be a handle to a non-empty qubit set. The qubits in this set correspond with the supplied unitary matrix.

controls optionally specifies a set of control qubits. You may pass 0 or an empty qubit set if you don't need control qubits.

matrix must be a handle to an appropriately sized matrix.

The supplied matrix is only applied to the target qubits if all the control qubits are or will be determined to be set. For instance, to encode a CCNOT/Toffoli gate, you can specify one target qubits, two control qubits, and [0, 1; 1, 0] (X) for the matrix. This is equivalent to extending the matrix to the full Toffoli matrix and specifying all three qubits in the targets set, or the midway solution using a CNOT matrix, but these solutions may be less efficient depending on whether the simulator can optimize its calculations for controlled gates.

Simulators are not required to apply the (hidden) global phase component of the gate matrix in the same way it is specified; that is, if the simulator can optimize its calculations by altering the global phase it is allowed to.

DQCsim checks whether the matrix is unitary using the equivalent of dqcs_mat_approx_unitary() with an epsilon value of 1e-6.

This function returns the handle to the gate, or 0 to indicate failure. The targets qubit set, (if specified) the controls qubit set, and the matrix are consumed/deleted by this function if and only if it succeeds.

dqcs_gate_new_measurement()

Constructs a new measurement gate.

dqcs_handle_t dqcs_gate_new_measurement(
    dqcs_handle_t measures,
    dqcs_handle_t matrix
)

measures must be a handle to a qubit set. matrix is an optional matrix handle signifying the measurement basis. If zero, the Z basis is used. Otherwise, it must be a handle to a unitary 2x2 matrix, and the semantics of the measurement are as follows:

  • apply the hermetian of the matrix to each qubit
  • measure each qubit in the Z basis
  • apply the matrix to each qubit

This function returns the handle to the gate, or 0 to indicate failure. The measures qubit set and matrix handle are consumed/deleted by this function if and only if it succeeds.

dqcs_gate_new_prep()

Constructs a new prep gate.

dqcs_handle_t dqcs_gate_new_prep(
    dqcs_handle_t targets,
    dqcs_handle_t matrix
)

targets must be a handle to a qubit set. matrix is an optional matrix handle signifying the state that the qubits are initialized to. If zero, the qubits are initialized to |0>. Otherwise, it must be a handle to a unitary 2x2 matrix, and the semantics are as follows:

  • initialize each qubit to |0>
  • apply the matrix to each qubit

This function returns the handle to the gate, or 0 to indicate failure. The targets qubit set and matrix handle are consumed/deleted by this function if and only if it succeeds.

dqcs_gate_new_custom()

Constructs a new custom gate.

dqcs_handle_t dqcs_gate_new_custom(
    const char *name,
    dqcs_handle_t targets,
    dqcs_handle_t controls,
    dqcs_handle_t measures,
    dqcs_handle_t matrix
)

The functionality of custom gates is not specified by DQCsim. Instead, this is left up to the plugins. Of course, for this to work, plugins that are connected to each other must agree on the format used.

name specifies the name of the gate. The name is used to indicate which custom operation is to be applied.

targets optionally specifies the set of target qubits. You may pass 0 or an empty qubit set if you don't need target qubits.

controls optionally specifies the set of control qubits. You may pass 0 or an empty qubit set if you don't need control qubits.

measures optionally specifies the set of measured qubits. You may pass 0 or an empty qubit set if no qubits are measured. Note that the upstream plugin expects exactly one measurement result for each qubit specified in this set; anything else results in a warning and the measurement result being set to undefined.

matrix optionally specifies a handle to an appropriately sized matrix for the targets qubit set.

In addition to the above data, gate objects implement the arb interface to allow user-specified classical information to be attached.

This function returns the handle to the gate, or 0 to indicate failure. The specified qubit sets are consumed/deleted by this function if and only if it succeeds.

Control qubit representation

A gatestream source is allowed to specify controlled gates either using DQCsim's separate list of control qubits (this is the recommended way), by using an explicitly controlled gate matrix and using only the target qubit list, or a even mix of the two. The following two functions, primarily intended for gatestream sinks, can be used to convert between these representations.

dqcs_gate_reduce_control()

Utility function that detects control qubits in the targets list of the gate by means of the gate matrix, and reduces them into controls qubits.

dqcs_handle_t dqcs_gate_reduce_control(
    dqcs_handle_t gate,
    double epsilon,
    bool ignore_gphase
)

This function borrows a handle to any gate with a matrix, and returns an equivalent copy of said gate with any control qubits in the targets set moved to the controls set. The associated gate matrix is accordingly reduced in size. The control qubits are added at the end of the controls set in the same order they appeared in the targets qubit set.

epsilon specifies the maximum element-wise deviation from the identity matrix for the relevant array elements for a qubit to be considered a control qubit. Note that if this is greater than zero, the resulting gate may not be exactly equivalent. If ignore_gphase is set, any global phase in the matrix is ignored, but the global phase of the non-control submatrix is not changed.

This function returns a new gate handle with the modified gate, or a copy of the input gate if the matrix could not be reduced. If the input gate does not have a matrix (measurement gate, or custom gate without matrix) an error is returned instead.

dqcs_gate_expand_control()

Utility function that expands a gate matrix to account for all control qubits.

dqcs_handle_t dqcs_gate_expand_control(dqcs_handle_t gate)

This function borrows a handle to any gate with a matrix, and returns an equivalent copy of said gate with any control qubits in the controls set moved to the targets set. The associated gate matrix is extended accordingly. The control qubits are added at the front of the targets set in the same order they appeared in the controls qubit set.

This function returns a new gate handle with the modified gate, or a copy of the input gate if the matrix could not be reduced. If the input gate does not have a matrix (measurement gate, or custom gate without matrix) an error is returned instead.

Attached classical data

Classical information can be attached to any gate using the ArbData protocol: gate handles support all the dqcs_arb_*() API calls. This is primarily intended for custom gates.

Interpreting gates

DQCsim provides two ways for interpreting incoming gates: manually querying the parameters and gate maps. The latter is quite advanced and deserves its own section (the next one), but let's deal with the manual method first.

The first step for any incoming gate is to query its type.

dqcs_gate_type()

Returns the gate type of the given gate.

dqcs_gate_type_t dqcs_gate_type(dqcs_handle_t gate)

Returns DQCS_GATE_TYPE_INVALID if the gate handle is invalid.

This results in the following enumeration. The exact semantics of each type of gate is listed in the documentation of each enum variant.

dqcs_gate_type_t

Types of DQCsim gates.

typedef enum { ... } dqcs_gate_type_t;

Variants:

DQCS_GATE_TYPE_INVALID = 0
Invalid gate type. Used as an error return value.
DQCS_GATE_TYPE_UNITARY
Unitary gates have one or more target qubits, zero or more control qubits, and a unitary matrix, sized for the number of target qubits.

The semantics are that the unitary matrix expanded by the number of control qubits is applied to the qubits.

The data field may add pragma-like hints to the gate, for instance to represent the line number in the source file that generated the gate, error modelling information, and so on. This data may be silently ignored.

DQCS_GATE_TYPE_MEASUREMENT
Measurement gates have one or more measured qubits and a 2x2 unitary matrix representing the basis.

The semantics are:

  • the hermetian of the matrix is applied to each individual qubit;
  • each individual qubit is measured in the Z basis;
  • the matrix is applied to each individual qubit;
  • the results of the measurement are propagated upstream.

This allows any measurement basis to be used.

The data field may add pragma-like hints to the gate, for instance to represent the line number in the source file that generated the gate, error modelling information, and so on. This data may be silently ignored.

DQCS_GATE_TYPE_PREP
Prep gates have one or more target qubits and a 2x2 unitary matrix representing the basis.

The semantics are:

  • each qubit is initialized to |0>;
  • the matrix is applied to each individual qubit.

This allows any initial state to be used.

The data field may add pragma-like hints to the gate, for instance to represent the line number in the source file that generated the gate, error modelling information, and so on. This data may be silently ignored.

DQCS_GATE_TYPE_CUSTOM
Custom gates perform a user-defined mixed quantum-classical operation, identified by a name. They can have zero or more target, control, and measured qubits, of which only the target and control sets must be mutually exclusive. They also have an optional matrix of arbitrary size.

The semantics are:

  • if the name is not recognized, an error is reported;
  • a user-defined operation is performed based on the name, qubits, matrix, and data arguments;
  • exactly one measurement result is reported upstream for exactly the qubits in the measures set.

The following functions can be used to read the remaining parameters associated with a gate.

dqcs_gate_has_targets()

Returns whether the specified gate has target qubits.

dqcs_bool_return_t dqcs_gate_has_targets(dqcs_handle_t gate)
dqcs_gate_targets()

Returns a handle to a new qubit reference set containing the qubits targeted by this gate.

dqcs_handle_t dqcs_gate_targets(dqcs_handle_t gate)
dqcs_gate_has_controls()

Returns whether the specified gate has control qubits.

dqcs_bool_return_t dqcs_gate_has_controls(dqcs_handle_t gate)
dqcs_gate_controls()

Returns a handle to a new qubit reference set containing the qubits that control this gate.

dqcs_handle_t dqcs_gate_controls(dqcs_handle_t gate)
dqcs_gate_has_measures()

Returns whether the specified gate measures any qubits.

dqcs_bool_return_t dqcs_gate_has_measures(dqcs_handle_t gate)
dqcs_gate_measures()

Returns a handle to a new qubit reference set containing the qubits measured by this gate.

dqcs_handle_t dqcs_gate_measures(dqcs_handle_t gate)
dqcs_gate_has_matrix()

Returns whether a unitary matrix is associated with this gate.

dqcs_bool_return_t dqcs_gate_has_matrix(dqcs_handle_t gate)
dqcs_gate_matrix()

Returns a copy of the unitary matrix associated with this gate, if one exists.

dqcs_handle_t dqcs_gate_matrix(dqcs_handle_t gate)

If this function succeeds, a new matrix handle is returned. If it fails, 0 is returned.

dqcs_gate_has_name()

Returns whether the specified gate has a name.

dqcs_bool_return_t dqcs_gate_has_name(dqcs_handle_t gate)
dqcs_gate_name()

Returns the name of a custom gate.

char *dqcs_gate_name(dqcs_handle_t gate)

This function fails if the gate is not a custom gate. Query dqcs_gate_has_name() to disambiguate between a non-custom gate and a different error.

On success, this returns a newly allocated string containing the gate name. Free it with free() when you're done with it to avoid memory leaks. On failure, this returns NULL.