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:
#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 forgate
(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 forgate
(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 aQkCircuit
matrix
is a pointer to a nested array ofQkComplex64
of dimension2 ^ num_qubits x 2 ^ num_qubits
qubits
is a pointer tonum_qubits
readable element of typeuint32_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 dimension2 ^ num_qubits x 2 ^ num_qubits
. More explicitly: the(i, j)
-th element is given bymatrix[i * 2^n + j]
. The contents ofmatrix
are copied inside this function before being added to the circuit, so caller keeps ownership of the original memory thatmatrix
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.