Skip to main content
IBM Quantum Platform

Transpiler Passes

Transpilation is the process of rewriting a given input circuit to match the topology of a specific quantum device, and/or to optimize the circuit for execution on a quantum system.

Most circuits must undergo a series of transformations that make them compatible with a given target device, and optimize them to reduce the effects of noise on the resulting outcomes. Rewriting quantum circuits to match hardware constraints and optimizing for performance can be far from trivial. The flow of logic in the rewriting tool chain need not be linear, and can often have iterative sub-loops, conditional branches, and other complex behaviors.

In Qiskit, the transpiler is built up by executing as a series of passes that each perform a singular task to analyze or transform a quantum circuit. The Python transpiler documentation contains a more detailed explanation of the transpilation process.

The Qiskit C API provides functions that execute transpiler passes in a standalone mode, where you provide the pass with a QkCircuit and then any necessary configuration for the execution of the pass, typically at least a QkTarget. These functions return either a new QkCircuit pointer or the analysis results of running the pass. While this can be used to create a custom workflow, the functions following the naming convention qk_transpiler_pass_standalone_* will have higher overhead as internally they’re converting from the quantum circuit to the dag circuit IR on the input, and if the function returns a new circuit it will convert back before returning. These standalone functions are intended to execute single passes in isolation rather than building a custom transpilation pipeline.


Functions

qk_transpiler_pass_standalone_basis_translator

void qk_transpiler_pass_standalone_basis_translator(QkCircuit *circuit, const QkTarget *target, size_t min_qubits)

Run the BasisTranslator transpiler pass on a circuit.

The BasisTranslator transpiler pass translates gates to a target basis by searching for a set of translations from the standard EquivalenceLibrary.

Example

#include <qiskit.h>
 
QkCircuit *circuit = qk_circuit_new(3, 0);
qk_circuit_gate(circuit, QkGate_CCX, (uint32_t[3]){0, 1, 2}, NULL);
 
// Create a Target with global properties.
QkTarget *target = qk_target_new(3);
qk_target_add_instruction(target, qk_target_entry_new(QkGate_H));
qk_target_add_instruction(target, qk_target_entry_new(QkGate_T));
qk_target_add_instruction(target, qk_target_entry_new(QkGate_Tdg));
qk_target_add_instruction(target, qk_target_entry_new(QkGate_CX));
 
// Run pass
qk_transpiler_pass_standalone_basis_translator(circuit, target, 0);
 
// Free the circuit and target pointers once you're done
qk_circuit_free(circuit);
qk_target_free(target);

Safety

Behavior is undefined if circuit and/or target are not valid, non-null pointers to a QkCircuit or QkTarget.

Parameters

  • circuit – A pointer to the circuit to run BasisTranslator on. The circuit will be mutated in-place, unless the circuit is already in the target basis, in which case the circuit remains unchanged.
  • target – The target where we will obtain basis gates from.
  • min_qubits – The minimum number of qubits for operations in the input ciruit to translate.

qk_transpiler_pass_standalone_commutative_cancellation

QkExitCode qk_transpiler_pass_standalone_commutative_cancellation(QkCircuit *circuit, const QkTarget *target, double approximation_degree)

Run the CommutativeCancellation transpiler pass on a circuit.

This pass cancels the redundant (self-adjoint) gates through commutation relations.

Example

QkCircuit *qc = qk_circuit_new(4, 0);
uint32_t cx_qargs[2] = {0, 1};
qk_circuit_gate(qc, QkGate_CX, cx_qargs, NULL);
qk_circuit_gate(qc, QkGate_Z, (uint32_t[]){0}, NULL);
qk_circuit_gate(qc, QkGate_CX, cx_qargs, NULL);
qk_transpiler_pass_standalone_commutative_cancellation(qc, NULL, 1.0);

Safety

Behavior is undefined if circuit or target is not a valid, QkCircuit and QkTarget. QkCircuit is not expected to be null and behavior is undefined if it is.

Parameters

  • circuit – A pointer to the circuit to run CommutativeCancellation on. This circuit pointer to will be updated with the modified circuit if the pass is able to remove any gates.
  • target – This pass will attempt to accumulate all Z rotations into either an RZ, P or U1 gate, depending on which is already used in the circuit. If none is present in the circuit, this (optional) target argument is used as fallback to decide which gate to use. If none of RZ, P or U1 are in the circuit or the target, single-qubit Z rotations will not be optimized.
  • approximation_degree – The approximation degree used when analyzing commutations. Must be within (0, 1].

Returns

The integer return code where 0 represents no error and 1 is used to indicate an error was encountered during the execution of the pass.

qk_transpiler_pass_standalone_consolidate_blocks

void qk_transpiler_pass_standalone_consolidate_blocks(QkCircuit *circuit, const QkTarget *target, double approximation_degree, bool force_consolidate)

Run the ConsolidateBlocks pass on a circuit.

ConsolidateBlocks is a transpiler pass that consolidates consecutive blocks of gates operating on the same qubits into a Unitary gate, to later on be resynthesized, which leads to a more optimal subcircuit.

Safety

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

Parameters

  • circuit – A pointer to the circuit to run ConsolidateBlocks on.
  • target – A pointer to the target to run ConsolidateBlocks on.
  • approximation_degree – A float between [0.0, 1.0] or a NaN which defaults to 1.0. Lower approximates more.
  • force_consolidate – Force block consolidation.

qk_transpiler_pass_standalone_elide_permutations

QkTranspileLayout *qk_transpiler_pass_standalone_elide_permutations(QkCircuit *circuit)

Run the ElidePermutations transpiler pass on a circuit.

The ElidePermutations transpiler pass removes any permutation operations from a pre-layout circuit.

This pass is intended to be run before a layout (mapping virtual qubits to physical qubits) is set during the transpilation pipeline. This pass iterates over the circuit and when a Swap gate is encountered it permutes the virtual qubits in the circuit and removes the swap gate. This will effectively remove any swap gates in the circuit prior to running layout. This optimization is not valid after a layout has been set and should not be run in this case.

Example

QkCircuit *qc = qk_circuit_new(4, 0);
for (uint32_t i = 0; i < qk_circuit_num_qubits(qc) - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    for (uint32_t j = 0; j<i+1; j++) {
        qk_circuit_gate(qc, QkGate_CX, qargs, NULL);
    }
}
QkTranspileLayout *elide_result = qk_transpiler_pass_standalone_elide_permutations(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 run ElidePermutations on. If there are changes made the object pointed to is changed in place. In case of gates being elided the original circuit’s allocations are freed by this function.

Returns

the layout object containing the output permutation induced by the elided gates in the circuit. If no elisions are performed this will be a null pointer and the input circuit is unchanged.

qk_transpiler_pass_standalone_check_gate_direction

bool qk_transpiler_pass_standalone_check_gate_direction(const QkCircuit *circuit, const QkTarget *target)

Run the CheckGateDirection pass on a circuit.

The pass checks if the directions of two-qubit gates comply with the gate directions specified in a given target.

Example

QkTarget *target = qk_target_new(2);
uint32_t qargs[3] = {0,1};
 
QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
qk_target_entry_add_property(cx_entry, qargs, 2, 0.0, 0.0);
qk_target_add_instruction(target, cx_entry);
 
QkCircuit *circuit = qk_circuit_new(2, 0);
qk_circuit_gate(circuit, QkGate_CX, (uint32_t[]){1,0}, NULL);
 
bool direction_ok = qk_transpiler_pass_standalone_check_gate_direction(circuit, target);

Safety

Behavior is undefined if circuit or target are not valid, non-null pointers to QkCircuit and QkTarget objects, respectively.

Parameters

  • circuit – A pointer to the circuit on which to run the CheckGateDirection pass.
  • target – A pointer to the target used for checking gate directions.

Returns

bool - true iff the directions of all two-qubit gates in the circuit comply with the specified target constraints.

qk_transpiler_pass_standalone_gate_direction

void qk_transpiler_pass_standalone_gate_direction(QkCircuit *circuit, const QkTarget *target)

Run the GateDirection pass on a circuit.

The GateDirection pass modifies asymmetric gates to match the hardware coupling directions. This pass supports replacements for the cx, cz, ecr, swap, rzx, rxx, ryy and rzz gates, using predefined identities.

Example

QkTarget *target = qk_target_new(3);
 
uint32_t qargs[2] = {0,1};
 
QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
qk_target_entry_add_property(cx_entry, qargs, 2, 0.0, 0.0);
qk_target_add_instruction(target, cx_entry);
 
QkCircuit *circuit = qk_circuit_new(3, 0);
qk_circuit_gate(circuit, QkGate_CX, (uint32_t[]){1,0}, NULL);
 
qk_transpiler_pass_standalone_gate_direction(circuit, target);

Safety

Behavior is undefined if circuit or target are not valid, non-null pointers to QkCircuit and QkTarget objects, respectively.

Parameters

  • circuit – A pointer to the circuit on which to run the GateDirection pass. The circuit will be modified in place by the pass.
  • target – A pointer to the target used for checking gate directions.

qk_transpiler_pass_standalone_inverse_cancellation

void qk_transpiler_pass_standalone_inverse_cancellation(QkCircuit *circuit)

Run the InverseCancellation transpiler pass on a circuit.

Cancels pairs of consecutive gates that are inverses of each other. The cancelled gates consist of pairs of self-inverse gates:

  • QkGate_H
  • QkGate_X
  • QkGate_Y
  • QkGate_Z
  • QkGate_CH
  • QkGate_CX
  • QkGate_CY
  • QkGate_CZ
  • QkGate_ECR
  • QkGate_Swap
  • QkGate_CCX
  • QkGate_CCZ
  • QkGate_CSwap
  • QkGate_RCCX
  • QkGate_C3X

and pairs of inverse gates:

  • (QkGate_T, QkGate_Tdg)
  • (QkGate_S, QkGate_Sdg)
  • (QkGate_SX, QkGate_SXdg)
  • (QkGate_CS, QkGate_CSdg)

Example

QkCircuit *qc = qk_circuit_new(2, 2);
uint32_t qargs[1] = {0};
qk_circuit_gate(qc, QkGate_X, qargs, NULL);
qk_circuit_gate(qc, QkGate_H, qargs, NULL);
qk_circuit_gate(qc, QkGate_H, qargs, NULL);
qk_circuit_gate(qc, QkGate_Y, qargs, NULL);
qk_transpiler_pass_standalone_inverse_cancellation(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 run InverseCancellation on. If the pass is able to remove any gates, the original circuit will be replaced by the circuit produced by this pass.

qk_transpiler_standalone_optimize_1q_sequences

void qk_transpiler_standalone_optimize_1q_sequences(QkCircuit *circuit, const QkTarget *target)

Runs the Optimize1qGatesDecomposition pass in standalone mode on a circuit.

Optimize1qGatesDecomposition optimizes single-qubit gate sequences by re-synthesizing the unitary under the constraints of the target’s basis gates and error rates.

The decision of whether to replace the original chain depends on:

  • If the original chain was out of basis.
  • If the original chain was in basis but the replacement has lower error rates.
  • If the original chain is an identity (chain gets removed).

The error is the combined multiplication of the errors of individual gates on the qubit it operates on.

Example

QkTarget *target = qk_target_new(1);
double u_errors[3] = {0., 1e-4, 1e-4};
for (int idx = 0; idx < 3; idx++) {
    QkTargetEntry *u_entry = qk_target_entry_new(QkGate_U);
    uint32_t qargs[1] = {
        0,
    };
    qk_target_entry_add_property(u_entry, qargs, 1, NAN, u_errors[idx]);
    qk_target_add_instruction(target, u_entry);
}
 
// Build circuit
QkCircuit *circuit = qk_circuit_new(1, 0);
uint32_t qubits[1] = {0};
for (int iter = 0; iter < 3; iter++) {
    qk_circuit_gate(circuit, QkGate_H, qubits, NULL);
}
 
// Run transpiler pass
qk_transpiler_standalone_optimize_1q_sequences(circuit, target);
 
// Clean up
qk_target_free(target);
qk_circuit_free(circuit);

Safety

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

Parameters

  • circuit – A pointer to the QkCircuit object to transform.
  • target – A pointer to the QkTarget object or a null pointer. In the case a null pointer is provided and gate errors are unknown the pass will choose the sequence with the least amount of gates, and will support all basis gates on its Euler basis set.

qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure

void qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure(QkCircuit *circuit)

Run the RemoveDiagonalGatesBeforeMeasure pass on a circuit.

Transpiler pass to remove diagonal gates (like RZ, T, Z, etc) before a measurement. Including diagonal 2Q gates.

Example

QkCircuit *qc = qk_circuit_new(1, 1);
qk_circuit_gate(qc, QkGate_Z, {0}, NULL);
qk_circuit_measure(qc, 0, 0);
qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure(qc);
// ...
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 to run this pass on

qk_transpiler_pass_standalone_remove_identity_equivalent

void qk_transpiler_pass_standalone_remove_identity_equivalent(QkCircuit *circuit, const QkTarget *target, double approximation_degree)

Run the RemoveIdentityEquivalent transpiler pass on a circuit.

Removes gates whose effect is close to an identity operation up to a global phase and up to the specified tolerance. Parameterized gates are not considered by this pass.

For a cutoff fidelity ff, this pass removes gates whose average gate fidelity with respect to the identity is below ff. Concretely, a gate GG is removed if Fˉ<f\bar F < f where

barF=1+dFprocess1+d, Fprocess=Tr(G)2d2bar{F} = \frac{1 + d F_{\text{process}}}{1 + d},\ F_{\text{process}} = \frac{|\mathrm{Tr}(G)|^2}{d^2}

where d=2nd = 2^n is the dimension of the gate for nn qubits.

Example

QkTarget *target = qk_target_new(5);
uint32_t current_num_qubits = qk_target_num_qubits(target);
QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
for (uint32_t i = 0; i < current_num_qubits - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    double inst_error = 0.0090393 * (current_num_qubits - i);
    double inst_duration = 0.020039;
    qk_target_entry_add_property(cx_entry, qargs, 2, inst_duration, inst_error);
}
QkExitCode result_cx = qk_target_add_instruction(target, cx_entry);
QkCircuit *qc = qk_circuit_new(4, 0);
for (uint32_t i = 0; i < qk_circuit_num_qubits(qc) - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    for (uint32_t j = 0; j<i+1; j++) {
        qk_circuit_gate(qc, QkGate_CX, qargs, NULL);
    }
}
uint32_t rz_qargs[1] = {1,};
double rz_params[1] = {0.,};
qk_circuit_gate(qc, QkGate_RZ, rz_qargs, rz_params);
qk_transpiler_pass_standalone_remove_identity_equivalent(qc, target, 1.0);

Safety

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

Parameters

  • circuit – A pointer to the circuit to run RemoveIdentityEquivalent on. This circuit pointed to will be updated with the modified circuit if the pass is able to remove any gates.
  • target – The target for the RemoveIdentityEquivalent pass. If approximation_degree is set to NAN the tolerance for determining whether an operation is equivalent to identity will be set to the reported error rate in the target. Otherwise the target is not used as the tolerance is independent of the target.
  • approximation_degree – The degree to approximate for the equivalence check. This can be a floating point value between 0 and 1, or NAN. If the value is 1 this does not approximate above the floating point precision. For a value < 1 this is used as a scaling factor for the cutoff fidelity. If the value is NAN this approximates up to the fidelity for the gate specified in target.

qk_transpiler_pass_standalone_sabre_layout

QkTranspileLayout *qk_transpiler_pass_standalone_sabre_layout(QkCircuit *circuit, const QkTarget *target, const QkSabreLayoutOptions *options)

Run the SabreLayout transpiler pass on a circuit.

The SabreLayout pass chooses a layout via an iterative bidirectional routing of the input circuit.

Starting with a random initial Layout, the algorithm does a full routing of the circuit to end up with a final_layout. This final_layout is then used as the initial_layout for routing the reverse circuit. The algorithm iterates a number of times until it finds an initial_layout that reduces full routing cost.

This method exploits the reversibility of quantum circuits, and tries to include global circuit information in the choice of initial_layout.

This pass will run both layout and routing and will transform the circuit so that the layout is applied to the input (meaning that the output circuit will have ancilla qubits allocated for unused qubits on the coupling map and the qubits will be reordered to match the mapped physical qubits) and then routing will be applied. This is done because the pass will run parallel seed trials with different random seeds for selecting the random initial layout and then selecting the routed output which results in the least number of swap gates needed. This final swap calculation is the same as performing a final routing, so it’s more efficient to apply it after computing it.

This function is multithreaded and will launch a thread pool with threads equal to the number of CPUs by default. You can tune the number of threads with the RAYON_NUM_THREADS environment variable. For example, setting RAYON_NUM_THREADS=4 would limit the thread pool to 4 threads.

References

[1] Henry Zou and Matthew Treinish and Kevin Hartman and Alexander Ivrii and Jake Lishman. “LightSABRE: A Lightweight and Enhanced SABRE Algorithm” arXiv:2409.08368

[2] Li, Gushu, Yufei Ding, and Yuan Xie. “Tackling the qubit mapping problem

for NISQ-era quantum devices.” ASPLOS 2019.

arXiv:1809.02573

Safety

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

Parameters

  • circuit – A pointer to the circuit to run SabreLayout on. The circuit is modified in place and the original circuit’s allocations are freed by this function.
  • target – A pointer to the target to run SabreLayout on
  • options – A pointer to the options for SabreLayout

Returns

The transpile layout that describes the layout and output permutation caused by the pass

qk_transpiler_pass_standalone_split_2q_unitaries

QkTranspileLayout *qk_transpiler_pass_standalone_split_2q_unitaries(QkCircuit *circuit, double requested_fidelity, bool split_swaps)

Run the Split2QUnitaries transpiler pass

Example

QkCircuit *qc = qk_circuit_new(4, 0);
for (uint32_t i = 0; i < qk_circuit_num_qubits(qc) - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    for (uint32_t j = 0; j<i+1; j++) {
        qk_circuit_gate(qc, QkGate_CX, qargs, NULL);
    }
}
QkTranspileLayout *result = qk_transpiler_pass_standalone_split_2q_unitaries(qc, 1e-12, true)

Safety

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

Parameters

  • circuit – A mutable pointer to the circuit to run Split2QUnitaries on. This will be replaced with the new circuit if any gates are optimized and the original will be freed.
  • requested_fidelity – Allowed tolerance for splitting two-qubit unitaries and gate decompositions.
  • split_swaps – Whether to attempt to split swap gates, resulting in a permutation of the qubits.

Returns

If any swap equivalent unitaries are split this function returns a pointer to a TranspileLayout that contains the permutation induced by this circuit optimization. If no swap equivalent unitaries are split this will be a null pointer.

qk_transpiler_pass_standalone_unitary_synthesis

void qk_transpiler_pass_standalone_unitary_synthesis(QkCircuit *circuit, const QkTarget *target, size_t min_qubits, double approximation_degree)

Run the UnitarySynthesis transpiler pass.

The UnitarySynthesis transpiler pass will synthesize any UnitaryGates in the circuit into gates available in the target.

Example

QkTarget *target = qk_target_new(2);
uint32_t current_num_qubits = qk_target_num_qubits(target);
QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
for (uint32_t i = 0; i < current_num_qubits - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    double inst_error = 0.0090393 * (current_num_qubits - i);
    double inst_duration = 0.020039;
    qk_target_entry_add_property(cx_entry, qargs, 2, inst_duration, inst_error);
}
QkExitCode result_cx = qk_target_add_instruction(target, cx_entry);
QkCircuit *qc = qk_circuit_new(2, 0);
QkComplex64 c0 = {0., 0.};
QkComplex64 c1 = {1., 0.};
QkComplex64 unitary[16] = {c1, c0, c0, c0,  // row 0
                           c0, c1, c0, c0,  // row 1
                           c0, c0, c1, c0,  // row 2
                           c0, c0, c0, c1}; // row 3
uint32_t qargs[2] = {0, 1};
qk_circuit_unitary(qc, unitary, qargs, 2, false);
qk_transpiler_pass_standalone_unitary_synthesis(qc, target, 0, 1.0);

Safety

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

Parameters

  • circuit – A pointer to the circuit to run UnitarySynthesis on
  • target – A pointer to the target to run UnitarySynthesis on
  • min_qubits – The minimum number of qubits in the unitary to synthesize. If the unitary is less than the specified number of qubits it will not be synthesized.
  • approximation_degree – heuristic dial used for circuit approximation (1.0=no approximation, 0.0=maximal approximation). Approximation can make the synthesized circuit cheaper at the cost of straying from the original unitary. If NAN, the target approximation is based on gate fidelities in the target.

qk_transpiler_pass_standalone_vf2_layout_average

QkVF2LayoutResult *qk_transpiler_pass_standalone_vf2_layout_average(const QkCircuit *circuit, const QkTarget *target, const QkVF2LayoutConfiguration *config, bool strict_direction)

Use the VF2 algorithm to choose a layout (if possible) for the input circuit, using a noise-aware scoring heuristic based only on hardware error rates, and not the specific gates in the circuit.

This function corresponds to the Python-space VF2Layout pass.

This function is suitable for use on circuits that have not yet been fully lowered to hardware. If your circuit has already been completely lowered to hardware and you are looking to improve the layout for an exact interaction graph, use qk_transpile_pass_standalone_vf2_layout_exact instead.

If this pass finds a solution that means there is a “perfect layout” and that no further swap mapping or routing is needed. However, there is not always a possible solution, or a solution might exist but it is not found within the limits specified when the pass is called.

Example

QkTarget *target = qk_target_new(5);
uint32_t current_num_qubits = qk_target_num_qubits(target);
QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
for (uint32_t i = 0; i < current_num_qubits - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    double inst_error = 0.0090393 * (current_num_qubits - i);
    double inst_duration = 0.020039;
    qk_target_entry_add_property(cx_entry, qargs, 2, inst_duration, inst_error);
}
QkExitCode result_cx = qk_target_add_instruction(target, cx_entry);
QkCircuit *qc = qk_circuit_new(4, 0);
for (uint32_t i = 0; i < qk_circuit_num_qubits(qc) - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    for (uint32_t j = 0; j<i+1; j++) {
        qk_circuit_gate(qc, QkGate_CX, qargs, NULL);
    }
}
QkVF2LayoutConfiguration *config = qk_vf2_layout_configuration_new();
qk_vf2_layout_configuration_set_call_limit(config, 10000, 10000);
QkVF2LayoutResult *layout_result = qk_transpiler_pass_standalone_vf2_layout_average(qc, target, config, false);
qk_vf2_layout_result_free(layout_result);
qk_vf2_layout_configuration_free(config);

Safety

Behavior is undefined if circuit or target is not a valid, non-null pointer to a QkCircuit and QkTarget. Behavior is undefined if config is a non-null pointer that does not point to a valid QkVF2LayoutConfiguration object (but a null pointer is fine).

Parameters

  • circuit – A pointer to the circuit to run VF2Layout on
  • target – A pointer to the target to run the VF2Layout pass on
  • config – A pointer to the QkVF2LayoutConfiguration configuration structure. If this pointer is null, the pass defaults are used.
  • strict_direction – If true, the pass will consider the edge direction in the connectivity described in the target. Typically, setting this to false is desireable as the error heuristic is already very approximate, and two-qubit gates can almost invariably be synthesised to “flip” direction using only local one-qubit gates and the native-direction two-qubit gate.

Returns

A pointer to a result object that contains the results of the pass. This object is heap allocated and will need to be freed with the qk_vf2_layout_result_free function.

qk_transpiler_pass_standalone_vf2_layout_exact

QkVF2LayoutResult *qk_transpiler_pass_standalone_vf2_layout_exact(const QkCircuit *circuit, const QkTarget *target, const QkVF2LayoutConfiguration *config)

Use the VF2 algorithm to choose a layout (if possible) for the input circuit, using a noise-aware scoring heuristic that requires the result is already fully compatible with the hardware.

This function corresponds to the Python-space VF2PostLayout pass with strict_direction=True.

This function is suitable for use on circuits that have already been fully lowered to hardware, and you are now looking to see if a qubit permutation can lead to better estimated error rates. If your circuit is still in terms of non-hardware-supported operations, use qk_transpile_pass_standalone_vf2_layout_average instead.

Typically, you call this pass after layout, routing, translation to a native basis set and optimization, such that the input circuit is already executable on hardware with the qubit indices referring to physical qubits. The pass will return a result indicating one of:

  • there is a better choice of initial virtual-to-physical qubit mapping than what the circuit is currently using.
  • the current choice of physical qubits is the best the pass found within its call limit.
  • there is no valid choice of virtual-to-physical mapping that results in an executable circuit (or at least, the pass failed to find one within its specified limits).

In both of the first two cases, qk_vf2_layout_has_match will return true. In only the first case, qk_vf2_layout_has_improvement will return true.

Example

QkTarget *target = qk_target_new(5)
QkTargetEntry *cx_entry = qk_target_entry_new(QkGate_CX);
for (uint32_t i = 0; i < current_num_qubits - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    double inst_error = 0.0090393 * (current_num_qubits - i);
    double inst_duration = 0.020039;
    qk_target_entry_add_property(cx_entry, qargs, 2, inst_duration, inst_error);
}
QkExitCode result_cx = qk_target_add_instruction(target, cx_entry);
QkCircuit *qc = qk_circuit_new(4, 0);
for (uint32_t i = 0; i < qk_circuit_num_qubits(qc) - 1; i++) {
    uint32_t qargs[2] = {i, i + 1};
    for (uint32_t j = 0; j<i+1; j++) {
        qk_circuit_gate(qc, QkGate_CX, qargs, NULL);
    }
}
QkVF2LayoutConfiguration *config = qk_vf2_layout_configuration_new();
qk_vf2_layout_configuration_call_limit(config, 10000, 10000);
QkVF2LayoutResult *layout_result = qk_transpiler_pass_standalone_vf2_layout_exact(qc, target, config);
qk_vf2_layout_result_free(layout_result);
qk_vf2_layout_configuration_free(config);

Safety

Behavior is undefined if circuit or target is not a valid, non-null pointer to a QkCircuit and QkTarget. Behavior is undefined if config is a non-null pointer that does not point to a valid QkVF2LayoutConfiguration object (but a null pointer is fine).

Parameters

  • circuit – A pointer to the circuit to run the layout search on.
  • target – A pointer to the target representing the QPU.
  • config – A pointer to the QkVF2LayoutConfiguration configuration structure. If this pointer is null, the pass defaults are used.

Returns

A pointer to a result object that contains the results of the pass. This object is heap allocated and will need to be freed with the qk_vf2_layout_result_free function.

qk_transpiler_pass_standalone_vf2_layout

QkVF2LayoutResult *qk_transpiler_pass_standalone_vf2_layout(const QkCircuit *circuit, const QkTarget *target, bool strict_direction, int64_t call_limit, double time_limit, int64_t max_trials)

Deprecated version of qk_transpiler_pass_standalone_vf2_layout_average.

This legacy interface does not use QkVf2LayoutConfiguration, and has a name that is not clear about how it handles the error heuristic (it averages over all gates in the QkTarget for a given qubit or link).

Deprecated since version 2.3.0

Safety

The safety requirements of qk_transpiler_pass_standalone_vf2_layout_average must be respected for circuit and target.

Parameters

  • circuit – As in qk_transpiler_pass_standalone_vf2_layout_average.
  • target – As in qk_transpiler_pass_standalone_vf2_layout_average.
  • strict_direction – As in qk_transpiler_pass_standalone_vf2_layout_average.
  • call_limit – As in qk_vf2_layout_configuration_set_call_limit, but the same value is used for both before and after.
  • time_limit – As in qk_vf2_layout_configuration_set_time_limit.
  • max_trials – As in qk_vf2_layout_configuration_set_max_trials.

Returns

As in qk_transpiler_pass_standalone_vf2_layout_average.

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