Skip to main content
IBM Quantum Platform

QkDag

typedef struct QkDag QkDag

The QkDag struct exposes a low level interface to the Qiskit transpiler’s directed acyclic graph (DAG) representation of a quantum circuit for use in transpiler passes. It exposes only what is defined in the inner data model of Qiskit. Therefore it is missing some functionality that is available in the higher level Python DAGCircuit class.

The C API currently only supports building DAGs that contain operations defined in Qiskit’s internal Rust data model. Generally this includes only gates in the standard gate library, standard non-unitary operations (currently Barrier, Measure, Reset, and Delay) and UnitaryGate. This functionality will be expanded over time as the Rust data model is expanded to natively support more functionality.


Data Types

QkDagNodeType

enum QkDagNodeType

The type of node in a QkDag.

Operation nodes represent an applied instruction. The rest of the nodes are considered “wire” nodes and represent the endpoints of the DAG’s data dependency chains.

Values:

enumerator QkDagNodeType_Operation

Operation node.

enumerator QkDagNodeType_QubitIn

Qubit wire start node.

enumerator QkDagNodeType_QubitOut

Qubit wire end node.

enumerator QkDagNodeType_ClbitIn

Clbit wire start node.

enumerator QkDagNodeType_ClbitOut

Clbit wire end node.

enumerator QkDagNodeType_VarIn

Classical variable wire start node.

enumerator QkDagNodeType_VarOut

Classical variable wire end node.

QkOperationKind

enum QkOperationKind

The operation’s kind.

This is returned when querying a particular node in the graph with qk_dag_op_node_kind, and is intended to allow the caller to dispatch (e.g. via a “switch”) calls specific to the contained operation’s kind.

Values:

enumerator QkOperationKind_Gate

enumerator QkOperationKind_Barrier

enumerator QkOperationKind_Delay

enumerator QkOperationKind_Measure

enumerator QkOperationKind_Reset

enumerator QkOperationKind_Unitary

enumerator QkOperationKind_PauliProductMeasurement

enumerator QkOperationKind_ControlFlow

enumerator QkOperationKind_Unknown

This variant is used as an opaque type for operations not yet implemented in the native data model.

QkDagNeighbors

struct QkDagNeighbors

A struct for storing successors and predecessors information retrieved from qk_dag_successors and qk_dag_predecessors, respectively.

This object is read-only from C. To satisfy the safety guarantees of qk_dag_neighbors_clear, you must not overwrite any data initialized by qk_dag_successors or qk_dag_predecessors, including any pointed-to data.

const uint32_t *neighbors

Array of size num_neighbors of node indices.

size_t num_neighbors

The length of the neighbors array.


Functions

qk_dag_new

QkDag *qk_dag_new(void)

Construct a new empty DAG.

You must free the returned DAG with qk_dag_free when done with it.

Example

QkDag *empty = qk_dag_new();

Returns

A pointer to the created DAG.

qk_dag_add_quantum_register

void qk_dag_add_quantum_register(QkDag *dag, const QkQuantumRegister *reg)

Add a quantum register to the DAG.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1024, "my_register");
qk_dag_add_quantum_register(dag, qr);
qk_quantum_register_free(qr);
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag and if reg is not a valid, non-null pointer to a QkQuantumRegister.

Parameters

  • dag – A pointer to the DAG.
  • reg – A pointer to the quantum register.

qk_dag_add_classical_register

void qk_dag_add_classical_register(QkDag *dag, const QkClassicalRegister *reg)

Add a classical register to the DAG.

Example

QkDag *dag = qk_dag_new();
QkClassicalRegister *cr = qk_classical_register_new(24, "my_register");
qk_dag_add_classical_register(dag, cr);
qk_classical_register_free(cr);
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag and if reg is not a valid, non-null pointer to a QkClassicalRegister.

Parameters

  • dag – A pointer to the DAG.
  • reg – A pointer to the classical register.

qk_dag_num_qubits

uint32_t qk_dag_num_qubits(const QkDag *dag)

Get the number of qubits the DAG contains.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(24, "my_register");
qk_dag_add_quantum_register(dag, qr);
uint32_t num_qubits = qk_dag_num_qubits(dag);  // num_qubits==24
qk_quantum_register_free(qr);
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.

Returns

The number of qubits the DAG is defined on.

qk_dag_num_clbits

uint32_t qk_dag_num_clbits(const QkDag *dag)

Get the number of clbits the DAG contains.

Example

QkDag *dag = qk_dag_new();
QkClassicalRegister *cr = qk_classical_register_new(24, "my_register");
qk_dag_add_classical_register(dag, cr);
uint32_t num_clbits = qk_dag_num_clbits(dag);  // num_clbits==24
qk_classical_register_free(cr);
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.

Returns

The number of clbits the DAG is defined on.

qk_dag_num_op_nodes

size_t qk_dag_num_op_nodes(const QkDag *dag)

Return the total number of operation nodes in the DAG.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
 
uint32_t qubit[1] = {0};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
size_t num = qk_dag_num_op_nodes(dag); // 1
 
qk_dag_free(dag);
qk_quantum_register_free(qr);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.

Returns

The total number of instructions in the DAG.

qk_dag_node_type

QkDagNodeType qk_dag_node_type(const QkDag *dag, uint32_t node)

Get the type of the specified node.

The result can be used in a switch statement to dispatch proper handling when iterating over nodes of unknown type.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The node to get the type of.

Returns

The type of the node.

qk_dag_qubit_in_node

uint32_t qk_dag_qubit_in_node(const QkDag *dag, uint32_t qubit)

Retrieve the index of the input node of the wire corresponding to the given qubit.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • qubit – The qubit to get the input node index of.

Returns

The input node of the qubit wire.

qk_dag_qubit_out_node

uint32_t qk_dag_qubit_out_node(const QkDag *dag, uint32_t qubit)

Retrieve the index of the output node of the wire corresponding to the given qubit.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • qubit – The qubit to get the output node index of.

Returns

The output node of the qubit wire.

qk_dag_clbit_in_node

uint32_t qk_dag_clbit_in_node(const QkDag *dag, uint32_t clbit)

Retrieve the index of the input node of the wire corresponding to the given clbit.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • clbit – The clbit to get the input node index of.

Returns

The input node of the clbit wire.

qk_dag_clbit_out_node

uint32_t qk_dag_clbit_out_node(const QkDag *dag, uint32_t clbit)

Retrieve the index of the output node of the wire corresponding to the given clbit.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • clbit – The clbit to get the output node index of.

Returns

The output node of the clbit wire.

qk_dag_wire_node_value

uint32_t qk_dag_wire_node_value(const QkDag *dag, uint32_t node)

Retrieve the value of a wire endpoint node.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The endpoint node to get the wire value of.

Returns

The value (e.g. qubit, clbit, or var) within the endpoint node.

qk_dag_op_node_num_qubits

uint32_t qk_dag_op_node_num_qubits(const QkDag *dag, uint32_t node)

Gets the number of qubits of the specified operation node.

Panics if the node is not an operation.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The operation node to get the number of qubits of.

Returns

The number of qubits of the operation.

qk_dag_op_node_num_clbits

uint32_t qk_dag_op_node_num_clbits(const QkDag *dag, uint32_t node)

Gets the number of clbits of the specified operation node.

Panics if the node is not an operation.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The operation node to get the number of clbits of.

Returns

The number of clbits of the operation.

qk_dag_op_node_num_params

uint32_t qk_dag_op_node_num_params(const QkDag *dag, uint32_t node)

Gets the number of params of the specified operation node.

Panics if the node is not an operation.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The operation node to get the number of params of.

Returns

The number of params of the operation.

qk_dag_op_node_qubits

const uint32_t *qk_dag_op_node_qubits(const QkDag *dag, uint32_t node)

Retrieve the qubits of the specified operation node.

Panics if the node is not an operation.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The operation node to get the qubits of.

Returns

A pointer to the qubits. Use qk_dag_op_node_num_qubits to determine the number of elements.

qk_dag_op_node_clbits

const uint32_t *qk_dag_op_node_clbits(const QkDag *dag, uint32_t node)

Retrieve the clbits of the specified operation node.

Panics if the node is not an operation.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The operation node to get the clbits of.

Returns

A pointer to the clbits. Use qk_dag_op_node_num_clbits to determine the number of elements.

qk_dag_apply_gate

uint32_t qk_dag_apply_gate(QkDag *dag, QkGate gate, const uint32_t *qubits, const double *params, bool front)

Apply a QkGate to the DAG.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
 
uint32_t qubit[1] = {0};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
 
qk_dag_free(dag);
qk_quantum_register_free(qr);

Safety

The qubits and params types are expected to be a pointer to an array of uint32_t and double respectively where the length is matching the expectations for the standard gate. If the array is insufficiently long the behavior of this function is undefined as this will read outside the bounds of the array. It can be a null pointer if there are no qubits or params for a given gate. You can check qk_gate_num_qubits and qk_gate_num_params to determine how many qubits and params are required for a given gate.

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG to apply the gate to.
  • gate – The StandardGate to apply.
  • qubits – The pointer to the array of uint32_t qubit indices to add the gate on. This can be a null pointer if there are no qubits for gate (e.g. QkGate_GlobalPhase).
  • params – The pointer to the array of double values to use for the gate parameters. This can be a null pointer if there are no parameters for gate (e.g. QkGate_H).
  • front – If true, the gate is applied as the first operation on the specified qubits, rather than as the last.

Returns

The index of the newly added operation node.

qk_dag_apply_measure

uint32_t qk_dag_apply_measure(QkDag *dag, uint32_t qubit, uint32_t clbit, bool front)

Apply a measure to a DAG.

Example

Measure all qubits into the corresponding clbit index at the end of the circuit.

uint32_t num_qubits = qk_dag_num_qubits(dag);
for (uint32_t i = 0; i < num_qubits; i++) {
    qk_dag_apply_measure(dag, i, i, false);
}

Safety

Behavior is undefined if dag is not an aligned, non-null pointer to a valid QkDag, or if qubit or clbit are out of range.

Parameters

  • dag – The circuit to apply to.
  • qubit – The qubit index to measure.
  • clbit – The clbit index to store the result in.
  • front – Whether to apply the measure at the start of the circuit. Usually false.

Returns

The node index of the created instruction.

qk_dag_apply_reset

uint32_t qk_dag_apply_reset(QkDag *dag, uint32_t qubit, bool front)

Apply a reset to the DAG.

Examples

Apply initial resets on all qubits.

uint32_t num_qubits = qk_dag_num_qubits(dag);
for (uint32_t qubit = 0; qubit < num_qubits; qubit++) {
    qk_dag_apply_reset(dag, qubit, true);
}

Safety

Behavior is undefined if dag is not an aligned, non-null pointer to a valid QkDag, or if qubit is out of range.

Parameters

  • dag – The circuit to apply to.
  • qubit – The qubit index to reset.
  • front – Whether to apply the reset at the start of the circuit. Usually false.

Returns

The node index of the created instruction.

qk_dag_apply_barrier

uint32_t qk_dag_apply_barrier(QkDag *dag, const uint32_t *qubits, uint32_t num_qubits, bool front)

Apply a barrier to the DAG.

Examples

Apply a final barrier on all qubits:

qk_dag_apply_barrier(dag, NULL, qk_dag_num_qubits(dag), false);

Apply a barrier at the beginning of a circuit on specified qubit indices:

uint32_t qubits[] = {0, 2, 4, 5};
uint32_t num_qubits = sizeof(qubits) / sizeof(qubits[0]);
qk_dag_apply_barrier(dag, qubits, num_qubits, true);

Safety

Behavior is undefined if:

  • dag is not an aligned, non-null pointer to a valid QkDag,
  • qubits is not aligned or is not valid for num_qubits reads of initialized, in-bounds and unduplicated indices, unless qubits is null.

Parameters

  • dag – The circuit to apply to.
  • qubits – The qubit indices to apply the barrier to. This can be null, in which case num_qubits is not read, and the barrier is applied to all qubits in the DAG.
  • num_qubits – How many qubits the barrier applies to.
  • front – Whether to apply the barrier at the start of the circuit. Usually false.

Returns

The node index of the created instruction.

qk_dag_apply_unitary

uint32_t qk_dag_apply_unitary(QkDag *dag, const QkComplex64 *matrix, const uint32_t *qubits, uint32_t num_qubits, bool front)

Apply a unitary gate to a DAG.

The values in matrix should form a row-major unitary matrix of the correct size for the number of qubits. The data is copied out of the pointer, and only needs to be valid for reads until this function returns.

See :Circuit conventions for detail on the bit-labelling and matrix conventions of Qiskit.

Safety

Behavior is undefined if any of:

  • dag is not an aligned, non-null pointer to a valid QkDag,
  • matrix is not an aligned pointer to 4**num_qubits initialized values,
  • qubits is not an aligned pointer to num_qubits initialized values.

Parameters

  • dag – The circuit to apply to.
  • matrix – An initialized row-major unitary matrix of total size 4**num_qubits.
  • qubits – An array of distinct uint32_t indices of the qubits.
  • num_qubits – The number of qubits the gate applies to.
  • front – Whether to apply the gate at the start of the circuit. Usually false.

Returns

The node index of the created instruction.

qk_dag_op_node_gate_op

QkGate qk_dag_op_node_gate_op(const QkDag *dag, uint32_t node, double *out_params)

Retrieve the standard gate of the specified node.

Panics if the node is not a standard gate operation.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
 
uint32_t qubit[1] = {0};
uint32_t h_gate_idx = qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
 
QkGate gate = qk_dag_op_node_gate_op(dag, h_gate_idx, NULL);
 
qk_dag_free(dag);
qk_quantum_register_free(qr);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag. If out_params is non-NULL, it must point to a buffer large enough to hold all the gate’s params, otherwise behavior is undefined as this function will write beyond its bounds. You can check qk_dag_op_node_num_params to determine how many params are required for any given operation node.

Parameters

  • dag – A pointer to the DAG.
  • node – The operation node to get the standard gate of.
  • out_params – A buffer to be filled with the gate’s params or NULL if they’re not wanted.

Returns

The gate value.

qk_dag_op_node_unitary

void qk_dag_op_node_unitary(const QkDag *dag, uint32_t node, QkComplex64 *out)

Copy out the unitary matrix of the corresponding node index.

Panics if the node is not a unitary gate.

Safety

Behavior is undefined if dag is not a non-null pointer to a valid QkDag, if out is unaligned, or if out is not valid for 4**num_qubits writes of QkComplex64.

Parameters

  • dag – The circuit to read from.
  • node – The node index of the unitary matrix instruction.
  • out – Allocated and aligned memory for 4**num_qubits complex values in row-major order, where num_qubits is the number of qubits the gate applies to.

qk_dag_op_node_kind

QkOperationKind qk_dag_op_node_kind(const QkDag *dag, uint32_t node)

Get the “kind” of an operation node.

The result can be used in a switch statement to dispatch proper handling when iterating over operation nodes.

Panics if node is not an operation node.

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The operation node to get the “kind” of.

Returns

The “kind” of the node.

qk_dag_successors

QkDagNeighbors qk_dag_successors(const QkDag *dag, uint32_t node)

Retrieve the successors of the specified node.

The successors array and its length are returned as a QkDagNeighbors struct, where each element in the array corresponds to a DAG node index. You must call the qk_dag_neighbors_clear function when done to free the memory allocated for the struct.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
qk_quantum_register_free(qr);
 
uint32_t node_cx = qk_dag_apply_gate(dag, QkGate_CX, (uint32_t[]){0, 1}, NULL, false);
 
QkDagNeighbors successors = qk_dag_successors(dag, node_cx);
 
qk_dag_neighbors_clear(&successors);
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The node to get the successors of.

Returns

An instance of the QkDagNeighbors struct with the successors information.

qk_dag_predecessors

QkDagNeighbors qk_dag_predecessors(const QkDag *dag, uint32_t node)

Retrieve the predecessors of the specified node.

The predecessors array and its length are returned as a QkDagNeighbors struct, where each element in the array corresponds to a DAG node index. You must call the qk_dag_neighbors_clear function when done to free the memory allocated for the struct.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
qk_quantum_register_free(qr);
 
uint32_t node_cx = qk_dag_apply_gate(dag, QkGate_CX, (uint32_t[]){0, 1}, NULL, false);
 
QkDagNeighbors predecessors = qk_dag_predecessors(dag, node_cx);
 
qk_dag_neighbors_clear(&predecessors);
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The node to get the predecessors of.

Returns

An instance of the QkDagNeighbors struct with the predecessors information.

qk_dag_neighbors_clear

void qk_dag_neighbors_clear(QkDagNeighbors *neighbors)

Clear the fields of the input QkDagNeighbors struct.

The function deallocates the memory pointed to by the neighbors field and sets it to NULL. It also sets the num_neighbors field to 0.

Safety

Behavior is undefined if neighbors is not a valid, non-null pointer to a QkDagNeighbors object populated with either qk_dag_successors or qk_dag_predecessors.

Parameters

  • neighbors – A pointer to a QkDagNeighbors object.

qk_dag_get_instruction

void qk_dag_get_instruction(const QkDag *dag, uint32_t index, QkCircuitInstruction *instruction)

Return the details for an instruction in the circuit.

This is a mirror of qk_circuit_get_instruction. You can also use individual methods such as qk_dag_op_node_gate_op to get individual properties.

You must call qk_circuit_instruction_clear to reset the QkCircuitInstruction before reusing it or dropping it.

Examples

Iterate through a DAG to find which qubits have measures on them:

bool *measured = calloc(qk_dag_num_qubits(dag), sizeof(*measured));
uint32_t num_ops = qk_dag_num_op_nodes(dag);
uint32_t *ops = malloc(num_ops * sizeof(*ops));
qk_dag_topological_op_nodes(dag, ops);
 
// Storage space for the instruction.
QkCircuitInstruction inst;
for (uint32_t i = 0; i < num_ops; i++) {
    qk_dag_get_instruction(dag, ops[i], &inst);
    if (!strcmp(inst.name, "measure"))
        measured[inst.qubits[0]] = true;
    qk_circuit_instruction_clear(&inst);
}
 
free(ops);
free(measured);

Safety

Behavior is undefined if either dag or instruction are not valid, aligned, non-null pointers to the relevant data type. The fields of instruction need not be initialized.

Parameters

  • dag – The circuit to retrieve the instruction from.
  • index – The node index. It is an error to pass an index that is node a valid op node.
  • instruction – A point to where to write out the QkCircuitInstruction.

qk_dag_compose

QkExitCode qk_dag_compose(QkDag *dag, const QkDag *other, const uint32_t *qubits, const uint32_t *clbits)

Compose the other DAG onto the dag instance with the option of a subset of input wires of other being mapped onto a subset of output wires of dag.

other may include a smaller or equal number of wires for each type.

Example

// Build the following dag
// rqr_0: ──■───────
//          │  ┌───┐
// rqr_1: ──┼──┤ Y ├
//        ┌─┴─┐└───┘
// rqr_2: ┤ X ├─────
//        └───┘
QkDag *dag_right = qk_dag_new();
QkQuantumRegister *rqr = qk_quantum_register_new(3, "rqr");
qk_dag_add_quantum_register(dag_right, rqr);
qk_dag_add_classical_register(dag_right, rcr);
qk_dag_apply_gate(dag_right, QkGate_CX, (uint32_t[]){0, 2}, NULL, false);
qk_dag_apply_gate(dag_right, QkGate_Y, (uint32_t[]){1}, NULL, false);
 
// Build the following dag
//          ┌───┐
// lqr_0: ──┤ H ├───
//        ┌─┴───┴──┐
// lqr_1: ┤ P(0.1) ├
//        └────────┘
QkDag *dag_left = qk_dag_new();
QkQuantumRegister *lqr = qk_quantum_register_new(2, "lqr");
qk_dag_add_quantum_register(dag_left, lqr);
qk_dag_add_classical_register(dag_left, lcr);
qk_dag_apply_gate(dag_left, QkGate_H, (uint32_t[]){0}, NULL, false);
qk_dag_apply_gate(dag_left, QkGate_Phase, (uint32_t[]){1}, (double[]){0.1}, false);
 
// Compose left circuit onto right circuit
// Should result in circuit
//             ┌───┐
// rqr_0: ──■──┤ H ├──────────
//          │  ├───┤┌────────┐
// rqr_1: ──┼──┤ Y ├┤ P(0.1) ├
//        ┌─┴─┐└───┘└────────┘
// rqr_2: ┤ X ├───────────────
//        └───┘
qk_dag_compose(dag_right, dag_left, NULL, NULL);
 
// Clean up after you're done
qk_dag_free(dag_left);
qk_dag_free(dag_right);
qk_quantum_register_free(lqr);
qk_quantum_register_free(rqr);

Safety

Behavior is undefined if dag or other are not valid, non-null pointers to a QkDag. If qubit nor clbit are NULL, it must contains a less or equal amount than what the circuit owns.

Parameters

  • dag – A pointer to the DAG to be composed on.
  • other – A pointer to the DAG to compose with dag.
  • qubits – A list of indices representing the qubit wires to compose onto.
  • clbits – A list of indices representing the clbit wires to compose onto.

Returns

QkExitCode_Success upon successful decomposition, otherwise a DAG-specific error code indicating the cause of the failure.

qk_dag_free

void qk_dag_free(QkDag *dag)

Free the DAG.

Example

QkDag *dag = qk_dag_new();
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not either null or a valid pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG to free.

qk_dag_to_circuit

QkCircuit *qk_dag_to_circuit(const QkDag *dag)

Convert a given DAG to a circuit.

The new circuit is copied from the DAG; the original dag reference is still owned by the caller and still required to be freed with qk_dag_free. You must free the returned circuit with qk_circuit_free when done with it.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
qk_quantum_register_free(qr);
 
QkCircuit *qc = qk_dag_to_circuit(dag);
 
qk_circuit_free(qc);
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG from which to create the circuit.

Returns

A pointer to the new circuit.

qk_dag_topological_op_nodes

void qk_dag_topological_op_nodes(const QkDag *dag, uint32_t *out_order)

Return the operation nodes in the DAG listed in topological order.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
 
uint32_t qubit[1] = {0};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
qk_dag_apply_gate(dag, QkGate_S, qubit, NULL, false);
 
// get the number of operation nodes
uint32_t num_ops = qk_dag_num_op_nodes(dag); // 2
uint32_t *out_order = malloc(sizeof(uint32_t) * num_ops);
 
// get operation nodes listed in topological order
qk_dag_topological_op_nodes(dag, out_order);
 
// do something with the ordered nodes
for (uint32_t i = 0; i < num_ops; i++) {
    QkGate gate = qk_dag_op_node_gate_op(dag, out_order[i], NULL);
    printf("The gate at location %u is %u.\n", i, gate);
}
 
// free the out_order array, register, and dag pointer when done
free(out_order);
qk_quantum_register_free(qr);
qk_dag_free(dag);

Safety

Behavior is undefined if dag is not a valid, non-null pointer to a QkDag or if out_order is not a valid, non-null pointer to a sequence of qk_dag_num_op_nodes(dag) consecutive elements of uint32_t.

Parameters

  • dag – A pointer to the DAG.
  • out_order – A pointer to an array of qk_dag_num_op_nodes(dag) elements of type uint32_t, where this function will write the output to.

qk_dag_substitute_node_with_dag

void qk_dag_substitute_node_with_dag(QkDag *dag, uint32_t node, const QkDag *replacement)

Replace a node in a QkDag with a subcircuit specfied by another QkDag

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
 
uint32_t qubit[1] = {0};
uint32_t node_to_replace = qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
qk_dag_apply_gate(dag, QkGate_S, qubit, NULL, false);
 
// Build replacement dag for H
QkDag *replacement = qk_dag_new();
QkQuantumRegister *replacement_qr = qk_quantum_register_new(1, "other");
qk_dag_add_quantum_register(replacement, replacement_qr);
double pi_param[1] = {3.14159};
qk_dag_apply_gate(replacement, QkGate_RZ, qubit, pi_param, false);
qk_dag_apply_gate(replacement, QkGate_SX, qubit, NULL, false);
qk_dag_apply_gate(replacement, QkGate_RZ, qubit, pi_param, false);
 
qk_dag_substitute_node_with_dag(dag, node_to_replace, replacement);
 
// Free the replacement dag, register, dag, and register
qk_quantum_register_free(replacement_qr);
qk_dag_free(replacement);
qk_quantum_register_free(qr);
qk_dag_free(dag);

Safety

Behavior is undefined if dag and replacement are not a valid, non-null pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG.
  • node – The node index of the operation to replace with the other QkDag. This must be the node index for an operation node in dag and the qargs and cargs count must match the number of qubits and clbits in replacement.
  • replacement – The other QkDag to replace node with. This dag must have the same number of qubits as the operation for node. The node bit ordering will be ordering will be handled in order, so qargs[0] for node will be mapped to qubits[0] in replacement, qargs[1] to qubits[0], etc. The same pattern applies to classical bits too.

qk_dag_copy_empty_like

QkDag *qk_dag_copy_empty_like(const QkDag *dag, QkVarsMode vars_mode, QkBlocksMode blocks_mode)

Return a copy of self with the same structure but empty.

That structure includes:

  • name and other metadata
  • global phase
  • duration
  • all the qubits and clbits, including the registers.

Example

QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "my_register");
qk_dag_add_quantum_register(dag, qr);
 
uint32_t qubit[1] = {0};
qk_dag_apply_gate(dag, QkGate_H, qubit, NULL, false);
 
// As the DAG does not contain any control-flow instructions,
// vars_mode and blocks_mode do not have any effect.
QkDag *copied_dag = qk_dag_copy_empty_like(dag, QkVarsMode_Alike, QkBlocksMode_Drop);
uint32_t num_ops_in_copied_dag = qk_dag_num_op_nodes(copied_dag); // 0
 
// do something with copied_dag
 
qk_quantum_register_free(qr);
qk_dag_free(dag);
qk_dag_free(copied_dag);

Safety

Behavior is undefined if dag is not a valid pointer to a QkDag.

Parameters

  • dag – A pointer to the DAG to copy.
  • vars_mode – The mode for handling classical variables.
  • blocks_mode – The mode for handling blocks.

Returns

The pointer to the copied DAG circuit.

Was this page helpful?
Report a bug, typo, or request content on GitHub.