QkCircuit
typedef struct QkCircuit QkCircuitThe 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, (uint32_t[]){0}, NULL);
// A CX (CNOT) gate on control qubit 0 and target qubit 1 generating a Bell state.
qk_circuit_gate(qc, QkGate_CX, (uint32_t[]){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, (uint32_t[]){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
size_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
size_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.
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.
QkParam **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.
QkCircuitDrawerConfig
struct QkCircuitDrawerConfig
The configuration options for the qk_circuit_draw function.
bool bundle_cregs
If true, bundles classical registers into single wires.
bool merge_wires
If true, merges the bottom and top lines of adjacent wires.
size_t fold
Sets the line length for wrapping the rendered text. Use 0 to auto-detect console width. Use SIZE_MAX to effectively skip wrapping altogether.
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.
QkVarsMode
enum QkVarsMode
The mode to copy the classical variables, for operations that create a new circuit based on an existing one.
Values:
enumerator QkVarsMode_Alike
Each variable has the same type it had in the input.
enumerator QkVarsMode_Captures
Each variable becomes a “capture”.
enumerator QkVarsMode_Drop
Do not copy the variable data.
QkBlocksMode
enum QkBlocksMode
The mode to use to copy blocks in control-flow instructions, for operations that create a new circuit based on an existing one.
Values:
enumerator QkBlocksMode_Drop
Drop the blocks.
enumerator QkBlocksMode_Keep
Keep the blocks.
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_num_quantum_registers
size_t qk_circuit_num_quantum_registers(const QkCircuit *circuit)
Get the number of quantum registers in the circuit.
Returns the number of quantum registers that have been added to the circuit.
Example
QkCircuit *qc = qk_circuit_new(0, 0);
QkQuantumRegister *qr1 = qk_quantum_register_new(2, "qr1");
QkQuantumRegister *qr2 = qk_quantum_register_new(3, "qr2");
qk_circuit_add_quantum_register(qc, qr1);
qk_circuit_add_quantum_register(qc, qr2);
size_t num_qregs = qk_circuit_num_quantum_registers(qc);
printf("Number of quantum registers: %zu\n", num_qregs); // Prints: 2
qk_quantum_register_free(qr1);
qk_quantum_register_free(qr2);
qk_circuit_free(qc);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 quantum registers in the circuit.
qk_circuit_get_quantum_register
const QkQuantumRegister *qk_circuit_get_quantum_register(const QkCircuit *circuit, size_t qreg_idx)
Returns the quantum register at the specified index.
Returns a borrowed pointer to the quantum register at the specified index. The returned pointer is valid as long as the circuit exists and is not modified. The caller should not free the returned pointer.
Example
QkCircuit *qc = qk_circuit_new(0, 0);
QkQuantumRegister *qr1 = qk_quantum_register_new(2, "qr1");
qk_circuit_add_quantum_register(qc, qr1);
const QkQuantumRegister *retrieved = qk_circuit_get_quantum_register(qc, 0);
qk_quantum_register_free(qr1);
qk_circuit_free(qc);Safety
Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit, or if qreg_idx is out of bounds (>= the number of quantum registers in the circuit).
Parameters
- circuit – A pointer to the circuit.
- qreg_idx – The index of the quantum register to retrieve.
Returns
A borrowed pointer to the quantum register at the specified index. Do not free this pointer.
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_num_classical_registers
size_t qk_circuit_num_classical_registers(const QkCircuit *circuit)
Get the number of classical registers in the circuit.
Returns the number of classical registers that have been added to the circuit.
Example
QkCircuit *qc = qk_circuit_new(0, 0);
QkClassicalRegister *cr1 = qk_classical_register_new(2, "cr1");
QkClassicalRegister *cr2 = qk_classical_register_new(3, "cr2");
qk_circuit_add_classical_register(qc, cr1);
qk_circuit_add_classical_register(qc, cr2);
size_t num_cregs = qk_circuit_num_classical_registers(qc);
printf("Number of classical registers: %zu\n", num_cregs); // Prints: 2
qk_classical_register_free(cr1);
qk_classical_register_free(cr2);
qk_circuit_free(qc);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 classical registers in the circuit.
qk_circuit_get_classical_register
const QkClassicalRegister *qk_circuit_get_classical_register(const QkCircuit *circuit, size_t creg_idx)
Returns the classical register at the specified index.
Returns a borrowed pointer to the classical register at the specified index. The returned pointer is valid as long as the circuit exists and is not modified. The caller should not free the returned pointer.
Example
QkCircuit *qc = qk_circuit_new(0, 0);
QkClassicalRegister *cr1 = qk_classical_register_new(2, "cr1");
qk_circuit_add_classical_register(qc, cr1);
const QkClassicalRegister *retrieved = qk_circuit_get_classical_register(qc, 0);
qk_classical_register_free(cr1);
qk_circuit_free(qc);Safety
Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit, or if creg_idx is out of bounds (>= the number of classical registers in the circuit).
Parameters
- circuit – A pointer to the circuit.
- creg_idx – The index of the classical register to retrieve.
Returns
A borrowed pointer to the classical register at the specified index. Do not free this pointer.
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==100Safety
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==50Safety
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 clbits the circuit is defined on.
qk_circuit_num_param_symbols
size_t qk_circuit_num_param_symbols(const QkCircuit *circuit)
Get the number of unbound symbols in QkParam objects in the circuit.
Example
QkCircuit *qc = qk_circuit_new(2, 0);
QkParam *x = qk_param_new_symbol("x");
QkParam *y = qk_param_new_symbol("y");
uint32_t q0[1] = {0};
const QkParam *rx_param[1] = {x};
const QkParam *ry_param[1] = {y};
qk_circuit_parameterized_gate(qc, QkGate_RX, q0, rx_param);
qk_circuit_parameterized_gate(qc, QkGate_RY, q0, ry_param);
// check the number of QkParam symbols
size_t num_symbols = qk_circuit_num_param_symbols(qc); // == 2
qk_param_free(x);
qk_param_free(y);
qk_circuit_free(qc);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 unbound QkParam symbols in the circuit.
qk_circuit_global_phase
QkParam *qk_circuit_global_phase(const QkCircuit *circuit)
Get the global phase of the circuit.
This function returns a copy of the circuit’s global phase and the value must be freed via :c:func:qk_param_free after usage.
Example
QkCircuit *qc = qk_circuit_new(100, 100);
QkParam *phase = qk_circuit_global_phase(qc);
qk_param_free(phase);
qk_circuit_free(qc);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 global phase of the circuit.
qk_circuit_set_global_phase
QkExitCode qk_circuit_set_global_phase(QkCircuit *circuit, const QkParam *phase)
Set the global phase of the circuit.
This function copies the new global phase upon setting it, so the caller retains ownership of the QkParam phase, and the value of the phase must be freed via :c:func:qk_param_free after setting.
Example
QkCircuit *qc = qk_circuit_new(100, 100);
QkParam *new_global_phase = qk_param_from_double(1.23);
qk_circuit_set_global_phase(qc, new_global_phase);
qk_param_free(new_global_phase);
qk_circuit_free(qc);Safety
Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit and if phase is not a valid, non-null pointer to a QkParam.
Parameters
- circuit – A pointer to the circuit.
- phase – A pointer to the global phase to set.
Returns
QkExitCode_Success upon successful setting of the global phase. Upon failure, QkExitCode_ParameterNameConflict indicates that a new parameter symbol has a name conflict with an existing one. QkExitCode_ParameterError describes other generic failures when attempting to track the parameter symbols.
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 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 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_tqubit 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
doublevalues 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_circuit_parameterized_gate
QkExitCode qk_circuit_parameterized_gate(QkCircuit *circuit, QkGate gate, const uint32_t *qubits, const QkParam *const *params)
Append a QkGate with QkParam* parameters to the circuit.
Example
QkCircuit *qc = qk_circuit_new(100, 0);
QkParam *theta = qk_param_new_symbol("theta");
uint32_t qubit[1] = {0};
const QkParam* params[1] = {theta};
qk_circuit_parameterized_gate(qc, QkGate_RX, qubit, params); // add RX(theta) to the circuitSafety
The qubits and params types are expected to be a pointer to an array of uint32_t and QkParam* 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 circuit is not a valid, non-null pointer to a QkCircuit, or if any of the elements in the params array is not a valid, non-null pointer to a QkParam.
Parameters
- circuit – A pointer to the circuit to add the gate to.
- gate – The
QkGateto add to the circuit. - qubits – The pointer to the array of
uint32_tqubit 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
QkParam*parameters to use for the gate parameters. This can be a null pointer if there are no parameters forgate(e.g.QkGate_H).
Returns
QkExitCode_Success upon successful append. Upon failure, QkExitCode_ParameterNameConflict indicates that a new parameter symbol has a name conflict with an existing one. QkExitCode_ParameterError describes other generic failures when attempting to track the parameter symbols.
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
QkGateto 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
QkGateto 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_tfor the qubit to measure - clbit – The
uint32_tfor 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_tfor 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_tqubit 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 = {0, 0}; // 0+0i
QkComplex64 c1 = {1, 0}; // 1+0i
const uint32_t num_qubits = 1;
QkComplex64 unitary[2*2] = {c0, c1, // row 0
c1, c0}; // row 1
QkCircuit *circuit = qk_circuit_new(1, 0); // 1 qubit circuit
uint32_t qubit[1] = {0}; // qubit to apply the unitary on
qk_circuit_unitary(circuit, unitary, qubit, num_qubits, true);Safety
Behavior is undefined if any of the following is violated:
circuitis a valid, non-null pointer to aQkCircuitmatrixis an aligned pointer to4**num_qubitsinitializedQkComplex64valuesqubitsis an aligned pointer tonum_qubitsinitializeduint32_tvalues
Parameters
- circuit – A pointer to the circuit to append the unitary to.
- matrix – A pointer to the
QkComplex64array 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 ofmatrixare copied inside this function before being added to the circuit, so caller keeps ownership of the original memory thatmatrixpoints 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.
Returns
An exit code.
qk_circuit_inst_unitary
void qk_circuit_inst_unitary(QkCircuit *circuit, size_t index, QkComplex64 *out)
Copy out the unitary matrix for a given instruction in the circuit.
Panics if the instruction at the given index is not a unitary.
Safety
Behavior is undefined if any of the following is violated: if circuit is not a valid, non-null pointer to a QkCircuit, if index is out of bounds for the number of instructions in the circuit, if out is not valid for 4**num_qubits writes of QkComplex64.
Parameters
- circuit – A pointer to the circuit to get the unitary from.
- index – The index of the instruction to get the unitary for.
- out – Allocated and aligned pointer to write the unitary matrix to.
qk_circuit_instruction_kind
QkOperationKind qk_circuit_instruction_kind(const QkCircuit *circuit, size_t index)
Get the “kind” of circuit instruction.
Safety
Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit and if index is out of bounds for the number of instructions in the circuit.
Parameters
- circuit – A pointer to the circuit to get the instruction kind from.
- index – The index of the instruction to get the kind for.
Returns
A QkOperationKind enum value representing the kind of instruction at the given index.
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.
To properly free the memory allocated by the struct, you should call qk_opcounts_clear. Dropping the QkOpCounts struct without doing so will leave the stored array of QkOpCount allocated and produce a memory leak.
Example
QkCircuit *qc = qk_circuit_new(100, 0);
uint32_t qubits[1] = {0};
qk_circuit_gate(qc, QkGate_H, qubits, NULL);
QkOpCounts counts = qk_circuit_count_ops(qc);
// .. once done
qk_opcounts_clear(&counts);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 QkOpCounts struct containing the circuit operation counts.
qk_circuit_num_instructions
size_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); // 1Safety
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, size_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.
This function allocates memory internally for the provided QkCircuitInstruction and thus you are responsible for calling qk_circuit_instruction_clear to free it.
Example
QkCircuitInstruction inst;
QkCircuit *qc = qk_circuit_new(100, 0);
uint32_t qubit[1] = {0};
qk_circuit_gate(qc, QkGate_H, qubit, NULL);
qk_circuit_get_instruction(qc, 0, &inst);
qk_circuit_instruction_clear(&inst);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_pauli_product_rotation
void qk_circuit_pauli_product_rotation(QkCircuit *circuit, const QkPauliProductRotation *rotation, const uint32_t *qubits)
Apply a QkPauliProductRotation to a circuit.
Example
// build a IXYZ Pauli rotation
bool x[4] = {false, true, true, false};
bool z[4] = {false, false, true, true};
QkParam *angle = qk_param_from_double(1.0);
QkPauliProductRotation rotation = {x, z, 4, angle};
// append it to a circuit
QkCircuit *circuit = qk_circuit_new(10, 1);
uint32_t qubits[4] = {0, 1, 2, 3};
qk_circuit_pauli_product_rotation(circuit, &rotation, qubits);
// do something with the circuit... and then free it
qk_param_free(angle);
qk_circuit_free(circuit);Safety
Behavior is undefined if any of the following is violated:
circuitis a valid, non-null pointer to aQkCircuitrotationis a valid, non-null pointer to a coherentQkPauliProductRotation. Specifically, therotation->zandrotation->xdata arrays must be readable forrotation->lenelements.qubitsis an aligned pointer torotation->leninitializeduint32_tvalues.
Parameters
- circuit – The circuit to apply the operation to.
- rotation – A pointer to the
QkPauliProductRotationto apply. - qubits – A pointer to the qubit array.
qk_circuit_inst_pauli_product_rotation
QkExitCode qk_circuit_inst_pauli_product_rotation(const QkCircuit *circuit, size_t index, QkPauliProductRotation *instruction)
Get the QkPauliProductRotation data from a circuit instruction.
For a circuit with a QkPauliProductRotation instruction at index index, this function will populate the instruction pointer with a copy of QkPauliProductRotation data. Note that this data lives independently of the circuit and must be freed manually with qk_pauli_product_rotation_clear.
If the instruction at the provided index is not a QkPauliProductRotation, this function will return QkExitCode_InvalidOperationKind error. You can verify that the instruction has the right kind using qk_circuit_instruction_kind.
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 QkPauliProductRotation.
Parameters
- circuit – A pointer to the circuit to retrieve the instruction details from.
- index – The circuit instruction index.
- instruction – A pointer to an allocated
QkPauliProductRotationto store the data.
Returns
QkExitCode_Success if the data was written into the instruction, or QkExitCode_InvalidOperationKind if the index did not point to a QkPauliProductRotation.
qk_circuit_pauli_product_measurement
void qk_circuit_pauli_product_measurement(QkCircuit *circuit, const QkPauliProductMeasurement *measurement, const uint32_t *qubits, uint32_t clbit)
Apply a QkPauliProductMeasurement to a circuit.
Example
// build a XZ Pauli measurement
bool x[2] = {true, false};
bool z[2] = {false, true};
QkPauliProductMeasurement measure = {x, z, 2, false};
// append it to a circuit
QkCircuit *circuit = qk_circuit_new(10, 1);
uint32_t qubits[2] = {0, 2};
uint32_t clbit = 0;
qk_circuit_pauli_product_measurement(circuit, &measure, qubits, clbit);
// do something with the circuit... and then free it
qk_circuit_free(circuit);Safety
Behavior is undefined if any of the following is violated:
circuitis a valid, non-null pointer to aQkCircuitmeasurementis a valid, non-null pointer to a coherentQkPauliProductMeasurement. Specifically, themeasurement->zandmeasurement->xdata arrays must be readable formeasurement->lenelements.qubitsis an aligned pointer torotation->leninitializeduint32_tvalues.
Parameters
- circuit – The circuit to apply the operation to.
- measurement – A pointer to the
QkPauliProductMeasurementto apply. - qubits – A pointer to the qubit array.
- clbit – A single
uint32_tspecifying the measurement qubit.
qk_circuit_inst_pauli_product_measurement
QkExitCode qk_circuit_inst_pauli_product_measurement(const QkCircuit *circuit, size_t index, QkPauliProductMeasurement *instruction)
Get the QkPauliProductMeasurement data from a circuit instruction.
For a circuit with a QkPauliProductMeasurement instruction at index index, this function will populate the instruction pointer with a copy of QkPauliProductMeasurement data. Note that this data lives independently of the circuit must be freed manually with qk_pauli_product_measurement_clear.
If the instruction at the provided index is not a QkPauliProductMeasurement, this function will return QkExitCode_InvalidOperationKind error. Verify that the instruction is of the correct kind using qk_circuit_instruction_kind.
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 QkPauliProductMeasurement.
Parameters
- circuit – A pointer to the circuit to retrieve the instruction details from.
- index – The circuit instruction index.
- instruction – A pointer to an allocated
QkPauliProductMeasurementto store the data.
Returns
QkExitCode_Success if the data was written into the instruction, or QkExitCode_InvalidOperationKind if the index did not point to a QkPauliProductMeasurement.
qk_circuit_instruction_clear
void qk_circuit_instruction_clear(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, 0);
uint32_t q0[1] = {0};
qk_circuit_gate(qc, QkGate_H, q0, NULL);
qk_circuit_get_instruction(qc, 0, inst);
qk_circuit_instruction_clear(inst); // clear internal allocations
free(inst); // free struct
qk_circuit_free(qc); // free the circuitSafety
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_clear
void qk_opcounts_clear(QkOpCounts *op_counts)
Clear the content in a circuit operation 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_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_tindex 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.
qk_circuit_draw
char *qk_circuit_draw(const QkCircuit *circuit, const QkCircuitDrawerConfig *config)
Draw the circuit as text.
Example
QkCircuit *circuit = qk_circuit_new(2, 1);
qk_circuit_gate(circuit, QkGate_H, (uint32_t[]){0}, NULL);
qk_circuit_gate(circuit, QkGate_CX, (uint32_t[]){0, 1}, NULL);
qk_circuit_measure(circuit, 0, 0);
qk_circuit_measure(circuit, 1, 0);
QkCircuitDrawerConfig config = {false, true, 0};
char *circ_str = qk_circuit_draw(circuit, &config);
printf("%s", circ_str);
qk_str_free(circ_str);
qk_circuit_free(circuit);Safety
Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit, or if config is not NULL and a non-valid pointer to a QkCircuitDrawerConfig struct.
Parameters
-
circuit – A pointer to the circuit to draw.
-
config – A pointer to the
QkCircuitDrawerConfigstructure or NULL. If NULL, the drawer will use these defaults:bundle_cregs = truemerge_wires = truefold = 0
Returns
A pointer to a null-terminated string containing the circuit representation. You must use qk_str_free to release the allocated memory when done.
qk_circuit_to_dag
QkDag *qk_circuit_to_dag(const QkCircuit *circuit)
Convert a given circuit to a DAG.
The new DAG is copied from the circuit; the original circuit reference is still owned by the caller and still required to be freed with qk_circuit_free. You must free the returned DAG with qk_dag_free when done with it.
Example
QkCircuit *qc = qk_circuit_new(0, 0);
QkQuantumRegister *qr = qk_quantum_register_new(3, "qr");
qk_circuit_add_quantum_register(qc, qr);
qk_quantum_register_free(qr);
QkDag *dag = qk_circuit_to_dag(qc);
qk_dag_free(dag);
qk_circuit_free(qc);Safety
Behavior is undefined if circuit is not a valid, non-null pointer to a QkCircuit.
Parameters
- circuit – A pointer to the circuit from which to create the DAG.
Returns
A pointer to the new DAG.
qk_circuit_copy_empty_like
QkCircuit *qk_circuit_copy_empty_like(const QkCircuit *circuit, QkVarsMode vars_mode, QkBlocksMode blocks_mode)
Return a copy of self with the same structure but empty.
That structure includes:
- global phase
- all the qubits and clbits, including the registers.
Example
QkCircuit *qc = qk_circuit_new(10, 10);
for (int i = 0; i < 10; i++) {
qk_circuit_measure(qc, i, i);
uint32_t qubits[1] = {i};
qk_circuit_gate(qc, QkGate_H, qubits, NULL);
}
// As the circuit does not contain any control-flow instructions,
// vars_mode and blocks_mode do not have any effect.
QkCircuit *copy = qk_circuit_copy_empty_like(qc, QkVarsMode_Alike, QkBlocksMode_Drop);
size_t num_copy_instructions = qk_circuit_num_instructions(copy); // 0
// do something with the copy
qk_circuit_free(qc);
qk_circuit_free(copy);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.
- vars_mode – The mode for handling classical variables.
- blocks_mode – The mode for handling blocks.
Returns
The pointer to the copied circuit.
qk_circuit_estimate_fidelity
double qk_circuit_estimate_fidelity(const QkCircuit *circuit, const QkTarget *target)
Estimate the fidelity of a physical circuit.
This function will compute the product of the error rates for each gate in the circuit to estimate the fidelity of the circuit. This method is not intended to compute a realistic simulation of the fidelity of execution on real hardware. It is designed to provide an estimate of how the transpiler would work with the fidelity for various heuristics in its operation. It is typically only useful for comparing different compilation outputs against each other to estimate which one would produce a better quality execution on hardware.
Safety
Behavior is undefined if circuit and target are not a valid, non-null pointer to a QkCircuit and QkTarget respectively.
Parameters
- circuit – A pointer to the circuit to estimate the fidelity of.
- target – A pointer to the target that the circuit will be executed on. This is used to get the error rates for the instructions in the circuit.
Returns
The computed fidelity of the circuit. This will return NaN if the circuit is not physical, meaning there are instructions in circuit not supported by target.
qk_circuit_get_control_flow_instruction
QkControlFlowInstruction *qk_circuit_get_control_flow_instruction(const QkCircuit *circuit, size_t inst_idx, const QkControlFlowInstruction *parent_cf)
Get a control flow instruction from a circuit at the specified index.
This function returns a pointer to an opaque QkControlFlowInstruction struct, which holds information about a control flow instruction at the specified index. The instruction at inst_idx must be a control flow instruction (e.g. IfElse, ForLoop etc.).
Example
QkCircuit *circuit = ...; // Assume circuit contains a control flow instruction at index 0
QkControlFlowInstruction *cf_inst = qk_circuit_get_control_flow_instruction(circuit, 0, NULL);
QkControlFlowKind kind = qk_control_flow_kind(cf_inst);
qk_control_flow_instruction_free(cf_inst);Safety
Behavior is undefined if circuit is not a valid pointer to a QkCircuit object, or if inst_idx is not a valid index within the circuit’s instruction list, or if the instruction at inst_idx is not a control flow instruction. If parent_cf is not null, it must be a valid pointer to a QkControlFlowInstruction.
Parameters
- circuit – A pointer to the circuit containing the control flow instruction.
- inst_idx – The index of the instruction in the circuit’s instruction list.
- parent_cf – A pointer to the enclosing control flow instruction, or
NULLif this instruction is at the top level of the circuit. This is used to compute the correct qubit and clbit mappings relative to the top-level circuit.
Returns
A pointer to a newly allocated QkControlFlowInstruction object.
qk_control_flow_instruction_free
void qk_control_flow_instruction_free(QkControlFlowInstruction *cf_inst)
Free a QkControlFlowInstruction object.
Example
QkCircuit *circuit = ...; // Assume circuit contains a control flow instruction at index 0
QkControlFlowInstruction *cf_inst = qk_circuit_get_control_flow_instruction(circuit, 0, NULL);
qk_control_flow_instruction_free(cf_inst);Safety
Behavior is undefined if cf_inst is not a valid pointer that was returned by qk_circuit_get_control_flow_instruction, or if this function is called more than once on the same pointer.
Parameters
- cf_inst – A pointer to the control flow instruction to free.
qk_circuit_to_python
PyObject *qk_circuit_to_python(QkCircuit *qc)
Pass ownership of a QkCircuit object to Python.
The resulting Python object is not QuantumCircuit, it is the inner CircuitData, which is typically accessed as QuantumCircuit._data. You can use qk_circuit_to_python_full to produce a complete QuantumCircuit object.
It is not safe to use the QkCircuit pointer after calling this function. In particular, you should not attempt to clear or free it. The caller must own the QkCircuit, not hold a borrowed reference (for example, a QkCircuit * retrieved from qk_circuit_borrow_from_python is not owned).
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if circuit is not a valid non-null pointer to an initialized and owned QkCircuit.
Parameters
- qc – The owned object.
Returns
An owned Python reference to the object.
qk_circuit_to_python_full
PyObject *qk_circuit_to_python_full(QkCircuit *qc)
Pass ownership of a QkCircuit object to Python and create a complete QuantumCircuit.
This includes additional Python-space logic to produce the complete QuantumCircuit, since QkCircuit corresponds only to the internal QuantumCircuit._data field.
It is not safe to use the QkCircuit pointer after calling this function. In particular, you should not attempt to clear or free it. The caller must own the QkCircuit, not hold a borrowed reference (for example, a QkCircuit * retrieved from qk_circuit_borrow_from_python is not owned).
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if circuit is not a valid non-null pointer to an initialized and owned QkCircuit.
Parameters
- qc – The owned object.
Returns
An owned Python reference to the object.
qk_circuit_borrow_from_python
QkCircuit *qk_circuit_borrow_from_python(PyObject *ob)
Retrieve a QkCircuit pointer from a Python object.
Note that the input to this function should not be QuantumCircuit, but the output of QuantumCircuit._data. This is necessary to enforce correct reference-counting semantics.
This borrows a Python reference and extracts the QkCircuit pointer for it, if it is of the correct type. The returned pointer is borrowed from the ob pointer. If the PyObject is not the correct type, the return value is NULL and the exception state of the Python interpreter is set.
You must be attached to a Python interpreter to call this function.
You can also use qk_circuit_convert_from_python, which is logically the exact same as this function, but can be directly used as a “converter” function for the PyArg_Parse* family of Python converter functions.
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if ob is not a valid non-null pointer to a Python object.
Parameters
- ob – A borrowed Python object.
Returns
A pointer to the native object, or NULL if the Python object is the wrong type.
qk_circuit_convert_from_python
int qk_circuit_convert_from_python(PyObject *object, void *address)
Retrieve a QkCircuit pointer from a Python object.
Note that the input to this function should not be QuantumCircuit, but the output of QuantumCircuit._data. This is necessary to enforce correct reference-counting semantics.
This borrows a Python reference and extracts the QkCircuit pointer for it into address, if it is of the correct type. The returned pointer is borrowed from the object pointer. If the PyObject is not the correct type, the return value is 0, the exception state of the Python interpreter is set, and address is unchanged.
You must be attached to a Python interpreter to call this function.
You can also use qk_circuit_borrow_from_python, which is logically the exact same as this, but with a more natural signature for direct usage.
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if object is not a valid non-null pointer to a Python object, or if address is not a pointer to writeable data of the correct type.
Parameters
- object – A borrowed Python object.
- address – The location to write the output to.
Returns
1 on success, 0 on failure.
qk_quantum_register_to_python
PyObject *qk_quantum_register_to_python(QkQuantumRegister *qr)
Pass ownership of a QkQuantumRegister object to Python.
It is not safe to use the QkQuantumRegister pointer after calling this function. In particular, you should not attempt to clear or free it. The caller must own the QkQuantumRegister, not hold a borrowed reference (for example, a QkQuantumRegister * retrieved from qk_quantum_register_borrow_from_python is not owned).
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if qr is not a valid non-null pointer to an initialized and owned QkQuantumRegister.
Parameters
- qr – The owned object.
Returns
An owned Python reference to the object.
qk_quantum_register_borrow_from_python
const QkQuantumRegister *qk_quantum_register_borrow_from_python(PyObject *ob)
Retrieve a QkQuantumRegister pointer from a Python object.
This borrows a Python reference and extracts the QkQuantumRegister pointer for it, if it is of the correct type. The returned pointer is borrowed from the ob pointer. If the PyObject is not the correct type, the return value is NULL and the exception state of the Python interpreter is set.
You must be attached to a Python interpreter to call this function.
You can also use qk_quantum_register_convert_from_python, which is logically the exact same as this function, but can be directly used as a “converter” function for the PyArg_Parse* family of Python converter functions.
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if ob is not a valid non-null pointer to a Python object.
Parameters
- ob – A borrowed Python object.
Returns
A pointer to the native object, or NULL if the Python object is the wrong type.
qk_quantum_register_convert_from_python
int qk_quantum_register_convert_from_python(PyObject *object, void *address)
Retrieve a QkQuantumRegister pointer from a Python object.
This borrows a Python reference and extracts the QkQuantumRegister pointer for it into address, if it is of the correct type. The returned pointer is borrowed from the object pointer. If the PyObject is not the correct type, the return value is 0, the exception state of the Python interpreter is set, and address is unchanged.
You must be attached to a Python interpreter to call this function.
You can also use qk_quantum_register_borrow_from_python, which is logically the exact same as this, but with a more natural signature for direct usage.
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if object is not a valid non-null pointer to a Python object, or if address is not a pointer to writeable data of the correct type.
Parameters
- object – A borrowed Python object.
- address – The location to write the output to.
Returns
1 on success, 0 on failure.
qk_classical_register_to_python
PyObject *qk_classical_register_to_python(QkClassicalRegister *cr)
Pass ownership of a QkClassicalRegister object to Python.
It is not safe to use the QkClassicalRegister pointer after calling this function. In particular, you should not attempt to clear or free it. The caller must own the QkClassicalRegister, not hold a borrowed reference (for example, a QkClassicalRegister * retrieved from qk_classical_register_borrow_from_python is not owned).
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if cr is not a valid non-null pointer to an initialized and owned QkClassicalRegister.
Parameters
- cr – The owned object.
Returns
An owned Python reference to the object.
qk_classical_register_borrow_from_python
const QkClassicalRegister *qk_classical_register_borrow_from_python(PyObject *ob)
Retrieve a QkClassicalRegister pointer from a Python object.
This borrows a Python reference and extracts the QkClassicalRegister pointer for it, if it is of the correct type. The returned pointer is borrowed from the ob pointer. If the PyObject is not the correct type, the return value is NULL and the exception state of the Python interpreter is set.
You must be attached to a Python interpreter to call this function.
You can also use qk_classical_register_convert_from_python, which is logically the exact same as this function, but can be directly used as a “converter” function for the PyArg_Parse* family of Python converter functions.
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if ob is not a valid non-null pointer to a Python object.
Parameters
- ob – A borrowed Python object.
Returns
A pointer to the native object, or NULL if the Python object is the wrong type.
qk_classical_register_convert_from_python
int qk_classical_register_convert_from_python(PyObject *object, void *address)
Retrieve a QkClassicalRegister pointer from a Python object.
This borrows a Python reference and extracts the QkClassicalRegister pointer for it into address, if it is of the correct type. The returned pointer is borrowed from the object pointer. If the PyObject is not the correct type, the return value is 0, the exception state of the Python interpreter is set, and address is unchanged.
You must be attached to a Python interpreter to call this function.
You can also use qk_classical_register_borrow_from_python, which is logically the exact same as this, but with a more natural signature for direct usage.
Safety
The caller must be attached to a Python interpreter. Behavior is undefined if object is not a valid non-null pointer to a Python object, or if address is not a pointer to writeable data of the correct type.
Parameters
- object – A borrowed Python object.
- address – The location to write the output to.
Returns
1 on success, 0 on failure.