Pases del transpilador
La transpilación es el proceso de reescribir un circuito de entrada dado para que se ajuste a la topología de un dispositivo cuántico específico, y/o para optimizar el circuito para su ejecución en un sistema cuántico.
La mayoría de los circuitos deben someterse a una serie de transformaciones que los hagan compatibles con un determinado dispositivo de destino y los optimicen para reducir los efectos del ruido en los resultados obtenidos. Reescribir los circuitos cuánticos para adaptarlos a las limitaciones del hardware y optimizar su rendimiento puede no ser tarea fácil. El flujo de la lógica en la cadena de herramientas de reescritura no tiene por qué ser lineal, y a menudo puede tener sub-bucles iterativos, ramas condicionales y otros comportamientos complejos.
En Qiskit, el transpilador se construye ejecutándose como una serie de pases que realizan cada uno una tarea singular para analizar o transformar un circuito cuántico. La documentación de Python transpiler contiene una explicación más detallada del proceso de transpilación.
La API de C de Qiskit ofrece funciones de paso del transpilador en dos modalidades: unas que operan sobre un QkDag y otro conjunto que opera sobre un QkCircuit. Las funciones basadas en DAG, que siguen la convención de qk_transpiler_pass_*nomenclatura, aceptan un QkDag junto con un QkTarget y cualquier parámetro de configuración específico de la pasada. Estas funciones son la opción recomendada cuando se encadenan varias pasadas, por ejemplo, al crear un proceso de transpilación personalizado, ya que operan directamente sobre el objeto DAG y permiten que este se transmita de manera eficiente de una pasada a la siguiente dentro de una sesión de transpilación. Por el contrario, las funciones basadas en circuitos, siguiendo la convención qk_transpiler_pass_standalone_* de nomenclatura, operan sobre un QkCircuit y están pensadas para ejecutar pasadas individuales de forma aislada. Aunque también se pueden utilizar para crear flujos de trabajo personalizados, cada llamada conlleva una sobrecarga adicional, ya que el circuito de entrada debe convertirse internamente en un DAG y, si se devuelve un circuito transformado, el DAG resultante debe volver a convertirse en un circuito.
Funciones basadas en DAG
qk_transpiler_pass_elide_permutations
QkTranspileLayout *qk_transpiler_pass_elide_permutations(QkDag *dag)
Ejecuta la fase de transpilación « ElidePermutations » en un DAG.
La etapa del transpilador « ElidePermutations » elimina cualquier operación de permutación de un DAG previo al diseño.
Esta pasada está pensada para ejecutarse antes de que se establezca una disposición (asignación de qubits virtuales a qubits físicos) durante el proceso de transpilación. Esta pasada recorre el DAG y, cuando encuentra una puerta de intercambio, permuta los qubits virtuales del DAG y elimina la puerta de intercambio. Esto eliminará de forma efectiva cualquier «swap gate» del DAG antes de ejecutar el diseño. Esta optimización no es válida una vez que se ha establecido el diseño y, por lo tanto, no debe ejecutarse en este caso.
Ejemplo
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(4, "qr");
qk_dag_add_quantum_register(dag, qr);
for (uint32_t i = 0; i < qk_dag_num_qubits(dag) - 1; i++) {
uint32_t qargs[2] = {i, i + 1};
for (uint32_t j = 0; j < i + 1; j++) {
qk_dag_apply_gate(dag, QkGate_CX, qargs, NULL, false);
}
}
QkTranspileLayout *elide_result = qk_transpiler_pass_elide_permutations(dag);
if (elide_result != NULL) {
qk_transpile_layout_free(elide_result);
}
qk_quantum_register_free(qr);
qk_dag_free(dag);Seguridad
El comportamiento es indefinido si no dag es un puntero válido y no nulo a un QkDAG.
Parámetros
- dag : un puntero al DAG en el que se ejecutará « ElidePermutations ». Si se realizan cambios, el objeto al que apunta se modifica in situ. En caso de que se omitan puertas, esta función libera las asignaciones del DAG original.
Devuelve
el objeto de disposición que contiene la permutación de salida inducida por las puertas omitidas en el DAG. Si no se realizan elisiones, este será un puntero nulo y el DAG de entrada permanecerá sin cambios. El autor de la llamada es responsable de liberar el diseño devuelto llamando a qk_transpile_layout_free.
qk_transpiler_pass_check_gate_direction
bool qk_transpiler_pass_check_gate_direction(const QkDag *dag, const QkTarget *target)
Ejecuta el CheckGateDirection proceso en un circuito DAG.
El pase comprueba si las direcciones de las puertas de dos qubits cumplen con las direcciones de puerta especificadas en un objetivo dado.
Ejemplo
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);
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(2, "qr");
qk_dag_add_quantum_register(dag, qr);
qk_dag_apply_gate(dag, QkGate_CX, (uint32_t[]){1,0}, NULL, false);
bool direction_ok = qk_transpiler_pass_check_gate_direction(dag, target);
qk_quantum_register_free(qr);
qk_dag_free(dag);
qk_target_free(target);Seguridad
El comportamiento es indefinido si dag o no target son punteros válidos y no nulos a los QkTarget objetos QkDag y, respectivamente.
Parámetros
- dag : un puntero al circuito DAG en el que se ejecutará la pasada « CheckGateDirection ».
- target - Un puntero al objetivo utilizado para comprobar las direcciones de las puertas.
Devuelve
bool - true si las direcciones de todas las puertas de dos qubits en el circuito cumplen con las restricciones objetivo especificadas.
qk_transpiler_pass_gate_direction
void qk_transpiler_pass_gate_direction(QkDag *dag, const QkTarget *target)
Ejecuta el GateDirection proceso en un DAG.
El paso GateDirection modifica las puertas asimétricas para que coincidan con las direcciones de acoplamiento del hardware. Este pase permite sustituir las puertas cx, cz, ecr, swap, rzx, rxx, ryy y rzz , utilizando identidades predefinidas.
Ejemplo
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);
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(3, "qr");
qk_dag_add_quantum_register(dag, qr);
qk_dag_apply_gate(dag, QkGate_CX, (uint32_t[]){1,0}, NULL, false);
qk_transpiler_pass_gate_direction(dag, target);
qk_quantum_register_free(qr);
qk_dag_free(dag);
qk_target_free(target);Seguridad
El comportamiento es indefinido si dag o no target son punteros válidos y no nulos a los QkTarget objetos QkDag y, respectivamente.
Parámetros
- dag : un puntero al circuito DAG en el que se ejecutará la pasada « GateDirection ». El DAG se modificará in situ mediante esta pasada.
- target - Un puntero al objetivo utilizado para comprobar las direcciones de las puertas.
qk_transpiler_pass_optimize_1q_sequences
void qk_transpiler_pass_optimize_1q_sequences(QkDag *dag, const QkTarget *target)
Ejecuta el proceso « Optimize1qGatesDecomposition » en modo autónomo en un circuito DAG.
Optimize1qGatesDecomposition optimiza las secuencias de compuertas de un solo qubit resintetizando el unitario bajo las restricciones de las compuertas base del objetivo y las tasas de error.
La decisión de sustituir o no la cadena original depende de:
- Si la cadena original estaba fuera de base.
- Si la cadena original estaba en base pero la de repuesto tiene menores tasas de error.
- Si la cadena original es una identidad (se elimina la cadena).
El error es la multiplicación combinada de los errores de las puertas individuales en el qubit sobre el que opera.
Ejemplo
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
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "qr");
qk_dag_add_quantum_register(dag, qr);
uint32_t qubits[1] = {0};
for (int iter = 0; iter < 3; iter++) {
qk_dag_apply_gate(dag, QkGate_H, qubits, NULL, false);
}
// Run transpiler pass
qk_transpiler_pass_optimize_1q_sequences(dag, target);
// Clean up
qk_target_free(target);
qk_dag_free(dag);
qk_quantum_register_free(qr);Seguridad
El comportamiento es indefinido si no dag es un puntero válido y no nulo a un QkDag y si no target es un puntero válido a un QkTarget.
Parámetros
- dag – Un puntero al objeto
QkDagque se va a transformar. - target - Un puntero al objeto
QkTargeto un puntero nulo. En el caso de que se proporcione un puntero nulo y se desconozcan los errores de puerta, el pase elegirá la secuencia con la menor cantidad de puertas y admitirá todas las puertas de base en su conjunto de bases de Euler.
qk_transpiler_pass_remove_diagonal_gates_before_measure
void qk_transpiler_pass_remove_diagonal_gates_before_measure(QkDag *dag)
Ejecuta el RemoveDiagonalGatesBeforeMeasure proceso en un circuito DAG.
Paso del transpilador para eliminar las puertas diagonales (como RZ, T, Z, etc.) antes de una medición. Incluidas las puertas diagonales 2Q.
Ejemplo
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(1, "qr");
QkClassicalRegister *cr = qk_classical_register_new(1, "cr");
qk_dag_add_quantum_register(dag, qr);
qk_dag_add_classical_register(dag, cr);
qk_dag_apply_gate(dag, QkGate_Z, (uint32_t[1]){0}, NULL, false);
qk_dag_apply_measure(dag, 0, 0, false);
qk_transpiler_pass_remove_diagonal_gates_before_measure(dag);
// ...
qk_dag_free(dag);
qk_quantum_register_free(qr);
qk_classical_register_free(cr);Seguridad
El comportamiento es indefinido si no dag es un puntero válido y no nulo a un QkDag.
Parámetros
- dag : un puntero al DAG sobre el que se ejecutará esta pasada. El DAG se modificará in situ mediante esta pasada.
qk_transpiler_pass_remove_identity_equivalent
void qk_transpiler_pass_remove_identity_equivalent(QkDag *dag, const QkTarget *target, double approximation_degree)
Ejecuta la fase de transpilación « RemoveIdentityEquivalent » en un circuito DAG.
Elimina las compuertas cuyo efecto se aproxima a una operación de identidad hasta una fase global y hasta la tolerancia especificada. Las puertas parametrizadas no se tienen en cuenta en este paso.
Para una fidelidad de corte , este paso elimina las puertas cuya fidelidad media con respecto a la identidad es inferior a . Concretamente, una puerta se elimina si donde
donde es la dimensión de la puerta para qubits.
Esta función es multihilo y, por defecto, puede iniciar un grupo de subprocesos con un número de subprocesos igual al número de CPU. Puedes ajustar el número de subprocesos mediante la variable de entorno RAYON_NUM_THREADS. Por ejemplo, si se establece el valor « RAYON_NUM_THREADS=4 », el grupo de subprocesos se limitaría a 4 subprocesos.
Ejemplo
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);
QkDag *dag = qk_dag_new();
QkQuantumRegister *qr = qk_quantum_register_new(4, "qr");
qk_dag_add_quantum_register(dag, qr);
for (uint32_t i = 0; i < qk_dag_num_qubits(dag) - 1; i++) {
uint32_t qargs[2] = {i, i + 1};
for (uint32_t j = 0; j<i+1; j++) {
qk_dag_apply_gate(dag, QkGate_CX, qargs, NULL, false);
}
}
uint32_t rz_qargs[1] = {1,};
double rz_params[1] = {0.,};
qk_dag_apply_gate(dag, QkGate_RZ, rz_qargs, rz_params, false);
qk_transpiler_pass_remove_identity_equivalent(dag, target, 1.0);
qk_quantum_register_free(qr);
qk_dag_free(dag);
qk_target_free(target);Seguridad
El comportamiento no está definido si dag o no target es un puntero válido y no nulo a un QkDag y QkTarget.
Parámetros
- dag : un puntero al DAG en el que se ejecutará « RemoveIdentityEquivalent ». El DAG al que se hace referencia se actualizará con el DAG modificado si la pasada logra eliminar alguna puerta.
- objetivo - El objetivo para el pase RemoveIdentityEquivalent. Si
approximation_degreese establece enNAN, la tolerancia para determinar si una operación es equivalente a la identidad se establecerá en la tasa de error notificada en el objetivo. En caso contrario, no se utilizatarget, ya que la tolerancia es independiente del objetivo. - grado_de_aproximación - El grado a aproximar para la comprobación de equivalencia. Puede ser un valor de coma flotante entre 0 y 1, o
NAN. Si el valor es 1 no se aproxima por encima de la precisión en coma flotante. Para un valor < 1 se utiliza como factor de escala para la fidelidad de corte. Si el valor esNANse aproxima hasta la fidelidad para la puerta especificada entarget.
qk_transpiler_pass_split_2q_unitaries
QkTranspileLayout *qk_transpiler_pass_split_2q_unitaries(QkDag *dag, double requested_fidelity, bool split_swaps)
Ejecuta la fase de transpilación « Split2QUnitaries » en un circuito DAG
Seguridad
El comportamiento es indefinido si no dag es un puntero válido y no nulo a un QkDAG.
Parámetros
- dag : un puntero mutable al circuito DAG en el que se ejecutará « Split2QUnitaries ». Esto se sustituirá por el nuevo DAG si se optimiza alguna puerta.
- requested_fidelity - Tolerancia permitida para dividir unitarios de dos qubits y descomposiciones de puertas.
- split_swaps - Si se intentan dividir las puertas de intercambio, dando lugar a una permutación de los qubits.
Devuelve
Si se dividen algunas unidades equivalentes a permutaciones, esta función devuelve un puntero a un objeto TranspileLayout que contiene la permutación inducida por esta optimización del DAG. Si no se han dividido unidades equivalentes de intercambio, este será un puntero nulo.
Funciones basadas en circuitos
qk_transpiler_pass_standalone_basis_translator
void qk_transpiler_pass_standalone_basis_translator(QkCircuit *circuit, const QkTarget *target, size_t min_qubits)
Ejecute el pase de transpilador BasisTranslator en un circuito.
El paso del transpilador BasisTranslator traduce las puertas a una base de destino buscando un conjunto de traducciones a partir del estándar EquivalenceLibrary.
Ejemplo
#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);Seguridad
El comportamiento es indefinido si circuit y/o target no son punteros válidos y no nulos a un QkCircuit o QkTarget.
Parámetros
- circuit - Un puntero al circuito en el que se ejecutará BasisTranslator. El circuito se mutará in situ, a menos que el circuito ya se encuentre en la base de destino, en cuyo caso el circuito permanecerá inalterado.
- objetivo - El objetivo del que obtendremos las puertas base.
- min_qubits : el número mínimo de qubits para las operaciones del circuito de entrada que se van a traducir.
qk_transpiler_pass_standalone_commutative_cancellation
QkExitCode qk_transpiler_pass_standalone_commutative_cancellation(QkCircuit *circuit, const QkTarget *target, double approximation_degree)
Ejecute el pase de transpilador CommutativeCancellation en un circuito.
Este paso cancela las puertas redundantes (autoadjuntas) mediante relaciones de conmutación.
Ejemplo
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);Seguridad
El comportamiento es indefinido si circuit o target no son válidos, QkCircuit y QkTarget. QkCircuit no se espera que sea nulo y el comportamiento es indefinido si lo es.
Parámetros
- circuit - Un puntero al circuito en el que se ejecutará CommutativeCancellation. Este puntero de circuito a se actualizará con el circuito modificado si el pase consigue eliminar alguna puerta.
- objetivo - Esta pasada intentará acumular todas las rotaciones Z en una puerta RZ, P o U1, dependiendo de cuál se utilice ya en el circuito. Si no hay ninguna presente en el circuito, este argumento de destino (opcional) se utiliza como alternativa para decidir qué puerta utilizar. Si ninguno de RZ, P o U1 está en el circuito o en el objetivo, las rotaciones Z de un solo qubit no se optimizarán.
- grado_de_aproximación - El grado de aproximación utilizado al analizar conmutaciones. Debe estar en
(0, 1].
Devuelve
El código de retorno entero donde 0 representa ningún error y 1 se utiliza para indicar que se encontró un error durante la ejecución del pase.
qk_transpiler_pass_standalone_consolidate_blocks
void qk_transpiler_pass_standalone_consolidate_blocks(QkCircuit *circuit, const QkTarget *target, double approximation_degree, bool force_consolidate)
Ejecute el paso ConsolidateBlocks en un circuito.
ConsolidateBlocks es un paso de transpilador que consolida bloques consecutivos de compuertas que operan sobre los mismos qubits en una compuerta Unitaria, para posteriormente ser resintetizada, lo que conduce a un subcircuito más óptimo.
Seguridad
El comportamiento es indefinido si circuit no es un puntero válido y no nulo a un QkCircuit y si target no es un puntero válido a un QkTarget.
Parámetros
- circuit - Un puntero al circuito en el que se ejecutará ConsolidateBlocks.
- target - Un puntero al objetivo sobre el que ejecutar ConsolidateBlocks.
- grado_de_aproximación - Un valor flotante entre
[0.0, 1.0]oNaN, que por defecto es1.0. Más bajo aproxima más. - force_consolidate - Fuerza la consolidación de bloques.
qk_transpiler_pass_standalone_convert_to_pauli_rotations
void qk_transpiler_pass_standalone_convert_to_pauli_rotations(QkCircuit *circuit)
Ejecuta el ConvertToPauliRotations recorrido sin salir del circuito.
Esta operación convierte todas las puertas estándar (con menos de 4 qubits) del circuito en una secuencia de QkPauliProductRotation puertas y las mediciones en QkPauliProductMeasurement instrucciones. Ten en cuenta que esta pasada genera un error si el circuito contiene puertas no estándar. El flujo de trabajo recomendado consiste en, en primer lugar, transpilar a una base estándar, manteniendo intactas las puertas de rotación (como QkGate_RXX y otras) siempre que sea posible, y, a continuación, ejecutar esta pasada.
Seguridad
El comportamiento es indefinido si no circuit es válido, punteros no nulos a un QkCircuit.
Parámetros
- circuito : un puntero al circuito en el que se ejecutará la pasada.
qk_transpiler_pass_standalone_elide_permutations
QkTranspileLayout *qk_transpiler_pass_standalone_elide_permutations(QkCircuit *circuit)
Ejecute el pase de transpilador ElidePermutations en un circuito.
Consulte la qk_transpiler_pass_elide_permutations función para obtener más detalles sobre el pase.
Seguridad
El comportamiento es indefinido si circuit no es un puntero válido y no nulo a QkCircuit.
Parámetros
- circuit - Un puntero al circuito en el que se ejecutará ElidePermutations. Si se realizan cambios, el objeto señalado se modifica en su lugar. En caso de que se elidan puertas, esta función libera las asignaciones del circuito original.
Devuelve
el objeto de diseño que contiene la permutación de salida inducida por las puertas omitidas en el circuito. Si no se realizan elisiones, este será un puntero nulo y el circuito de entrada permanecerá sin cambios. El autor de la llamada es responsable de liberar el diseño devuelto llamando a qk_transpile_layout_free.
qk_transpiler_pass_standalone_check_gate_direction
bool qk_transpiler_pass_standalone_check_gate_direction(const QkCircuit *circuit, const QkTarget *target)
Ejecute el paso CheckGateDirection en un circuito.
Consulte la qk_transpiler_pass_check_gate_direction función para obtener más detalles sobre el pase.
Seguridad
El comportamiento es indefinido si circuit o target no son punteros válidos y no nulos a los objetos QkCircuit y QkTarget , respectivamente.
Parámetros
- circuito : un puntero al circuito en el que se ejecutará la pasada.
- target - Un puntero al objetivo utilizado para comprobar las direcciones de las puertas.
Devuelve
Es verdadero si y solo si todas las direcciones de las puertas de dos qubits cumplen las restricciones establecidas.
qk_transpiler_pass_standalone_gate_direction
void qk_transpiler_pass_standalone_gate_direction(QkCircuit *circuit, const QkTarget *target)
Ejecute el paso GateDirection en un circuito.
Consulte la qk_transpiler_pass_gate_direction función para obtener más detalles sobre el pase.
Seguridad
El comportamiento es indefinido si circuit o target no son punteros válidos y no nulos a los objetos QkCircuit y QkTarget , respectivamente.
Parámetros
- circuito : un puntero al circuito que se va a modificar in situ.
- destino : un puntero al destino utilizado para las direcciones de las puertas.
qk_transpiler_pass_standalone_inverse_cancellation
void qk_transpiler_pass_standalone_inverse_cancellation(QkCircuit *circuit)
Ejecute el pase de transpilador InverseCancellation en un circuito.
Cancela pares de puertas consecutivas que son inversas entre sí. Las puertas canceladas están formadas por pares de puertas autoinversas:
- 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
y pares de puertas inversas:
- (QkGate_T, QkGate_Tdg)
- (QkGate_S, QkGate_Sdg)
- (QkGate_SX, QkGate_SXdg)
- (QkGate_CS, QkGate_CSdg)
Ejemplo
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);Seguridad
El comportamiento es indefinido si circuit no es un puntero válido y no nulo a QkCircuit.
Parámetros
- circuit - Un puntero al circuito en el que se ejecutará InverseCancellation. Si el pase consigue eliminar alguna puerta, el circuito original será sustituido por el circuito producido por este pase.
qk_transpiler_pass_standalone_litinski_transformation
void qk_transpiler_pass_standalone_litinski_transformation(QkCircuit *circuit, bool fix_clifford)
Ejecuta el LitinskiTransformation recorrido sin salir del circuito.
Esta etapa transforma todas las puertas de Clifford en el extremo del circuito, convirtiendo las puertas de rotación de Pauli en QkPauliProductRotation puertas y las mediciones en QkPauliProductMeasurement instrucciones. Ten en cuenta que, actualmente, este paso solo admite circuitos que contengan puertas QkGate_T, QkGate_Tdg QkGate_RZ o como puertas no Clifford; en caso contrario, se produce un error. El flujo de trabajo recomendado consiste en transpilar primero a una base Clifford+RZ y, a continuación, ejecutar esta pasada.
Seguridad
El comportamiento es indefinido si no circuit es válido, punteros no nulos a un QkCircuit.
Parámetros
- circuito : un puntero al circuito en el que se ejecutará la pasada.
- fix_clifford – Si es así
true, deja las puertas de Clifford al final del circuito. Sifalsese omiten.
qk_transpiler_standalone_optimize_1q_sequences
void qk_transpiler_standalone_optimize_1q_sequences(QkCircuit *circuit, const QkTarget *target)
Ejecuta el paso Optimize1qGatesDecomposition en modo autónomo en un circuito.
utiliza qk_transpiler_pass_standalone_optimize_1q_sequences() esto en su lugar.
Seguridad
El comportamiento es indefinido si circuit no es un puntero válido y no nulo a un QkCircuit y si target no es un puntero válido a un QkTarget.
Parámetros
- circuit - Puntero al objeto
QkCircuitque se va a transformar. - target - Un puntero al objeto
QkTargeto un puntero nulo. En el caso de que se proporcione un puntero nulo y se desconozcan los errores de puerta, el pase elegirá la secuencia con la menor cantidad de puertas y admitirá todas las puertas de base en su conjunto de bases de Euler.
qk_transpiler_pass_standalone_optimize_1q_sequences
void qk_transpiler_pass_standalone_optimize_1q_sequences(QkCircuit *circuit, const QkTarget *target)
Ejecuta el paso Optimize1qGatesDecomposition en modo autónomo en un circuito.
Consulte la qk_transpiler_pass_optimize_1q_sequences función para obtener más detalles sobre el pase.
Seguridad
El comportamiento es indefinido si circuit no es un puntero válido y no nulo a un QkCircuit y si target no es un puntero válido a un QkTarget.
Parámetros
- circuit - Puntero al objeto
QkCircuitque se va a transformar. - target - Un puntero al objeto
QkTargeto un puntero nulo. En el caso de que se proporcione un puntero nulo y se desconozcan los errores de puerta, el pase elegirá la secuencia con la menor cantidad de puertas y admitirá todas las puertas de base en su conjunto de bases de Euler.
qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure
void qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure(QkCircuit *circuit)
Ejecute el paso RemoveDiagonalGatesBeforeMeasure en un circuito.
Consulte la qk_transpiler_pass_remove_diagonal_gates_before_measure función para obtener más detalles sobre el pase.
Seguridad
El comportamiento es indefinido si circuit no es un puntero válido y no nulo a QkCircuit.
Parámetros
- circuito : un puntero al circuito en el que se ejecutará esta pasada.
qk_transpiler_pass_standalone_remove_identity_equivalent
void qk_transpiler_pass_standalone_remove_identity_equivalent(QkCircuit *circuit, const QkTarget *target, double approximation_degree)
Ejecute el pase de transpilador RemoveIdentityEquivalent en un circuito.
Consulte la qk_transpiler_pass_remove_identity_equivalent función para obtener más detalles sobre el pase.
Esta función es multihilo y, por defecto, puede iniciar un grupo de subprocesos con un número de subprocesos igual al número de CPU. Puedes ajustar el número de subprocesos mediante la variable de entorno RAYON_NUM_THREADS. Por ejemplo, si se establece el valor « RAYON_NUM_THREADS=4 », el grupo de subprocesos se limitaría a 4 subprocesos.
Seguridad
El comportamiento es indefinido si circuit o target no es un puntero válido y no nulo a un QkCircuit y QkTarget.
Parámetros
- circuit - Un puntero al circuito en el que se ejecutará RemoveIdentityEquivalent. Este circuito señalado se actualizará con el circuito modificado si el pase consigue eliminar alguna puerta.
- objetivo - El objetivo para el pase RemoveIdentityEquivalent. Si
approximation_degreese establece enNAN, la tolerancia para determinar si una operación es equivalente a la identidad se establecerá en la tasa de error notificada en el objetivo. En caso contrario, no se utilizatarget, ya que la tolerancia es independiente del objetivo. - grado_de_aproximación - El grado a aproximar para la comprobación de equivalencia. Puede ser un valor de coma flotante entre 0 y 1, o
NAN. Si el valor es 1 no se aproxima por encima de la precisión en coma flotante. Para un valor < 1 se utiliza como factor de escala para la fidelidad de corte. Si el valor esNANse aproxima hasta la fidelidad para la puerta especificada entarget.
qk_transpiler_pass_standalone_sabre_layout
QkTranspileLayout *qk_transpiler_pass_standalone_sabre_layout(QkCircuit *circuit, const QkTarget *target, const QkSabreLayoutOptions *options)
Ejecute el pase de transpilador SabreLayout en un circuito.
El paso SabreLayout elige un trazado mediante un encaminamiento bidireccional iterativo del circuito de entrada.
Partiendo de un trazado inicial aleatorio, el algoritmo realiza un enrutamiento completo del circuito para terminar con un trazado final. Este esquema final se utiliza como esquema inicial para el trazado del circuito inverso. El algoritmo itera varias veces hasta encontrar una distribución inicial que reduzca el coste total de enrutamiento.
Este método explota la reversibilidad de los circuitos cuánticos, y trata de incluir información global del circuito en la elección del trazado_inicial.
Este paso ejecutará tanto el diseño como el enrutamiento y transformará el circuito de modo que el diseño se aplique a la entrada (lo que significa que el circuito de salida tendrá qubits ancilla asignados para los qubits no utilizados en el mapa de acoplamiento y los qubits se reordenarán para que coincidan con los qubits físicos mapeados) y luego se aplicará el enrutamiento. Esto se hace porque el pase ejecutará pruebas de semillas paralelas con diferentes semillas aleatorias para seleccionar la disposición inicial aleatoria y luego seleccionar la salida enrutada que resulte en el menor número de compuertas de intercambio necesarias. Este cálculo de intercambio final es lo mismo que realizar un enrutamiento final, por lo que es más eficiente aplicarlo después de computarlo.
Esta función es multihilo y lanzará un pool de hilos con hilos igual al número de CPUs por defecto. Puede ajustar el número de hilos con la variable de entorno RAYON_NUM_THREADS . Por ejemplo, configurando RAYON_NUM_THREADS=4 se limitaría el pool de hilos a 4 hilos.
Referencias
[1] Henry Zou y Matthew Treinish y Kevin Hartman y Alexander Ivrii y Jake Lishman. “LightSABRE: Un algoritmo SABRE ligero y mejorado" arXiv:2409.08368
[2] Li, Gushu, Yufei Ding y Yuan Xie. "Abordar el problema del mapeo de qubits
para los dispositivos cuánticos de la era NISQ" ASPLOS 2019.
Seguridad
El comportamiento es indefinido si circuit o target no es un puntero válido y no nulo a un QkCircuit y QkTarget.
Parámetros
- circuit - Un puntero al circuito en el que se ejecutará SabreLayout. El circuito se modifica en su lugar y las asignaciones del circuito original son liberadas por esta función.
- target - Un puntero al objetivo en el que ejecutar SabreLayout
- options - Un puntero a las opciones de SabreLayout
Devuelve
El diseño transpile que describe el diseño y la permutación de salida causada por el pase
qk_transpiler_pass_standalone_split_2q_unitaries
QkTranspileLayout *qk_transpiler_pass_standalone_split_2q_unitaries(QkCircuit *circuit, double requested_fidelity, bool split_swaps)
Ejecuta la fase de transpilación « Split2QUnitaries » en un circuito.
Consulte la qk_transpiler_pass_split_2q_unitaries función para obtener más detalles sobre el pase.
Seguridad
El comportamiento es indefinido si circuit no es un puntero válido y no nulo a QkCircuit.
Parámetros
- circuito : un puntero mutable al circuito en el que se ejecutará « Split2QUnitaries ».
- requested_fidelity - Tolerancia permitida para dividir unitarios de dos qubits y descomposiciones de puertas.
- split_swaps - Si se intentan dividir las puertas de intercambio, dando lugar a una permutación de los qubits.
Devuelve
Si cualquier permutación equivalente a unitarios se divide esta función devuelve un puntero a un TranspileLayout que contiene la permutación inducida por esta optimización del circuito. Si no se dividen unitarios equivalentes de intercambio será un puntero nulo.
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)
Ejecute el pase del transpilador UnitarySynthesis.
El UnitarySynthesis transpiler pass sintetizará cualquier UnitaryGates en el circuito en puertas disponibles en el objetivo.
Ejemplo
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);Seguridad
El comportamiento es indefinido si circuit o target no es un puntero válido y no nulo a un QkCircuit y QkTarget.
Parámetros
- circuit - Un puntero al circuito en el que se va a ejecutar UnitarySynthesis
- target - Un puntero al objetivo en el que ejecutar UnitarySynthesis
- min_qubits - El número mínimo de qubits en el unitario a sintetizar. Si el unitario es inferior al número de qubits especificado, no se sintetizará.
- approximation\degree - dial heurístico utilizado para la aproximación de circuitos ( 1.0=no approximation, 0.0=maximal approximation). La aproximación puede abaratar el circuito sintetizado a costa de alejarse del unitario original. Si es NAN, la aproximación al objetivo se basa en las fidelidades de puerta en la
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)
Utilice el algoritmo « VF2 » para elegir un diseño (si es posible) para el circuito de entrada, utilizando una puntuación heurística sensible al ruido basada únicamente en las tasas de error del hardware, y no en las puertas específicas del circuito.
Esta función corresponde al paso del VF2Layout espacio e Python.
Esta función es adecuada para su uso en circuitos que aún no se han bajado completamente al hardware. Si su circuito ya se ha reducido completamente al hardware y desea mejorar el diseño para obtener un gráfico de interacción exacto, utilice qk_transpile_pass_standalone_vf2_layout_exact en su lugar.
Si en esta pasada se encuentra una solución, significa que existe un "trazado perfecto" y que no es necesario ningún otro trazado de intercambio o enrutamiento. Sin embargo, no siempre hay una solución posible, o puede existir una solución pero no se encuentra dentro de los límites especificados cuando se llama al pase.
Ejemplo
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);Seguridad
El comportamiento es indefinido si circuit o no target es un puntero válido y distinto de nulo a y QkCircuit QkTarget. El comportamiento es indefinido si config es un puntero distinto de nulo que no apunta a un objeto QkVF2LayoutConfiguration válido (pero un puntero nulo sí es válido).
Parámetros
- circuit - Un puntero al circuito en el que se va a ejecutar VF2Layout
- target - Un puntero al objetivo en el que ejecutar el pase VF2Layout
- config : un puntero a la estructura
QkVF2LayoutConfigurationde configuración. Si este puntero es nulo, se utilizan los valores predeterminados del pase. - strict_direction – Si
truese especifica, la pasada tendrá en cuenta la dirección de los bordes en la conectividad descrita en eltarget. Por lo general, es recomendablefalseestablecer este parámetro en, ya que la heurística de error ya es muy aproximada y las puertas de dos qubits casi siempre pueden sintetizarse para «invertir» la dirección utilizando únicamente puertas locales de un qubit y la puerta de dos qubits en su dirección nativa.
Devuelve
Un puntero a un objeto de resultados que contiene los resultados de la pasada. Este objeto se asigna en el montón y deberá liberarse con la qk_vf2_layout_result_free función.
qk_transpiler_pass_standalone_vf2_layout_exact
QkVF2LayoutResult *qk_transpiler_pass_standalone_vf2_layout_exact(const QkCircuit *circuit, const QkTarget *target, const QkVF2LayoutConfiguration *config)
Utilice el algoritmo VF2 para elegir un diseño (si es posible) para el circuito de entrada, utilizando una heurística de puntuación sensible al ruido que requiere que el resultado sea totalmente compatible con el hardware.
Esta función corresponde al paso del VF2PostLayout espacio e Python con strict_direction=True.
Esta función es adecuada para su uso en circuitos que ya se han reducido completamente al hardware, y ahora se busca determinar si una permutación de qubits puede conducir a mejores tasas de error estimadas. Si su circuito sigue estando en términos de operaciones no compatibles con el hardware, utilice qk_transpile_pass_standalone_vf2_layout_average en su lugar.
Normalmente, se llama a esta pasada después del diseño, el enrutamiento, la traducción a un conjunto base nativo y la optimización, de modo que el circuito de entrada ya sea ejecutable en hardware con los índices de qubits haciendo referencia a qubits físicos. El pase devolverá un resultado que indicará uno de los siguientes:
- Existe una mejor opción para la asignación inicial de qubits virtuales a físicos que la que utiliza actualmente el circuito.
- La elección actual de qubits físicos es la mejor que se ha encontrado dentro de su límite de llamada.
- No existe ninguna asignación válida de virtual a físico que dé como resultado un circuito ejecutable (o, al menos, el paso no ha logrado encontrar ninguno dentro de los límites especificados).
En los dos primeros casos, qk_vf2_layout_has_match devolverá true. Solo en el primer caso, qk_vf2_layout_has_improvement devolverá true.
Ejemplo
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);Seguridad
El comportamiento es indefinido si circuit o no target es un puntero válido y distinto de nulo a y QkCircuit QkTarget. El comportamiento es indefinido si config es un puntero distinto de nulo que no apunta a un objeto QkVF2LayoutConfiguration válido (pero un puntero nulo sí es válido).
Parámetros
- circuito : un puntero al circuito en el que se ejecutará la búsqueda de diseño.
- target : puntero al objetivo que representa la QPU.
- config : un puntero a la estructura
QkVF2LayoutConfigurationde configuración. Si este puntero es nulo, se utilizan los valores predeterminados del pase.
Devuelve
Un puntero a un objeto de resultados que contiene los resultados de la pasada. Este objeto se asigna en el montón y deberá liberarse con la qk_vf2_layout_result_free función.
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)
Versión obsoleta de qk_transpiler_pass_standalone_vf2_layout_average.
Esta interfaz heredada no utiliza QkVf2LayoutConfiguration, y tiene un nombre que no deja claro cómo maneja la heurística de error (calcula el promedio de todas las puertas en el QkTarget para un qubit o enlace dado).
Sustituido por qk_transpiler_pass_standalone_vf2_layout_average().
Seguridad
Los requisitos de seguridad de qk_transpiler_pass_standalone_vf2_layout_average deben respetarse para circuit y target.
Parámetros
- circuito – Como en
qk_transpiler_pass_standalone_vf2_layout_average. - objetivo – Como en
qk_transpiler_pass_standalone_vf2_layout_average. - strict_direction – Como en
qk_transpiler_pass_standalone_vf2_layout_average. - call_limit : igual que en
qk_vf2_layout_configuration_set_call_limit, pero se utiliza el mismo valor tanto parabeforecomo paraafter. - time_limit – Como en
qk_vf2_layout_configuration_set_time_limit. - max_trials – Como en
qk_vf2_layout_configuration_set_max_trials.
Devuelve
Como en qk_transpiler_pass_standalone_vf2_layout_average.