Skip to main content
IBM Quantum Platform

QkCircuit

typedef struct QkCircuit QkCircuit

The fundamental element of quantum computing is the quantum circuit. This is a computational routine that can be run, one shot at a time, on a quantum processing unit (QPU). A circuit will act on a predefined amount of quantum data (in Qiskit, we only directly support qubits) with unitary operations (gates), measurements and resets. In addition, a quantum circuit can contain operations on classical data, including real-time computations and control-flow constructs, which are executed by the controllers of the QPU. The QkCircuit struct exposes a low level interface to Qiskit’s quantum circuit data structure and 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 QuantumCircuit class.

Below is an example of a quantum circuit that makes a three-qubit Greenberger–Horne–Zeilinger (GHZ) state defined as:

ψ=(000+111)/2|\psi\rangle = \left( |000\rangle + |111\rangle \right) / \sqrt{2}
#include <qiskit.h>
 
// Create a circuit with three qubits and 3 classical bits
QkCircuit *qc = qk_circuit_new(3, 0);
// H gate on qubit 0, putting this qubit in a superposition of |0> + |1>.
qk_circuit_gate(qc, QkGate_H, {0}, NULL);
// A CX (CNOT) gate on control qubit 0 and target qubit 1 generating a Bell state.
qk_circuit_gate(qc, QkGate_CX, {0, 1}, NULL);
// A CX (CNOT) gate on control qubit 0 and target qubit 2 generating a GHZ state.
qk_circuit_gate(qc, QkGate_CX, {0, 2}, NULL);
// Free the created circuit.
qk_circuit_free(qc);

The circuit C API currently only supports creating circuits 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

QkOpCount

struct QkOpCount

An individual operation count represented by the operation name and the number of instances in the circuit.

const char *name

A nul terminated string representing the operation name

uintptr_t count

The number of instances of this operation in the circuit

QkOpCounts

struct QkOpCounts

An array of OpCount objects representing the total counts of all the operation types in a circuit.

QkOpCount *data

A array of size len containing OpCount objects for each type of operation in the circuit

uintptr_t len

The number of elements in data

QkCircuitInstruction

struct QkCircuitInstruction

A circuit instruction representation.

This struct represents the data contained in an individual instruction in a QkCircuit. It is not a pointer to the underlying object, but contains a copy of the properties of the instruction for inspection.

const char *name

The instruction name

uint32_t *qubits

A pointer to an array of qubit indices this instruction operates on.

uint32_t *clbits

A pointer to an array of clbit indices this instruction operates on.

double *params

A pointer to an array of parameter values for this instruction.

uint32_t num_qubits

The number of qubits for this instruction.

uint32_t num_clbits

The number of clbits for this instruction.

uint32_t num_params

The number of parameters for this instruction.


Functions

QkDelayUnit

enum QkDelayUnit

Units for circuit delays.

Values:

enumerator QkDelayUnit_S

Seconds.

enumerator QkDelayUnit_MS

Milliseconds.

enumerator QkDelayUnit_US

Microseconds.

enumerator QkDelayUnit_NS

Nanoseconds.

enumerator QkDelayUnit_PS

Picoseconds.

qk_circuit_new

QkCircuit *qk_circuit_new(uint32_t num_qubits, uint32_t num_clbits)

Construct a new circuit with the given number of qubits and clbits.

Example

QkCircuit *empty = qk_circuit_new(100, 100);

Parameters

  • num_qubits – The number of qubits the circuit contains.
  • num_clbits – The number of clbits the circuit contains.

Returns

A pointer to the created circuit.

qk_circuit_add_quantum_register

void qk_circuit_add_quantum_register(QkCircuit *circuit, const QkQuantumRegister *reg)

Add a quantum register to a given quantum circuit

Example

QkCircuit *qc = qk_circuit_new(0, 0);
QkQuantumRegister *qr = qk_quantum_register_new(1024, "my_little_register");
qk_circuit_add_quantum_register(qc, qr);
qk_quantum_register_free(qr);
qk_circuit_free(qc)

Safety

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

Parameters

  • circuit – A pointer to the circuit.
  • reg – A pointer to the quantum register

qk_circuit_add_classical_register

void qk_circuit_add_classical_register(QkCircuit *circuit, const QkClassicalRegister *reg)

Add a classical register to a given quantum circuit

Example

QkCircuit *qc = qk_circuit_new(0, 0);
QkClassicalRegister *cr = qk_classical_register_new(24, "my_big_register");
qk_circuit_add_classical_register(qc, cr);
qk_classical_register_free(cr);
qk_circuit_free(qc)

Safety

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

Parameters

  • circuit – A pointer to the circuit.
  • reg – A pointer to the classical register

qk_circuit_copy

QkCircuit *qk_circuit_copy(const QkCircuit *circuit)

Create a copy of a QkCircuit.

Example

QkCircuit *qc = qk_circuit_new(100, 100);
QkCircuit *copy = qk_circuit_copy(qc);

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

circuit – A pointer to the circuit to copy.

Returns

A new pointer to a copy of the input circuit.

qk_circuit_num_qubits

uint32_t qk_circuit_num_qubits(const QkCircuit *circuit)

Get the number of qubits the circuit contains.

Example

QkCircuit *qc = qk_circuit_new(100, 100);
uint32_t num_qubits = qk_circuit_num_qubits(qc);  // num_qubits==100

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

circuit – A pointer to the circuit.

Returns

The number of qubits the circuit is defined on.

qk_circuit_num_clbits

uint32_t qk_circuit_num_clbits(const QkCircuit *circuit)

Get the number of clbits the circuit contains.

Example

QkCircuit *qc = qk_circuit_new(100, 50);
uint32_t num_clbits = qk_circuit_num_clbits(qc);  // num_clbits==50

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

circuit – A pointer to the circuit.

Returns

The number of qubits the circuit is defined on.

qk_circuit_free

void qk_circuit_free(QkCircuit *circuit)

Free the circuit.

Example

QkCircuit *qc = qk_circuit_new(100, 100);
qk_circuit_free(qc);

Safety

Behavior is undefined if circuit is not either null or a valid pointer to a QkCircuit.

Parameters

circuit – A pointer to the circuit to free.

qk_circuit_gate

QkExitCode qk_circuit_gate(QkCircuit *circuit, QkGate gate, const uint32_t *qubits, const double *params)

Append a QkGate to the circuit.

Example

QkCircuit *qc = qk_circuit_new(100, 0);
uint32_t qubit[1] = {0};
qk_circuit_gate(qc, QkGate_H, qubit, NULL);

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 insufficently 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 circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

  • circuit – A pointer to the circuit to add the gate to.
  • gate – The StandardGate to add to the circuit.
  • 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).

Returns

An exit code.

qk_gate_num_qubits

uint32_t qk_gate_num_qubits(QkGate gate)

Get the number of qubits for a QkGate.

Example

uint32_t num_qubits = qk_gate_num_qubits(QkGate_CCX);

Parameters

gate – The QkGate to get the number of qubits for.

Returns

The number of qubits the gate acts on.

qk_gate_num_params

uint32_t qk_gate_num_params(QkGate gate)

Get the number of parameters for a QkGate.

Example

uint32_t num_params = qk_gate_num_params(QkGate_R);

Parameters

gate – The QkGate to get the number of qubits for.

Returns

The number of parameters the gate has.

qk_circuit_measure

QkExitCode qk_circuit_measure(QkCircuit *circuit, uint32_t qubit, uint32_t clbit)

Append a measurement to the circuit

Example

QkCircuit *qc = qk_circuit_new(100, 1);
qk_circuit_measure(qc, 0, 0);

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

  • circuit – A pointer to the circuit to add the measurement to
  • qubit – The uint32_t for the qubit to measure
  • clbit – The uint32_t for the clbit to store the measurement outcome in

Returns

An exit code.

qk_circuit_reset

QkExitCode qk_circuit_reset(QkCircuit *circuit, uint32_t qubit)

Append a reset to the circuit

Example

QkCircuit *qc = qk_circuit_new(100, 0);
qk_circuit_reset(qc, 0);

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

  • circuit – A pointer to the circuit to add the reset to
  • qubit – The uint32_t for the qubit to reset

Returns

An exit code.

qk_circuit_barrier

QkExitCode qk_circuit_barrier(QkCircuit *circuit, const uint32_t *qubits, uint32_t num_qubits)

Append a barrier to the circuit.

Example

QkCircuit *qc = qk_circuit_new(100, 1);
uint32_t qubits[5] = {0, 1, 2, 3, 4};
qk_circuit_barrier(qc, qubits, 5);

Safety

The length of the array qubits points to must be num_qubits. If there is a mismatch the behavior is undefined.

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

  • circuit – A pointer to the circuit to add the barrier to.
  • num_qubits – The number of qubits wide the barrier is.
  • qubits – The pointer to the array of uint32_t qubit indices to add the barrier on.

Returns

An exit code.

qk_circuit_unitary

QkExitCode qk_circuit_unitary(QkCircuit *circuit, const QkComplex64 *matrix, const uint32_t *qubits, uint32_t num_qubits, bool check_input)

Append an arbitrary unitary matrix to the circuit.

Example

QkComplex64 c0 = qk_complex64_from_native(0);  // 0+0i
QkComplex64 c1 = qk_complex64_from_native(1);  // 1+0i
 
const uint32_t num_qubits = 1;
const uint32_t dim = 2;
QkComplex64[dim * dim] unitary = {c0, c1,  // row 0
                                  c1, c0}; // row 1
 
QkCircuit *circuit = qk_circuit_new(1, 0);  // 1 qubit circuit
uint32_t qubit = {0};  // qubit to apply the unitary on
qk_circuit_unitary(circuit, unitary, qubit, num_qubits);

Safety

Behavior is undefined if any of the following is violated:

  • circuit is a valid, non-null pointer to a QkCircuit
  • matrix is a pointer to a nested array of QkComplex64 of dimension 2 ^ num_qubits x 2 ^ num_qubits
  • qubits is a pointer to num_qubits readable element of type uint32_t

Parameters

  • circuit – A pointer to the circuit to append the unitary to.
  • matrix – A pointer to the QkComplex64 array representing the unitary matrix. This must be a row-major, unitary matrix of dimension 2 ^ num_qubits x 2 ^ num_qubits. More explicitly: the (i, j)-th element is given by matrix[i * 2^n + j]. The contents of matrix are copied inside this function before being added to the circuit, so caller keeps ownership of the original memory that matrix points to and can reuse it after the call and the caller is responsible for freeing it.
  • qubits – A pointer to array of qubit indices, of length num_qubits.
  • num_qubits – The number of qubits the unitary acts on.
  • check_input – When true, the function verifies that the matrix is unitary. If set to False the caller is responsible for ensuring the matrix is unitary, if the matrix is not unitary this is undefined behavior and will result in a corrupt circuit.

qk_circuit_count_ops

QkOpCounts qk_circuit_count_ops(const QkCircuit *circuit)

Return a list of string names for instructions in a circuit and their counts.

Example

QkCircuit *qc = qk_circuit_new(100, 0);
uint32_t qubit[1] = {0};
qk_circuit_gate(qc, QkGate_H, qubits, NULL);
QkOpCounts counts = qk_circuit_count_ops(qc);

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

circuit – A pointer to the circuit to get the counts for.

Returns

An OpCounts struct containing the circuit operation counts.

qk_circuit_num_instructions

uintptr_t qk_circuit_num_instructions(const QkCircuit *circuit)

Return the total number of instructions in the circuit.

Example

QkCircuit *qc = qk_circuit_new(100, 0);
uint32_t qubit[1] = {0};
qk_circuit_gate(qc, QkGate_H, qubit, NULL);
size_t num = qk_circuit_num_instructions(qc); // 1

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

circuit – A pointer to the circuit to get the total number of instructions for.

Returns

The total number of instructions in the circuit.

qk_circuit_get_instruction

void qk_circuit_get_instruction(const QkCircuit *circuit, uintptr_t index, QkCircuitInstruction *instruction)

Return the instruction details for an instruction in the circuit.

This function is used to get the instruction details for a given instruction in the circuit.

Example

QkCircuitInstruction *inst = malloc(sizeof(QkCircuitInstruction));
QkCircuit *qc = qk_circuit_new(100);
uint32_t qubit[1] = {0};
qk_circuit_gate(qc, QkGate_H, qubit, NULL);
QkCircuitInstruction inst = qk_circuit_get_instruction(qc, 0);

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit. The value for index must be less than the value returned by qk_circuit_num_instructions otherwise this function will panic. Behavior is undefined if instruction is not a valid, non-null pointer to a memory allocation with sufficient space for a QkCircuitInstruction.

Parameters

  • circuit – A pointer to the circuit to get the instruction details for.
  • index – The instruction index to get the instruction details of.
  • instruction – A pointer to where to write out the QkCircuitInstruction

qk_circuit_instruction_clear

void qk_circuit_instruction_clear(const QkCircuitInstruction *inst)

Clear the data in circuit instruction object.

This function doesn’t free the allocation for the provided QkCircuitInstruction pointer, it only frees the internal allocations for the data contained in the instruction. You are responsible for allocating and freeing the actual allocation used to store a QkCircuitInstruction.

Example

QkCircuitInstruction *inst = malloc(sizeof(QkCircuitInstruction));
QkCircuit *qc = qk_circuit_new(100);
uint32_t q0 = {0};
qk_circuit_gate(qc, QkGate_H, q0, NULL);
qk_circuit_get_instruction(qc, 0, inst);
qk_circuit_instruction_clear(inst); // free the data
free(inst); // free the pointer
qk_circuit_free(qc); // free the circuit

Safety

Behavior is undefined if inst is not a valid, non-null pointer to a QkCircuitInstruction.

Parameters

inst – A pointer to the instruction to free.

qk_opcounts_free

void qk_opcounts_free(QkOpCounts op_counts)

Free a circuit op count list.

Safety

Behavior is undefined if op_counts is not the object returned by qk_circuit_count_ops.

Parameters

op_counts – The returned op count list from qk_circuit_count_ops.

qk_circuit_to_python

PyObject *qk_circuit_to_python(QkCircuit *circuit)

Convert to a Python-space QuantumCircuit.

This function takes ownership of the pointer and gives it to Python. Using the input circuit pointer after it’s passed to this function is undefined behavior. In particular, qk_circuit_free should not be called on this pointer anymore.

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit

It is assumed that the thread currently executing this function holds the Python GIL. This is required to create the Python object returned by this function.

Parameters

circuit – The C-space QkCircuit pointer.

Returns

A Python QuantumCircuit object.

qk_circuit_delay

QkExitCode qk_circuit_delay(QkCircuit *circuit, uint32_t qubit, double duration, QkDelayUnit unit)

Append a delay instruction to the circuit.

Example

QkCircuit *qc = qk_circuit_new(1, 0);
qk_circuit_delay(qc, 0, 100.0, QkDelayUnit_NS);

Safety

Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.

Parameters

  • circuit – A pointer to the circuit to add the delay to.
  • qubit – The uint32_t index of the qubit to apply the delay to.
  • duration – The duration of the delay.
  • unit – An enum representing the unit of the duration.

Returns

An exit code.

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