Passagens do Transpiler
A transpilação é o processo de reescrever um determinado circuito de entrada para corresponder à topologia de um dispositivo quântico específico e/ou para otimizar o circuito para execução em um sistema quântico.
A maioria dos circuitos precisa passar por uma série de transformações que os tornam compatíveis com um determinado dispositivo de destino e os otimizam para reduzir os efeitos do ruído nos resultados resultantes. A reescrita de circuitos quânticos para atender às restrições de hardware e a otimização do desempenho podem estar longe de ser triviais. O fluxo da lógica na cadeia de ferramentas de reescrita não precisa ser linear e, muitas vezes, pode ter sub-loops iterativos, ramificações condicionais e outros comportamentos complexos.
No Qiskit, o transpilador é construído por meio da execução de uma série de passagens, cada uma executando uma tarefa singular para analisar ou transformar um circuito quântico. A documentação Python transpiler contém uma explicação mais detalhada do processo de transpilação.
A API C do Qiskit oferece funções de passagem do transpiler em duas formas: aquelas que operam sobre um QkDag e outro conjunto que opera sobre um QkCircuit. As funções baseadas em DAG, que seguem a convenção de qk_transpiler_pass_*nomenclatura, aceitam um QkDag juntamente com um QkTarget e quaisquer parâmetros de configuração específicos da passagem. Essas funções são a opção recomendada ao encadear várias etapas, por exemplo, ao criar um pipeline de transpilagem personalizado, pois atuam diretamente sobre o objeto DAG e permitem que ele seja passado de forma eficiente de uma etapa para a seguinte dentro de uma sessão de transpilagem. Em contrapartida, as funções baseadas em circuitos, seguindo a qk_transpiler_pass_standalone_* convenção de nomenclatura, operam sobre um QkCircuit e destinam-se à execução de passagens individuais de forma isolada. Embora também possam ser usados para criar fluxos de trabalho personalizados, cada chamada acarreta uma sobrecarga adicional, pois o circuito de entrada precisa ser convertido internamente em um DAG e, caso seja retornado um circuito transformado, o DAG resultante precisa ser convertido de volta em um circuito.
Funções baseadas em DAG
qk_transpiler_pass_elide_permutations
QkTranspileLayout *qk_transpiler_pass_elide_permutations(QkDag *dag)
Execute a etapa do transpilador ElidePermutations em um DAG.
A etapa do transpilador ElidePermutations remove quaisquer operações de permutação de um DAG pré-layout.
Esta etapa deve ser executada antes que um layout (mapeamento de qubits virtuais para qubits físicos) seja definido durante o pipeline de transpilagem. Esta passagem percorre o DAG e, quando encontra uma porta de troca, permuta os qubits virtuais no DAG e remove a porta de troca. Isso removerá efetivamente quaisquer portas de troca no DAG antes da execução do layout. Essa otimização não é válida após a definição de um layout e não deve ser executada nesse caso.
Exemplo
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);Segurança
O comportamento é indefinido se não dag for um ponteiro válido e diferente de nulo para um QkDAG.
Parâmetros
- dag – Um ponteiro para o DAG no qual será executado o comando
ElidePermutations. Se forem feitas alterações, o objeto ao qual se aponta é modificado no próprio local. Caso os portões sejam omitidos, as alocações do DAG original são liberadas por esta função.
Retorna
o objeto de layout que contém a permutação de saída induzida pelas portas omitidas no DAG. Se nenhuma elisão for realizada, este será um ponteiro nulo e o DAG de entrada permanecerá inalterado. O chamador é responsável por liberar o layout retornado chamando qk_transpile_layout_free.
qk_transpiler_pass_check_gate_direction
bool qk_transpiler_pass_check_gate_direction(const QkDag *dag, const QkTarget *target)
Execute a CheckGateDirection passagem em um circuito DAG.
A aprovação verifica se as direções das portas de dois qubits estão em conformidade com as direções das portas especificadas em um determinado destino.
Exemplo
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);Segurança
O comportamento é indefinido se dag ou não target forem ponteiros válidos e não nulos para os QkTarget objetos QkDag e, respectivamente.
Parâmetros
- dag – Um ponteiro para o circuito DAG no qual a passagem de verificação de integridade ( CheckGateDirection ) deve ser executada.
- alvo - Um ponteiro para o alvo usado para verificar as direções do portão.
Retorna
bool - verdadeiro se as direções de todas as portas de dois qubits no circuito estiverem em conformidade com as restrições de destino especificadas.
qk_transpiler_pass_gate_direction
void qk_transpiler_pass_gate_direction(QkDag *dag, const QkTarget *target)
Execute o GateDirection pass em um DAG.
A passagem GateDirection modifica as portas assimétricas para corresponder às direções de acoplamento do hardware. Essa passagem suporta substituições para os portões cx, cz, ecr, swap, rzx, rxx, ryy e rzz , usando identidades predefinidas.
Exemplo
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);Segurança
O comportamento é indefinido se dag ou não target forem ponteiros válidos e não nulos para os QkTarget objetos QkDag e, respectivamente.
Parâmetros
- dag – Um ponteiro para o circuito DAG no qual a passagem de verificação de integridade ( GateDirection ) deve ser executada. O DAG será modificado in loco por essa passagem.
- alvo - Um ponteiro para o alvo usado para verificar as direções do portão.
qk_transpiler_pass_optimize_1q_sequences
void qk_transpiler_pass_optimize_1q_sequences(QkDag *dag, const QkTarget *target)
Executa a passagem " Optimize1qGatesDecomposition " no modo autônomo em um circuito DAG.
Optimize1qGatesDecomposition otimiza as sequências de porta de um único qubit ao sintetizar novamente o unitário sob as restrições das portas de base e das taxas de erro do alvo.
A decisão de substituir ou não a corrente original depende de:
- Se a corrente original estiver fora de base.
- Se a corrente original estava com defeito, mas a substituta tem taxas de erro menores.
- Se a cadeia original for uma identidade (a cadeia é removida).
O erro é a multiplicação combinada dos erros de portas individuais no qubit em que ele opera.
Exemplo
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);Segurança
O comportamento é indefinido se não dag for um ponteiro válido e diferente de nulo para um QkDag e se não target for um ponteiro válido para um QkTarget.
Parâmetros
- dag – Um ponteiro para o
QkDagobjeto a ser transformado. - target - Um ponteiro para o objeto
QkTargetou um ponteiro nulo. Caso um ponteiro nulo seja fornecido e os erros de porta sejam desconhecidos, a passagem escolherá a sequência com a menor quantidade de portas e oferecerá suporte a todas as portas de base em seu conjunto de base Euler.
qk_transpiler_pass_remove_diagonal_gates_before_measure
void qk_transpiler_pass_remove_diagonal_gates_before_measure(QkDag *dag)
Execute a RemoveDiagonalGatesBeforeMeasure passagem em um circuito DAG.
Passagem do transpilador para remover portas diagonais (como RZ, T, Z, etc.) antes de uma medição. Incluindo portas diagonais 2Q.
Exemplo
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);Segurança
O comportamento é indefinido se não dag for um ponteiro válido e diferente de nulo para um QkDag.
Parâmetros
- dag – Um ponteiro para o DAG no qual esta etapa será executada. O DAG será modificado in loco por essa passagem.
qk_transpiler_pass_remove_identity_equivalent
void qk_transpiler_pass_remove_identity_equivalent(QkDag *dag, const QkTarget *target, double approximation_degree)
Execute a etapa do transpilador RemoveIdentityEquivalent em um circuito DAG.
Remove portas cujo efeito está próximo de uma operação de identidade até uma fase global e até a tolerância especificada. As portas parametrizadas não são consideradas por essa passagem.
Para uma fidelidade de corte , essa passagem remove as portas cuja fidelidade média em relação à identidade está abaixo de . Em termos concretos, uma porta é removida se onde
em que é a dimensão da porta para qubits.
Esta função é multithread e, por padrão, pode iniciar um pool de threads com um número de threads igual ao número de CPUs. Você pode ajustar o número de threads usando a variável de ambiente RAYON_NUM_THREADS. Por exemplo, definir RAYON\_NUM\_THREADS=4 limitaria o conjunto de threads a 4 threads.
Exemplo
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);Segurança
O comportamento é indefinido se dag ou não target for um ponteiro válido e diferente de nulo para um QkDag e QkTarget.
Parâmetros
- dag – Um ponteiro para o DAG no qual será executado o comando
RemoveIdentityEquivalent. Este DAG indicado será atualizado com o DAG modificado se a passagem conseguir remover algum portão. - alvo - O alvo para o passe RemoveIdentityEquivalent. Se
approximation_degreeestiver definido comoNAN, a tolerância para determinar se uma operação é equivalente à identidade será definida como a taxa de erro relatada no alvo. Caso contrário, otargetnão é usado, pois a tolerância é independente do alvo. - approximation_degree - O grau a ser aproximado para a verificação de equivalência. Esse pode ser um valor de ponto flutuante entre 0 e 1, ou
NAN. Se o valor for 1, não haverá aproximação acima da precisão do ponto flutuante. Para um valor < 1, isso é usado como um fator de escala para a fidelidade de corte. Se o valor forNAN, isso se aproxima da fidelidade da porta especificada emtarget.
qk_transpiler_pass_split_2q_unitaries
QkTranspileLayout *qk_transpiler_pass_split_2q_unitaries(QkDag *dag, double requested_fidelity, bool split_swaps)
Execute a etapa do transpilador Split2QUnitaries em um circuito DAG
Segurança
O comportamento é indefinido se não dag for um ponteiro válido e diferente de nulo para um QkDAG.
Parâmetros
- dag – Um ponteiro mutável para o circuito DAG no qual será executado o
Split2QUnitaries. Isso será substituído pelo novo DAG caso algum gate seja otimizado. - requested_fidelity - Tolerância permitida para divisão de unidades de dois qubits e decomposições de porta.
- split_swaps - Se deve tentar dividir as portas de troca, resultando em uma permutação dos qubits.
Retorna
Se houver unidades equivalentes de troca que sejam divididas, esta função retorna um ponteiro para um objeto TranspileLayout que contém a permutação induzida por esta otimização do DAG. Se não houver unidades equivalentes de troca a serem divididas, este será um ponteiro nulo.
Funções baseadas em circuitos
qk_transpiler_pass_standalone_basis_translator
void qk_transpiler_pass_standalone_basis_translator(QkCircuit *circuit, const QkTarget *target, size_t min_qubits)
Execute a passagem do transpilador BasisTranslator em um circuito.
A passagem do transpilador BasisTranslator traduz as portas para uma base de destino buscando um conjunto de traduções do padrão EquivalenceLibrary.
Exemplo
#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);Segurança
O comportamento é indefinido se circuit e/ou target não forem ponteiros válidos e não nulos para um QkCircuit ou QkTarget.
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em BasisTranslator. O circuito sofrerá mutação no local, a menos que já esteja na base de destino, caso em que o circuito permanecerá inalterado.
- alvo - O alvo de onde obteremos as portas de base.
- min_qubits – O número mínimo de qubits para as operações no circuito de entrada a serem traduzidas.
qk_transpiler_pass_standalone_commutative_cancellation
QkExitCode qk_transpiler_pass_standalone_commutative_cancellation(QkCircuit *circuit, const QkTarget *target, double approximation_degree)
Execute a passagem do transpilador CommutativeCancellation em um circuito.
Essa passagem cancela as portas redundantes (autoadjuntas) por meio de relações de comutação.
Exemplo
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);Segurança
O comportamento é indefinido se circuit ou target não for um site válido, QkCircuit e QkTarget. QkCircuit não deve ser nulo e o comportamento é indefinido se for.
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em CommutativeCancellation. Esse ponteiro de circuito será atualizado com o circuito modificado se o passe conseguir remover qualquer porta.
- target (alvo ) - Essa passagem tentará acumular todas as rotações Z em uma porta RZ, P ou U1, dependendo da que já estiver sendo usada no circuito. Se não houver nenhum no circuito, esse argumento de destino (opcional) será usado como alternativa para decidir qual porta usar. Se nenhum RZ, P ou U1 estiver no circuito ou no alvo, as rotações Z de um único qubit não serão otimizadas.
- approximation_degree - O grau de aproximação usado ao analisar as comutações. Deve estar em
(0, 1].
Retorna
O código de retorno inteiro, em que 0 representa nenhum erro e 1 é usado para indicar que foi encontrado um erro durante a execução da passagem.
qk_transpiler_pass_standalone_consolidate_blocks
void qk_transpiler_pass_standalone_consolidate_blocks(QkCircuit *circuit, const QkTarget *target, double approximation_degree, bool force_consolidate)
Execute a passagem ConsolidateBlocks em um circuito.
ConsolidateBlocks é uma passagem de transpilador que consolida blocos consecutivos de portas que operam nos mesmos qubits em uma porta unitária, para posteriormente ser ressintetizada, o que leva a um subcircuito mais otimizado.
Segurança
O comportamento é indefinido se circuit não for um ponteiro válido e não nulo para QkCircuit e se target não for um ponteiro válido para QkTarget.
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em ConsolidateBlocks.
- alvo - Um ponteiro para o alvo no qual será executado o ConsolidateBlocks.
- approximation_degree - Um valor flutuante entre
[0.0, 1.0]ouNaN, cujo padrão é1.0. Menor aproxima mais. - force_consolidate - Força a consolidação do bloco.
qk_transpiler_pass_standalone_convert_to_pauli_rotations
void qk_transpiler_pass_standalone_convert_to_pauli_rotations(QkCircuit *circuit)
Execute a ConvertToPauliRotations passagem no próprio circuito.
Esta operação converte todas as portas padrão (com menos de 4 qubits) do circuito em uma sequência de QkPauliProductRotation portas e medições em QkPauliProductMeasurement instruções. Observe que esta etapa gera um erro se o circuito contiver portas não padronizadas. O fluxo de trabalho sugerido consiste em, primeiro, compilar para uma base padrão, mantendo intactas as portas de rotação (como QkGate_RXX e outras) sempre que possível, e, em seguida, chamar esta etapa.
Segurança
O comportamento é indefinido se não circuit for válido, ou se for um ponteiro não nulo para um QkCircuit.
Parâmetros
- circuito – Um ponteiro para o circuito no qual a passagem deve ser executada.
qk_transpiler_pass_standalone_elide_permutations
QkTranspileLayout *qk_transpiler_pass_standalone_elide_permutations(QkCircuit *circuit)
Execute a passagem do transpilador ElidePermutations em um circuito.
Consulte a qk_transpiler_pass_elide_permutations função para obter mais detalhes sobre o passe.
Segurança
O comportamento é indefinido se circuit não for um ponteiro válido e não nulo para um QkCircuit.
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em ElidePermutations. Se forem feitas alterações, o objeto apontado será alterado no lugar. No caso de as portas serem elididas, as alocações do circuito original são liberadas por essa função.
Retorna
o objeto de layout que contém a permutação de saída induzida pelas portas omitidas no circuito. Se não forem realizadas elisões, este será um ponteiro nulo e o circuito de entrada permanecerá inalterado. O chamador é responsável por liberar o layout retornado chamando 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)
Execute a passagem CheckGateDirection em um circuito.
Consulte a qk_transpiler_pass_check_gate_direction função para obter mais detalhes sobre o passe.
Segurança
O comportamento é indefinido se circuit ou target não forem ponteiros válidos e não nulos para os objetos QkCircuit e QkTarget , respectivamente.
Parâmetros
- circuito – Um ponteiro para o circuito no qual a passagem deve ser executada.
- alvo - Um ponteiro para o alvo usado para verificar as direções do portão.
Retorna
É verdadeiro se e somente se todas as orientações das portas de dois qubits estiverem em conformidade com as restrições definidas.
qk_transpiler_pass_standalone_gate_direction
void qk_transpiler_pass_standalone_gate_direction(QkCircuit *circuit, const QkTarget *target)
Execute a passagem GateDirection em um circuito.
Consulte a qk_transpiler_pass_gate_direction função para obter mais detalhes sobre o passe.
Segurança
O comportamento é indefinido se circuit ou target não forem ponteiros válidos e não nulos para os objetos QkCircuit e QkTarget , respectivamente.
Parâmetros
- circuito – Um ponteiro para o circuito a ser modificado in loco.
- alvo – Um ponteiro para o alvo utilizado para as direções do portão.
qk_transpiler_pass_standalone_inverse_cancellation
void qk_transpiler_pass_standalone_inverse_cancellation(QkCircuit *circuit)
Execute a passagem do transpilador InverseCancellation em um circuito.
Cancela pares de portas consecutivas que são inversas uma da outra. As portas canceladas consistem em pares de portas 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
e pares de portas inversas:
- (QkGate_T, QkGate_Tdg)
- (QkGate_S, QkGate_Sdg)
- (QkGate_SX, QkGate_SXdg)
- (QkGate_CS, QkGate_CSdg)
Exemplo
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);Segurança
O comportamento é indefinido se circuit não for um ponteiro válido e não nulo para um QkCircuit.
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em InverseCancellation. Se a passagem for capaz de remover qualquer porta, o circuito original será substituído pelo circuito produzido por essa passagem.
qk_transpiler_pass_standalone_litinski_transformation
void qk_transpiler_pass_standalone_litinski_transformation(QkCircuit *circuit, bool fix_clifford)
Execute a LitinskiTransformation passagem no próprio circuito.
Esta passagem transfere todas as portas de Clifford para o final do circuito, convertendo as portas de rotação de Pauli em QkPauliProductRotation portas e as medições em QkPauliProductMeasurement instruções. Observe que, atualmente, esta passagem só suporta circuitos que contenham QkGate_Tportas, QkGate_Tdg``QkGate_RZ ou como não-Clifford; caso contrário, ela entra em pânico. O fluxo de trabalho sugerido é primeiro compilar para uma base Clifford+RZ e, em seguida, chamar essa etapa.
Segurança
O comportamento é indefinido se não circuit for válido, ou se for um ponteiro não nulo para um QkCircuit.
Parâmetros
- circuito – Um ponteiro para o circuito no qual a passagem deve ser executada.
- fix_clifford – Se for o caso
true, deixe as portas de Clifford no final do circuito. Sefalseforem omitidos.
qk_transpiler_standalone_optimize_1q_sequences
void qk_transpiler_standalone_optimize_1q_sequences(QkCircuit *circuit, const QkTarget *target)
Executa a passagem Optimize1qGatesDecomposition em modo autônomo em um circuito.
use isso em qk_transpiler_pass_standalone_optimize_1q_sequences() vez disso.
Segurança
O comportamento é indefinido se circuit não for um ponteiro válido e não nulo para QkCircuit e se target não for um ponteiro válido para QkTarget.
Parâmetros
- circuit - Um ponteiro para o objeto
QkCircuita ser transformado. - target - Um ponteiro para o objeto
QkTargetou um ponteiro nulo. Caso um ponteiro nulo seja fornecido e os erros de porta sejam desconhecidos, a passagem escolherá a sequência com a menor quantidade de portas e oferecerá suporte a todas as portas de base em seu conjunto de base Euler.
qk_transpiler_pass_standalone_optimize_1q_sequences
void qk_transpiler_pass_standalone_optimize_1q_sequences(QkCircuit *circuit, const QkTarget *target)
Executa a passagem Optimize1qGatesDecomposition em modo autônomo em um circuito.
Consulte a qk_transpiler_pass_optimize_1q_sequences função para obter mais detalhes sobre o passe.
Segurança
O comportamento é indefinido se circuit não for um ponteiro válido e não nulo para QkCircuit e se target não for um ponteiro válido para QkTarget.
Parâmetros
- circuit - Um ponteiro para o objeto
QkCircuita ser transformado. - target - Um ponteiro para o objeto
QkTargetou um ponteiro nulo. Caso um ponteiro nulo seja fornecido e os erros de porta sejam desconhecidos, a passagem escolherá a sequência com a menor quantidade de portas e oferecerá suporte a todas as portas de base em seu conjunto de base Euler.
qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure
void qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure(QkCircuit *circuit)
Execute a passagem RemoveDiagonalGatesBeforeMeasure em um circuito.
Consulte a qk_transpiler_pass_remove_diagonal_gates_before_measure função para obter mais detalhes sobre o passe.
Segurança
O comportamento é indefinido se circuit não for um ponteiro válido e não nulo para um QkCircuit.
Parâmetros
- circuito – Um ponteiro para o circuito no qual esta passagem será executada.
qk_transpiler_pass_standalone_remove_identity_equivalent
void qk_transpiler_pass_standalone_remove_identity_equivalent(QkCircuit *circuit, const QkTarget *target, double approximation_degree)
Execute a passagem do transpilador RemoveIdentityEquivalent em um circuito.
Consulte a qk_transpiler_pass_remove_identity_equivalent função para obter mais detalhes sobre o passe.
Esta função é multithread e, por padrão, pode iniciar um pool de threads com um número de threads igual ao número de CPUs. Você pode ajustar o número de threads usando a variável de ambiente RAYON_NUM_THREADS. Por exemplo, definir RAYON\_NUM\_THREADS=4 limitaria o conjunto de threads a 4 threads.
Segurança
O comportamento é indefinido se circuit ou target não for um ponteiro válido e não nulo para QkCircuit e QkTarget.
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em RemoveIdentityEquivalent. Esse circuito apontado será atualizado com o circuito modificado se a passagem for capaz de remover qualquer porta.
- alvo - O alvo para o passe RemoveIdentityEquivalent. Se
approximation_degreeestiver definido comoNAN, a tolerância para determinar se uma operação é equivalente à identidade será definida como a taxa de erro relatada no alvo. Caso contrário, otargetnão é usado, pois a tolerância é independente do alvo. - approximation_degree - O grau a ser aproximado para a verificação de equivalência. Esse pode ser um valor de ponto flutuante entre 0 e 1, ou
NAN. Se o valor for 1, não haverá aproximação acima da precisão do ponto flutuante. Para um valor < 1, isso é usado como um fator de escala para a fidelidade de corte. Se o valor forNAN, isso se aproxima da fidelidade da porta especificada emtarget.
qk_transpiler_pass_standalone_sabre_layout
QkTranspileLayout *qk_transpiler_pass_standalone_sabre_layout(QkCircuit *circuit, const QkTarget *target, const QkSabreLayoutOptions *options)
Execute a passagem do transpilador SabreLayout em um circuito.
A passagem SabreLayout escolhe um layout por meio de um roteamento bidirecional iterativo do circuito de entrada.
Começando com um layout inicial aleatório, o algoritmo faz um roteamento completo do circuito para chegar a um layout final. Esse layout final é então usado como layout inicial para o roteamento do circuito reverso. O algoritmo itera várias vezes até encontrar um layout inicial que reduza o custo total do roteamento.
Esse método explora a reversibilidade dos circuitos quânticos e tenta incluir informações globais do circuito na escolha do_layout inicial.
Essa passagem executará o layout e o roteamento e transformará o circuito de modo que o layout seja aplicado à entrada (o que significa que o circuito de saída terá qubits de ancilla alocados para qubits não utilizados no mapa de acoplamento e os qubits serão reordenados para corresponder aos qubits físicos mapeados) e, em seguida, o roteamento será aplicado. Isso é feito porque a passagem executará testes de sementes paralelos com diferentes sementes aleatórias para selecionar o layout inicial aleatório e, em seguida, selecionar a saída roteada que resulta no menor número de portas de troca necessárias. Esse cálculo final de swap é o mesmo que executar um roteamento final, portanto, é mais eficiente aplicá-lo após o cálculo.
Essa função é multithread e iniciará um pool de threads com threads iguais ao número de CPUs por padrão. Você pode ajustar o número de threads com a variável de ambiente RAYON_NUM_THREADS . Por exemplo, a configuração RAYON_NUM_THREADS=4 limitaria o pool de threads a 4 threads.
Referências
[1] Henry Zou, Matthew Treinish, Kevin Hartman, Alexander Ivrii e Jake Lishman. “LightSABRE: Um algoritmo SABRE leve e aprimorado" arXiv:2409.08368
[2] Li, Gushu, Yufei Ding e Yuan Xie. "Enfrentando o problema de mapeamento de qubit
para dispositivos quânticos da era NISQ" ASPLOS 2019.
Segurança
O comportamento é indefinido se circuit ou target não for um ponteiro válido e não nulo para QkCircuit e QkTarget.
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em SabreLayout. O circuito é modificado no local e as alocações do circuito original são liberadas por essa função.
- alvo - Um ponteiro para o alvo no qual executar SabreLayout
- options - Um ponteiro para as opções de SabreLayout
Retorna
O layout transpile que descreve o layout e a permutação de saída causados pela passagem
qk_transpiler_pass_standalone_split_2q_unitaries
QkTranspileLayout *qk_transpiler_pass_standalone_split_2q_unitaries(QkCircuit *circuit, double requested_fidelity, bool split_swaps)
Execute a etapa de transpilagem do Split2QUnitaries em um circuito.
Consulte a qk_transpiler_pass_split_2q_unitaries função para obter mais detalhes sobre o passe.
Segurança
O comportamento é indefinido se circuit não for um ponteiro válido e não nulo para um QkCircuit.
Parâmetros
- circuito – Um ponteiro mutável para o circuito no qual se executará o
Split2QUnitaries. - requested_fidelity - Tolerância permitida para divisão de unidades de dois qubits e decomposições de porta.
- split_swaps - Se deve tentar dividir as portas de troca, resultando em uma permutação dos qubits.
Retorna
Se qualquer unidade equivalente à troca for dividida, essa função retornará um ponteiro para TranspileLayout que contém a permutação induzida por essa otimização de circuito. Se nenhuma unidade equivalente de troca for dividida, esse será um ponteiro 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)
Execute a passagem do transpilador UnitarySynthesis.
A passagem do transpilador UnitarySynthesis sintetizará qualquer UnitaryGates no circuito em portas disponíveis no alvo.
Exemplo
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);Segurança
O comportamento é indefinido se circuit ou target não for um ponteiro válido e não nulo para QkCircuit e QkTarget.
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em UnitarySynthesis
- alvo - Um ponteiro para o alvo no qual executar UnitarySynthesis
- min_qubits - O número mínimo de qubits na unidade a ser sintetizada. Se a unitária for menor que o número especificado de qubits, ela não será sintetizada.
- approximation_degree - mostrador heurístico usado para a aproximação do circuito ( 1.0=no approximation, 0.0=maximal approximation). A aproximação pode tornar o circuito sintetizado mais barato ao custo de se afastar do unitário original. Se for NAN, a aproximação do alvo se baseia nas fidelidades da porta no site
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 o algoritmo VF2 para escolher um layout (se possível) para o circuito de entrada, usando uma heurística de pontuação sensível ao ruído baseada apenas nas taxas de erro de hardware, e não nas portas específicas do circuito.
Esta função corresponde à passagem VF2Layout do espaço Python.
Esta função é adequada para uso em circuitos que ainda não foram totalmente reduzidos ao hardware. Se o seu circuito já foi completamente reduzido ao hardware e você deseja melhorar o layout para obter um gráfico de interação exato, use qk_transpile_pass_standalone_vf2_layout_exact em vez disso.
Se essa passagem encontrar uma solução, isso significa que há um "layout perfeito" e que não é necessário nenhum outro mapeamento ou roteamento de swap. No entanto, nem sempre há uma solução possível, ou pode haver uma solução, mas ela não é encontrada dentro dos limites especificados quando a passagem é chamada.
Exemplo
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);Segurança
O comportamento é indefinido se circuit ou não target for um ponteiro válido e diferente de nulo para um QkCircuit e QkTarget. O comportamento é indefinido se config for um ponteiro diferente de nulo que não aponta para um objeto QkVF2LayoutConfiguration válido (mas um ponteiro nulo é aceitável).
Parâmetros
- circuit - Um ponteiro para o circuito a ser executado em VF2Layout
- alvo - Um ponteiro para o alvo para executar a passagem VF2Layout
- config – Um ponteiro para a estrutura
QkVF2LayoutConfigurationde configuração. Se este ponteiro for nulo, os padrões de passagem serão utilizados. - strict_direction – Se
trueestiver definido, a etapa levará em conta a direção das arestas na conectividade descrita notarget. Normalmente, é recomendávelfalsedefinir esse parâmetro como, pois a heurística de erro já é bastante aproximada, e as portas de dois qubits quase sempre podem ser sintetizadas para “inverter” a direção usando apenas portas locais de um qubit e a porta de dois qubits na direção nativa.
Retorna
Um ponteiro para um objeto de resultado que contém os resultados da passagem. Este objeto é alocado na pilha e precisará ser liberado com a qk_vf2_layout_result_free função.
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 o algoritmo VF2 para escolher um layout (se possível) para o circuito de entrada, usando uma heurística de pontuação sensível ao ruído que exige que o resultado já seja totalmente compatível com o hardware.
Esta função corresponde à passagem VF2PostLayout do espaço Python com strict_direction=True.
Esta função é adequada para uso em circuitos que já foram totalmente reduzidos ao hardware, e agora você está procurando ver se uma permutação de qubits pode levar a melhores taxas de erro estimadas. Se o seu circuito ainda estiver em termos de operações não suportadas por hardware, use qk_transpile_pass_standalone_vf2_layout_average em vez disso.
Normalmente, você chama essa passagem após o layout, o roteamento, a tradução para um conjunto base nativo e a otimização, de modo que o circuito de entrada já seja executável no hardware com os índices de qubits referindo-se a qubits físicos. A passagem retornará um resultado indicando uma das seguintes opções:
- existe uma opção melhor de mapeamento inicial de qubits virtuais para físicos do que a que o circuito está usando atualmente.
- A escolha atual de qubits físicos é a melhor que o pass encontrou dentro do seu limite de chamada.
- não há nenhuma escolha válida de mapeamento virtual-para-físico que resulte em um circuito executável (ou, pelo menos, a passagem não conseguiu encontrar nenhuma dentro dos limites especificados).
Nos dois primeiros casos, qk_vf2_layout_has_match retornará true. Apenas no primeiro caso, qk_vf2_layout_has_improvement retornará true.
Exemplo
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);Segurança
O comportamento é indefinido se circuit ou não target for um ponteiro válido e diferente de nulo para um QkCircuit e QkTarget. O comportamento é indefinido se config for um ponteiro diferente de nulo que não aponta para um objeto QkVF2LayoutConfiguration válido (mas um ponteiro nulo é aceitável).
Parâmetros
- circuito – Um ponteiro para o circuito no qual executar a pesquisa de layout.
- target – Um ponteiro para o alvo que representa a QPU.
- config – Um ponteiro para a estrutura
QkVF2LayoutConfigurationde configuração. Se este ponteiro for nulo, os padrões de passagem serão utilizados.
Retorna
Um ponteiro para um objeto de resultado que contém os resultados da passagem. Este objeto é alocado na pilha e precisará ser liberado com a qk_vf2_layout_result_free função.
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)
Versão obsoleta de qk_transpiler_pass_standalone_vf2_layout_average.
Essa interface legada não usa QkVf2LayoutConfiguratione tem um nome que não deixa claro como ela lida com a heurística de erro (ela calcula a média de todos os portões no QkTarget para um determinado qubit ou link).
Substituído por qk_transpiler_pass_standalone_vf2_layout_average().
Segurança
Os requisitos de segurança qk_transpiler_pass_standalone_vf2_layout_average devem ser respeitados para circuit e target.
Parâmetros
- circuito – Como em
qk_transpiler_pass_standalone_vf2_layout_average. - alvo – Como em
qk_transpiler_pass_standalone_vf2_layout_average. - strict_direction – Como em
qk_transpiler_pass_standalone_vf2_layout_average. - call_limit – Como em
qk_vf2_layout_configuration_set_call_limit, mas o mesmo valor é usado para ebeforeafter. - time_limit – Como em
qk_vf2_layout_configuration_set_time_limit. - max_trials – Como em
qk_vf2_layout_configuration_set_max_trials.
Retorna
Como em qk_transpiler_pass_standalone_vf2_layout_average.