Passaggi del transpiler
La transpilazione è il processo di riscrittura di un determinato circuito di ingresso per adattarlo alla topologia di uno specifico dispositivo quantistico e/o per ottimizzare il circuito per l'esecuzione su un sistema quantistico.
La maggior parte dei circuiti deve subire una serie di trasformazioni che li rendono compatibili con un determinato dispositivo di destinazione e li ottimizzano per ridurre gli effetti del rumore sui risultati ottenuti. Riscrivere i circuiti quantistici per adattarli ai vincoli hardware e ottimizzare le prestazioni può essere tutt'altro che banale. Il flusso della logica nella catena degli strumenti di riscrittura non deve necessariamente essere lineare e spesso può avere sottocicli iterativi, rami condizionali e altri comportamenti complessi.
In Qiskit, il transpiler viene costruito eseguendo una serie di passaggi che eseguono ciascuno un singolo compito per analizzare o trasformare un circuito quantistico. La documentazione di Python transpiler contiene una spiegazione più dettagliata del processo di transpilazione.
L'API C di Qiskit fornisce funzioni di passaggio del transpiler in due forme: quelle che operano su un QkDag e un altro insieme che opera su un QkCircuit. Le funzioni basate su DAG, che seguono la convenzione di qk_transpiler_pass_*denominazione, accettano un QkDag insieme a un QkTarget e a eventuali parametri di configurazione specifici del passaggio. Queste funzioni sono la scelta consigliata quando si concatenano più passaggi, ad esempio quando si crea una pipeline di transpilazione personalizzata, poiché operano direttamente sull'oggetto DAG e consentono di trasferirlo in modo efficiente da un passaggio all'altro all'interno di una sessione di transpilazione. Al contrario, le funzioni basate su circuiti, secondo la qk_transpiler_pass_standalone_* convenzione di denominazione, operano su un QkCircuit e sono destinate all'esecuzione di singoli passaggi in modo isolato. Sebbene possano essere utilizzati anche per creare flussi di lavoro personalizzati, ogni chiamata comporta un sovraccarico aggiuntivo poiché il circuito di input deve essere convertito internamente in un DAG e, se viene restituito un circuito trasformato, il DAG risultante deve poi essere riconvertito in un circuito.
Funzioni basate su DAG
qk_transpiler_pass_elide_permutations
QkTranspileLayout *qk_transpiler_pass_elide_permutations(QkDag *dag)
Esegui il passaggio di transpilazione " ElidePermutations " su un DAG.
Il passaggio del transpiler " ElidePermutations " rimuove tutte le operazioni di permutazione da un DAG pre-layout.
Questo passaggio è pensato per essere eseguito prima che venga definito un layout (che mappa i qubit virtuali sui qubit fisici) durante la pipeline di transpilazione. Questo ciclo percorre il DAG e, quando incontra un gate di scambio, permuta i qubit virtuali nel DAG e rimuove il gate di scambio. In questo modo verranno eliminati tutti gli swap gate presenti nel DAG prima dell'esecuzione del layout. Questa ottimizzazione non è valida una volta impostato il layout e, in tal caso, non dovrebbe essere eseguita.
Esempio
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);Sicurezza
Il comportamento è indefinito se non dag è un puntatore valido e non nullo a un QkDAG.
Parametri
- dag – Un puntatore al DAG su cui eseguire l'operazione « ElidePermutations ». Se vengono apportate delle modifiche, l'oggetto a cui si fa riferimento viene modificato direttamente. Nel caso in cui alcuni gate vengano omessi, questa funzione libera le allocazioni del DAG originale.
Risultati
l'oggetto di layout contenente la permutazione di output indotta dai gate omessi nel DAG. Se non vengono eseguite elisioni, questo sarà un puntatore nullo e il DAG di input rimarrà invariato. È responsabilità del chiamante liberare il layout restituito chiamando qk_transpile_layout_free.
qk_transpiler_pass_check_gate_direction
bool qk_transpiler_pass_check_gate_direction(const QkDag *dag, const QkTarget *target)
Esegui il CheckGateDirection passaggio su un circuito DAG.
Il passaggio verifica se le direzioni delle porte a due qubit sono conformi alle direzioni delle porte specificate in un determinato obiettivo.
Esempio
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);Sicurezza
Il comportamento è indefinito se dag o non target sono puntatori validi e non nulli rispettivamente agli QkDag oggetti QkTarget e.
Parametri
- dag – Un puntatore al circuito DAG su cui eseguire il passaggio " CheckGateDirection ".
- target - Un puntatore al target utilizzato per controllare le direzioni del gate.
Risultati
bool - vero se le direzioni di tutte le porte a due qubit del circuito sono conformi ai vincoli specificati.
qk_transpiler_pass_gate_direction
void qk_transpiler_pass_gate_direction(QkDag *dag, const QkTarget *target)
Esegui il GateDirection pass su un DAG.
Il passaggio GateDirection modifica le porte asimmetriche per adattarle alle direzioni di accoppiamento dell'hardware. Questo passaggio supporta le sostituzioni per le porte cx, cz, ecr, swap, rzx, rxx, ryy e rzz , utilizzando identità predefinite.
Esempio
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);Sicurezza
Il comportamento è indefinito se dag o non target sono puntatori validi e non nulli rispettivamente agli QkDag oggetti QkTarget e.
Parametri
- dag – Un puntatore al circuito DAG su cui eseguire il passaggio " GateDirection ". Il DAG verrà modificato in loco dal passaggio.
- target - Un puntatore al target utilizzato per controllare le direzioni del gate.
qk_transpiler_pass_optimize_1q_sequences
void qk_transpiler_pass_optimize_1q_sequences(QkDag *dag, const QkTarget *target)
Esegue il pass " Optimize1qGatesDecomposition " in modalità autonoma su un circuito DAG.
Optimize1qGatesDecomposition ottimizza le sequenze di gate a singolo qubit risintetizzando l'unitario sotto i vincoli delle porte base e dei tassi di errore dell'obiettivo.
La decisione di sostituire o meno la catena originale dipende da:
- Se la catena originale era fuori base.
- Se la catena originale era in base, ma la catena sostitutiva ha tassi di errore inferiori.
- Se la catena originale è un'identità (la catena viene rimossa).
L'errore è la moltiplicazione combinata degli errori dei singoli gate sul qubit su cui opera.
Questa funzione è multithread e, per impostazione predefinita, potrebbe avviare un pool di thread con un numero di thread pari a quello delle CPU. È possibile regolare il numero di thread tramite la RAYON_NUM_THREADS variabile d'ambiente. Ad esempio, impostando RAYON_NUM_THREADS=4 si limiterebbe il pool di thread a 4 thread.
Esempio
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);Sicurezza
Il comportamento è indefinito se non dag è un puntatore valido e non nullo a un QkDag e se non target è un puntatore valido a un QkTarget.
Parametri
- dag – Un puntatore
QkDagall'oggetto da trasformare. - target - Un puntatore all'oggetto
QkTargeto un puntatore nullo. Nel caso in cui venga fornito un puntatore nullo e gli errori dei gate siano sconosciuti, il passaggio sceglierà la sequenza con il minor numero di gate e supporterà tutti i gate della base sul suo insieme di basi di Eulero.
qk_transpiler_pass_remove_diagonal_gates_before_measure
void qk_transpiler_pass_remove_diagonal_gates_before_measure(QkDag *dag)
Esegui il RemoveDiagonalGatesBeforeMeasure passaggio su un circuito DAG.
Passaggio del transpiler per rimuovere le porte diagonali (come RZ, T, Z, ecc.) prima di una misura. Comprese le porte diagonali 2Q.
Esempio
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);Sicurezza
Il comportamento è indefinito se non dag è un puntatore valido e non nullo a un QkDag.
Parametri
- dag – Un puntatore al DAG su cui eseguire questo passaggio. Il DAG verrà modificato in loco dal passaggio.
qk_transpiler_pass_remove_identity_equivalent
void qk_transpiler_pass_remove_identity_equivalent(QkDag *dag, const QkTarget *target, double approximation_degree)
Eseguire il passaggio di transpilazione " RemoveIdentityEquivalent " su un circuito DAG.
Rimuove le porte il cui effetto è vicino a un'operazione di identità fino a una fase globale e fino alla tolleranza specificata. Le porte parametrizzate non sono considerate da questo passaggio.
Per una fedeltà di cutoff , questo passaggio rimuove i gate la cui fedeltà media rispetto all'identità è inferiore a . Concretamente, un gate viene rimosso se dove
dove è la dimensione del gate per qubit.
Questa funzione è multithread e, per impostazione predefinita, avvia un pool di thread con un numero di thread pari a quello delle CPU. È possibile regolare il numero di thread tramite la variabile d'ambiente RAYON_NUM_THREADS. Ad esempio, impostando RAYON\_NUM\_THREADS=4 si limiterebbe il pool di thread a 4 thread.
Esempio
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);Sicurezza
Il comportamento è indefinito se dag o non target è un puntatore valido e non nullo a un QkDag e QkTarget.
Parametri
- dag – Un puntatore al DAG su cui eseguire l'operazione « RemoveIdentityEquivalent ». Il DAG a cui si fa riferimento verrà aggiornato con il DAG modificato se il passaggio riesce a rimuovere dei gate.
- target - L'obiettivo del passaggio RemoveIdentityEquivalent. Se
approximation_degreeè impostato suNAN, la tolleranza per determinare se un'operazione è equivalente all'identità sarà impostata sul tasso di errore riportato nel target. In caso contrario, il sitotargetnon viene utilizzato poiché la tolleranza è indipendente dall'obiettivo. - grado_di_approssimazione - Il grado da approssimare per la verifica dell'equivalenza. Può essere un valore in virgola mobile compreso tra 0 e 1, oppure
NAN. Se il valore è 1, l'approssimazione non è superiore alla precisione in virgola mobile. Per un valore < 1 questo viene utilizzato come fattore di scala per la fedeltà di taglio. Se il valore èNANsi approssima alla fedeltà del gate specificata intarget.
qk_transpiler_pass_split_2q_unitaries
QkTranspileLayout *qk_transpiler_pass_split_2q_unitaries(QkDag *dag, double requested_fidelity, bool split_swaps)
Eseguire il passaggio di transpilazione " Split2QUnitaries " su un circuito DAG
Sicurezza
Il comportamento è indefinito se non dag è un puntatore valido e non nullo a un QkDAG.
Parametri
- dag – Un puntatore mutabile al circuito DAG su cui eseguire l'operazione « Split2QUnitaries ». Se vengono ottimizzati dei gate, questo verrà sostituito con il nuovo DAG.
- requested_fidelity - Tolleranza consentita per la suddivisione di unitari a due qubit e per le decomposizioni dei gate.
- split_swaps - Se tentare di dividere le porte swap, ottenendo una permutazione dei qubit.
Risultati
Se vengono suddivise delle unità equivalenti per permutazione, questa funzione restituisce un puntatore a un oggetto TranspileLayout che contiene la permutazione indotta da questa ottimizzazione DAG. Se non vengono suddivise unità equivalenti di swap, questo sarà un puntatore nullo.
qk_transpiler_pass_2q_peephole_optimization
void qk_transpiler_pass_2q_peephole_optimization(QkDag *dag, const QkTarget *target, double approximation_degree)
Eseguire il passaggio di transpilazione " TwoQubitPeepholeOptimization ".
Questo passaggio del transpiler è progettato per eseguire l'ottimizzazione unitaria "peephole" a due qubit. Questo passaggio individua tutti i blocchi da 2 qubit presenti nel circuito, calcola l'operatore unitario di ciascun blocco e quindi sintetizza tale operatore unitario. Se l'operatore unitario a due qubit sintetizzato risulta “migliore” del sottocircuito originale, quest'ultimo viene sostituito da quello sintetizzato. L'euristica utilizzata per determinare quale sia la soluzione migliore esamina innanzitutto il numero di porte a due qubit presenti nel circuito e privilegia la sintesi con un numero inferiore di porte a due qubit; se il numero di porte a due qubit è lo stesso, esamina la fedeltà stimata del circuito e sceglie il sottocircuito con la fedeltà stimata più elevata; infine, se necessario, sceglie il sottocircuito con il minor numero totale di porte.
Nel caso in cui il target sia sovracompleto, il passaggio proverà tutti i decompositori supportati per tutti i gate supportati su un dato qubit. Verrà selezionata la scomposizione che, in base all'euristica sopra descritta, offre le migliori prestazioni attese e verrà utilizzata per sostituire il blocco.
Questo passaggio è progettato per essere eseguito su un circuito fisico e si presume che i dettagli delle operazioni su un dato qubit corrispondano al qubit hardware del target. Tuttavia, l'output del passaggio potrebbe non utilizzare operazioni hardware; in particolare, potrebbero essere emessi gate a singolo qubit che non rientrano tra le operazioni supportate dal target, in genere solo se per la sintesi viene utilizzato un gate parametrizzato supportato dal TwoQubitControlledUDecomposer . Pertanto, se si esegue questo passaggio in una fase di ottimizzazione fisica (come la fase di ottimizzazione), è opportuno abbinarlo a passaggi quali BasisTranslator e/o Optimize1qGatesDecomposition per garantire che tali porte su singolo qubit non corrette vengano sostituite con operazioni supportate dall'hardware prima di uscire dalla fase.
Questo passaggio è multithread e eseguirà l'analisi in parallelo, utilizzando tutti i core disponibili sul sistema locale. Per maggiori dettagli su come gestire il comportamento del threading in Qiskit in generale — il che influirà anche su questo passaggio — è possibile consultare la guida alla configurazione
Esempio
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);
uint32_t forward[2] = {0, 1};
uint32_t reverse[2] = {1, 0};
for (int i = 0; i < 10; i++) {
if (i % 2) {
qk_circuit_gate(qc, QkGate_CX, forward, NULL);
} else {
qk_circuit_gate(qc, QkGate_CX, reverse, NULL);
}
}
QkDag *dag = qk_circuit_to_dag(qc);
qk_circuit_free(qc);
qk_transpiler_pass_2q_peephole_optimization(dag, target, 1.0);
qk_dag_free(dag);
qk_target_free(target);Sicurezza
Il comportamento è indefinito se dag o non target è un puntatore valido e non nullo a un QkDag e QkTarget.
Non è sicuro richiamare questa funzione in un contesto in cui il circuito DAG contenga oggetti di proprietà di Python. Poiché la funzione è internamente multithread, se nel circuito sono presenti porte gestite da Python, i thread di lavoro potrebbero dover acquisire il GIL per accedere agli attributi di tali porte, causando così un deadlock. È necessario utilizzare la classe di spazio TwoQubitPeepholeOptimization “ Python ” per eseguire questa fase, qualora siano presenti elementi del circuito di proprietà di “ Python ”.
Parametri
- dag – Un puntatore al circuito DAG su cui eseguire l' TwoQubitPeepholeOptimization
- target – Un puntatore alla destinazione su cui eseguire " TwoQubitPeepholeOptimization "
- approximation_degree – manopola euristica utilizzata per l'approssimazione dei circuiti (approssimazione 1.0=no, approssimazione 0.0=maximal ). L'approssimazione può ridurre le dimensioni del circuito sintetizzato, a costo di allontanarsi dall'operatore unitario originale. Se NAN, l'approssimazione del target si basa sulle fedeltà dei gate nel
target.
Funzioni basate su circuiti
qk_transpiler_pass_standalone_basis_translator
void qk_transpiler_pass_standalone_basis_translator(QkCircuit *circuit, const QkTarget *target, size_t min_qubits)
Eseguire il passaggio del transpiler BasisTranslator su un circuito.
Il passaggio del transpiler BasisTranslator traduce i gate in una base di destinazione cercando un insieme di traduzioni dallo standard EquivalenceLibrary.
Esempio
#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);Sicurezza
Il comportamento è indefinito se circuit e/o target non sono puntatori validi e non nulli a un QkCircuit o QkTarget.
Parametri
- circuit - Un puntatore al circuito su cui eseguire BasisTranslator. Il circuito verrà mutato in-place, a meno che il circuito non sia già presente nella base di destinazione, nel qual caso il circuito rimarrà invariato.
- target - Il target da cui ottenere i gate di base.
- min_qubits – Il numero minimo di qubit necessari per le operazioni nel circuito di ingresso da tradurre.
qk_transpiler_pass_standalone_commutative_cancellation
QkExitCode qk_transpiler_pass_standalone_commutative_cancellation(QkCircuit *circuit, const QkTarget *target, double approximation_degree)
Eseguire il passaggio del transpiler CommutativeCancellation su un circuito.
Questo passaggio annulla le porte ridondanti (autoaggiunte) attraverso le relazioni di commutazione.
Questa funzione è multithread e, per impostazione predefinita, potrebbe avviare un pool di thread con un numero di thread pari a quello delle CPU. È possibile regolare il numero di thread tramite la RAYON_NUM_THREADS variabile d'ambiente. Ad esempio, impostando RAYON_NUM_THREADS=4 si limiterebbe il pool di thread a 4 thread.
Esempio
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);Sicurezza
Il comportamento è indefinito se circuit o target non sono validi, QkCircuit e QkTarget. QkCircuit non è previsto che sia nullo e il comportamento è indefinito se lo è.
Parametri
- circuit - Un puntatore al circuito su cui eseguire CommutativeCancellation. Questo puntatore al circuito verrà aggiornato con il circuito modificato se il passaggio è in grado di rimuovere qualche porta.
- target - Questo passaggio cercherà di accumulare tutte le rotazioni Z in un gate RZ, P o U1, a seconda di quale sia già utilizzato nel circuito. Se nel circuito non è presente nessuno, questo argomento target (opzionale) viene utilizzato come ripiego per decidere quale gate utilizzare. Se nessuno di RZ, P o U1 è presente nel circuito o nell'obiettivo, le rotazioni Z a singolo qubit non saranno ottimizzate.
- grado_di_approssimazione - Il grado di approssimazione utilizzato nell'analisi delle commutazioni. Deve trovarsi all'interno di
(0, 1].
Risultati
Il codice intero di ritorno, dove 0 rappresenta nessun errore e 1 è usato per indicare che è stato riscontrato un errore durante l'esecuzione del passaggio.
qk_transpiler_pass_standalone_consolidate_blocks
void qk_transpiler_pass_standalone_consolidate_blocks(QkCircuit *circuit, const QkTarget *target, double approximation_degree, bool force_consolidate)
Eseguire il passaggio ConsolidateBlocks su un circuito.
ConsolidateBlocks è un passaggio di transpiler che consolida blocchi consecutivi di porte che operano sugli stessi qubit in una porta unitaria, da risintetizzare successivamente, il che porta a un sottocircuito più ottimale.
Sicurezza
Il comportamento è indefinito se circuit non è un puntatore valido e non nullo a un QkCircuit e se target non è un puntatore valido a un QkTarget.
Parametri
- circuit - Un puntatore al circuito su cui eseguire ConsolidateBlocks.
- target - Un puntatore al target su cui eseguire ConsolidateBlocks.
- grado_di_approssimazione - Un valore fluttuante compreso tra
[0.0, 1.0]oNaN, predefinito a1.0. Più basso approssima di più. - force_consolidate - Forza il consolidamento dei blocchi.
qk_transpiler_pass_standalone_convert_to_pauli_rotations
void qk_transpiler_pass_standalone_convert_to_pauli_rotations(QkCircuit *circuit)
Esegui il ConvertToPauliRotations passaggio sul posto lungo un circuito.
Questo passaggio converte tutte le porte standard (con meno di 4 qubit) presenti nel circuito in una sequenza di QkPauliProductRotation porte e le misurazioni in QkPauliProductMeasurement istruzioni. Si noti che questa fase genera un errore se il circuito contiene porte non standard. Il flusso di lavoro consigliato consiste nel compilare prima in una base standard, mantenendo intatti, ove possibile, i gate di rotazione (come QkGate_RXX e altri), e poi eseguire questa fase.
Sicurezza
Il comportamento è indefinito se non circuit è un puntatore valido e non nullo a un QkCircuit.
Parametri
- circuito – Un puntatore al circuito su cui eseguire il passaggio.
qk_transpiler_pass_standalone_elide_permutations
QkTranspileLayout *qk_transpiler_pass_standalone_elide_permutations(QkCircuit *circuit)
Eseguire il passaggio del transpiler ElidePermutations su un circuito.
Per ulteriori dettagli sul pass, consultare la qk_transpiler_pass_elide_permutations funzione.
Sicurezza
Il comportamento è indefinito se circuit non è un puntatore valido e non nullo a un QkCircuit.
Parametri
- circuit - Un puntatore al circuito su cui eseguire ElidePermutations. Se vengono apportate modifiche, l'oggetto a cui si punta viene modificato al suo posto. In caso di elisione di porte, le allocazioni del circuito originale vengono liberate da questa funzione.
Risultati
l'oggetto di layout contenente la permutazione di uscita indotta dai porte omesse nel circuito. Se non vengono eseguite elisioni, questo sarà un puntatore nullo e il circuito di ingresso rimarrà invariato. È responsabilità del chiamante liberare il layout restituito chiamando 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)
Eseguire il passaggio CheckGateDirection su un circuito.
Per ulteriori dettagli sul pass, consultare la qk_transpiler_pass_check_gate_direction funzione.
Sicurezza
Il comportamento è indefinito se circuit o target non sono puntatori validi e non nulli agli oggetti QkCircuit e QkTarget , rispettivamente.
Parametri
- circuito – Un puntatore al circuito su cui eseguire il passaggio.
- target - Un puntatore al target utilizzato per controllare le direzioni del gate.
Risultati
È vero se e solo se tutte le direzioni dei gate a due qubit soddisfano i vincoli specificati.
qk_transpiler_pass_standalone_gate_direction
void qk_transpiler_pass_standalone_gate_direction(QkCircuit *circuit, const QkTarget *target)
Eseguire il passaggio GateDirection su un circuito.
Per ulteriori dettagli sul pass, consultare la qk_transpiler_pass_gate_direction funzione.
Sicurezza
Il comportamento è indefinito se circuit o target non sono puntatori validi e non nulli agli oggetti QkCircuit e QkTarget , rispettivamente.
Parametri
- circuito – Un puntatore al circuito da modificare in loco.
- target – Un puntatore al target utilizzato per le direzioni dei gate.
qk_transpiler_pass_standalone_inverse_cancellation
void qk_transpiler_pass_standalone_inverse_cancellation(QkCircuit *circuit)
Eseguire il passaggio del transpiler InverseCancellation su un circuito.
Annulla coppie di porte consecutive che sono inverse l'una dell'altra. Le porte annullate sono costituite da coppie di porte autoinvertite:
- 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 coppie di porte inverse:
- (QkGate_T, QkGate_Tdg)
- (QkGate_S, QkGate_Sdg)
- (QkGate_SX, QkGate_SXdg)
- (QkGate_CS, QkGate_CSdg)
Esempio
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);Sicurezza
Il comportamento è indefinito se circuit non è un puntatore valido e non nullo a un QkCircuit.
Parametri
- circuit - Un puntatore al circuito su cui eseguire InverseCancellation. Se il passaggio è in grado di rimuovere qualsiasi porta, il circuito originale sarà sostituito dal circuito prodotto da questo passaggio.
qk_transpiler_pass_standalone_litinski_transformation
void qk_transpiler_pass_standalone_litinski_transformation(QkCircuit *circuit, bool fix_clifford)
Esegui il LitinskiTransformation passaggio sul posto lungo un circuito.
Questo passaggio trasferisce tutte le porte di Clifford alla fine del circuito, convertendo le porte di rotazione di Pauli in QkPauliProductRotation porte e le misurazioni in QkPauliProductMeasurement istruzioni. Si noti che attualmente questo passaggio supporta solo circuiti che contengono porte QkGate_T, QkGate_Tdg QkGate_RZ o come non-Clifford; in caso contrario, genera un errore. Il flusso di lavoro consigliato consiste nel trasporre prima in una base Clifford+RZ e poi eseguire questa fase.
Sicurezza
Il comportamento è indefinito se non circuit è un puntatore valido e non nullo a un QkCircuit.
Parametri
- circuito – Un puntatore al circuito su cui eseguire il passaggio.
- fix_clifford – Se
true, lasciare le porte di Clifford alla fine del circuito. Sefalsevengono omessi.
qk_transpiler_standalone_optimize_1q_sequences
void qk_transpiler_standalone_optimize_1q_sequences(QkCircuit *circuit, const QkTarget *target)
Esegue il passaggio Optimize1qGatesDecomposition in modalità standalone su un circuito.
Questa funzione è multithread e, per impostazione predefinita, potrebbe avviare un pool di thread con un numero di thread pari a quello delle CPU. È possibile regolare il numero di thread tramite la RAYON_NUM_THREADS variabile d'ambiente. Ad esempio, impostando RAYON_NUM_THREADS=4 si limiterebbe il pool di thread a 4 thread.
Sicurezza
Il comportamento è indefinito se circuit non è un puntatore valido e non nullo a un QkCircuit e se target non è un puntatore valido a un QkTarget.
Parametri
- circuito - Un puntatore all'oggetto
QkCircuitda trasformare. - target - Un puntatore all'oggetto
QkTargeto un puntatore nullo. Nel caso in cui venga fornito un puntatore nullo e gli errori dei gate siano sconosciuti, il passaggio sceglierà la sequenza con il minor numero di gate e supporterà tutti i gate della base sul suo insieme di basi di Eulero.
qk_transpiler_pass_standalone_optimize_1q_sequences
void qk_transpiler_pass_standalone_optimize_1q_sequences(QkCircuit *circuit, const QkTarget *target)
Esegue il passaggio Optimize1qGatesDecomposition in modalità standalone su un circuito.
Per ulteriori dettagli sul pass, consultare la qk_transpiler_pass_optimize_1q_sequences funzione.
Questa funzione è multithread e, per impostazione predefinita, potrebbe avviare un pool di thread con un numero di thread pari a quello delle CPU. È possibile regolare il numero di thread tramite la RAYON_NUM_THREADS variabile d'ambiente. Ad esempio, impostando RAYON_NUM_THREADS=4 si limiterebbe il pool di thread a 4 thread.
Sicurezza
Il comportamento è indefinito se circuit non è un puntatore valido e non nullo a un QkCircuit e se target non è un puntatore valido a un QkTarget.
Parametri
- circuito - Un puntatore all'oggetto
QkCircuitda trasformare. - target - Un puntatore all'oggetto
QkTargeto un puntatore nullo. Nel caso in cui venga fornito un puntatore nullo e gli errori dei gate siano sconosciuti, il passaggio sceglierà la sequenza con il minor numero di gate e supporterà tutti i gate della base sul suo insieme di basi di Eulero.
qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure
void qk_transpiler_pass_standalone_remove_diagonal_gates_before_measure(QkCircuit *circuit)
Eseguire il passaggio RemoveDiagonalGatesBeforeMeasure su un circuito.
Per ulteriori dettagli sul pass, consultare la qk_transpiler_pass_remove_diagonal_gates_before_measure funzione.
Sicurezza
Il comportamento è indefinito se circuit non è un puntatore valido e non nullo a un QkCircuit.
Parametri
- circuito – Un puntatore al circuito su cui eseguire questo passaggio.
qk_transpiler_pass_standalone_remove_identity_equivalent
void qk_transpiler_pass_standalone_remove_identity_equivalent(QkCircuit *circuit, const QkTarget *target, double approximation_degree)
Eseguire il passaggio del transpiler RemoveIdentityEquivalent su un circuito.
Per ulteriori dettagli sul pass, consultare la qk_transpiler_pass_remove_identity_equivalent funzione.
Questa funzione è multithread e, per impostazione predefinita, avvia un pool di thread con un numero di thread pari a quello delle CPU. È possibile regolare il numero di thread tramite la variabile d'ambiente RAYON_NUM_THREADS. Ad esempio, impostando RAYON\_NUM\_THREADS=4 si limiterebbe il pool di thread a 4 thread.
Sicurezza
Il comportamento è indefinito se circuit o target non è un puntatore valido e non nullo a QkCircuit e QkTarget.
Parametri
- circuit - Un puntatore al circuito su cui eseguire RemoveIdentityEquivalent. Il circuito a cui si punta verrà aggiornato con il circuito modificato se il passaggio è in grado di rimuovere qualche porta.
- target - L'obiettivo del passaggio RemoveIdentityEquivalent. Se
approximation_degreeè impostato suNAN, la tolleranza per determinare se un'operazione è equivalente all'identità sarà impostata sul tasso di errore riportato nel target. In caso contrario, il sitotargetnon viene utilizzato poiché la tolleranza è indipendente dall'obiettivo. - grado_di_approssimazione - Il grado da approssimare per la verifica dell'equivalenza. Può essere un valore in virgola mobile compreso tra 0 e 1, oppure
NAN. Se il valore è 1, l'approssimazione non è superiore alla precisione in virgola mobile. Per un valore < 1 questo viene utilizzato come fattore di scala per la fedeltà di taglio. Se il valore èNANsi approssima alla fedeltà del gate specificata intarget.
qk_transpiler_pass_standalone_sabre_layout
QkTranspileLayout *qk_transpiler_pass_standalone_sabre_layout(QkCircuit *circuit, const QkTarget *target, const QkSabreLayoutOptions *options)
Eseguire il passaggio del transpiler SabreLayout su un circuito.
Il passaggio SabreLayout sceglie un layout attraverso un instradamento iterativo bidirezionale del circuito di ingresso.
Partendo da un layout iniziale casuale, l'algoritmo esegue un instradamento completo del circuito per arrivare al layout finale. Questo layout finale viene quindi utilizzato come layout iniziale per l'instradamento del circuito inverso. L'algoritmo itera un certo numero di volte finché non trova un layout iniziale che riduca il costo di instradamento completo.
Questo metodo sfrutta la reversibilità dei circuiti quantistici e cerca di includere informazioni globali sul circuito nella scelta del layout iniziale.
Questo passaggio eseguirà sia il layout che l'instradamento e trasformerà il circuito in modo che il layout sia applicato all'ingresso (il che significa che il circuito di uscita avrà dei qubit ancilla allocati per i qubit non utilizzati nella mappa di accoppiamento e i qubit saranno riordinati in modo da corrispondere ai qubit fisici mappati) e quindi sarà applicato l'instradamento. Questo perché il passaggio eseguirà prove di seme in parallelo con diversi semi casuali per selezionare il layout iniziale casuale e quindi selezionare l'uscita instradata che risulta nel minor numero di porte di scambio necessarie. Il calcolo dello swap finale equivale all'esecuzione di un instradamento finale, quindi è più efficiente applicarlo dopo averlo calcolato.
Questa funzione è multithread e lancia un pool di thread con un numero di thread pari al numero di CPU per impostazione predefinita. È possibile regolare il numero di thread con la variabile d'ambiente RAYON_NUM_THREADS . Ad esempio, impostando RAYON_NUM_THREADS=4 si limita il pool di thread a 4 thread.
Riferimenti
[1] Henry Zou e Matthew Treinish e Kevin Hartman e Alexander Ivrii e Jake Lishman. “LightSABRE: Un algoritmo SABRE leggero e migliorato" arXiv:2409.08368
[2] Li, Gushu, Yufei Ding e Yuan Xie. "Affrontare il problema della mappatura dei qubit
per i dispositivi quantistici dell'era NISQ" ASPLOS 2019.
Sicurezza
Il comportamento è indefinito se circuit o target non è un puntatore valido e non nullo a QkCircuit e QkTarget.
Parametri
- circuit - Un puntatore al circuito su cui eseguire SabreLayout. Il circuito viene modificato sul posto e le allocazioni del circuito originale vengono liberate da questa funzione.
- target - Un puntatore al target su cui eseguire SabreLayout
- opzioni - Un puntatore alle opzioni per SabreLayout
Risultati
Il layout transpile che descrive il layout e la permutazione dell'output causati dal passaggio
qk_transpiler_pass_standalone_split_2q_unitaries
QkTranspileLayout *qk_transpiler_pass_standalone_split_2q_unitaries(QkCircuit *circuit, double requested_fidelity, bool split_swaps)
Esegui il passaggio di transpilazione " Split2QUnitaries " su un circuito.
Per ulteriori dettagli sul pass, consultare la qk_transpiler_pass_split_2q_unitaries funzione.
Sicurezza
Il comportamento è indefinito se circuit non è un puntatore valido e non nullo a un QkCircuit.
Parametri
- circuito – Un puntatore modificabile al circuito su cui eseguire l'operazione « Split2QUnitaries ».
- requested_fidelity - Tolleranza consentita per la suddivisione di unitari a due qubit e per le decomposizioni dei gate.
- split_swaps - Se tentare di dividere le porte swap, ottenendo una permutazione dei qubit.
Risultati
Se vengono divisi unitari equivalenti allo scambio, questa funzione restituisce un puntatore a un TranspileLayout che contiene la permutazione indotta da questa ottimizzazione del circuito. Se non sono stati divisi unitari equivalenti allo swap, questo sarà un puntatore nullo.
qk_transpiler_pass_standalone_2q_peephole_optimization
void qk_transpiler_pass_standalone_2q_peephole_optimization(QkCircuit *circuit, const QkTarget *target, double approximation_degree)
Eseguire il passaggio di transpilazione " TwoQubitPeepholeOptimization ".
Per i dettagli sul passaggio, consultare la documentazione della qk_transpiler_pass_2q_peephole_optimization() funzione.
Questa funzione è multithread ed eseguirà l'analisi in parallelo, utilizzando tutti i core disponibili sul sistema locale. Per maggiori dettagli su come gestire il comportamento del threading in Qiskit in generale — il che influirà anche su questo passaggio — è possibile consultare la guida alla configurazione
Esempio
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);
uint32_t forward[2] = {0, 1};
uint32_t reverse[2] = {1, 0};
for (int i = 0; i < 10; i++) {
if (i % 2) {
qk_circuit_gate(qc, QkGate_CX, forward, NULL);
} else {
qk_circuit_gate(qc, QkGate_CX, reverse, NULL);
}
}
qk_transpiler_pass_standalone_2q_peephole_optimization(qc, target, 1.0);
qk_circuit_free(qc);
qk_target_free(target);Sicurezza
Il comportamento è indefinito se circuit o target non è un puntatore valido e non nullo a QkCircuit e QkTarget.
Non è sicuro richiamare questa funzione in un contesto in cui il circuito contiene oggetti di proprietà di Python. Poiché la funzione è internamente multithread, se nel circuito sono presenti porte gestite da Python, i thread di lavoro potrebbero dover acquisire il GIL per accedere agli attributi di tali porte, causando così un deadlock. È necessario utilizzare la classe di spazio TwoQubitPeepholeOptimization “ Python ” per eseguire questa fase, qualora siano presenti elementi del circuito di proprietà di “ Python ”.
Parametri
- circuito – Un puntatore al circuito su cui eseguire l' TwoQubitPeepholeOptimization
- target – Un puntatore alla destinazione su cui eseguire " TwoQubitPeepholeOptimization "
- approximation_degree – manopola euristica utilizzata per l'approssimazione dei circuiti (approssimazione 1.0=no, approssimazione 0.0=maximal ). L'approssimazione può ridurre le dimensioni del circuito sintetizzato, a costo di allontanarsi dall'operatore unitario originale. Se NAN, l'approssimazione del target si basa sulle fedeltà dei gate nel
target.
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)
Eseguire il passaggio del transpiler UnitarySynthesis.
Il passaggio di transpiler UnitarySynthesis sintetizzerà qualsiasi UnitaryGates del circuito in porte disponibili nel target.
Questo passaggio è multithread e, per impostazione predefinita, avvierà potenzialmente un pool di thread con un numero di thread pari a quello delle CPU. È possibile regolare il numero di thread tramite la RAYON_NUM_THREADS variabile d'ambiente. Ad esempio, impostando RAYON_NUM_THREADS=4 si limiterebbe il pool di thread a 4 thread.
Esempio
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);Sicurezza
Il comportamento è indefinito se circuit o target non è un puntatore valido e non nullo a QkCircuit e QkTarget.
Parametri
- circuito - Un puntatore al circuito su cui eseguire UnitarySynthesis
- target - Un puntatore al target su cui eseguire UnitarySynthesis
- min_qubits - Il numero minimo di qubit nell'unitario da sintetizzare. Se l'unitario è inferiore al numero di qubit specificato, non verrà sintetizzato.
- approximation_degree - quadrante euristico usato per l'approssimazione dei circuiti (approssimazione 1.0=no, approssimazione 0.0=maximal ). L'approssimazione può rendere il circuito sintetizzato più economico a costo di allontanarsi dall'unitario originale. Se NAN, l'approssimazione del target si basa sulle fedeltà delle porte in
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)
Utilizzare l'algoritmo VF2 per scegliere un layout (se possibile) per il circuito di ingresso, utilizzando un punteggio euristico sensibile al rumore basato solo sui tassi di errore hardware e non sui gate specifici nel circuito.
Questa funzione corrisponde al passaggio dello VF2Layout spazio dell' Python.
Questa funzione è adatta per l'uso su circuiti che non sono ancora stati completamente trasferiti all'hardware. Se il circuito è già stato completamente ridotto all'hardware e si desidera migliorare il layout per ottenere un grafico di interazione esatto, utilizzare qk_transpile_pass_standalone_vf2_layout_exact invece.
Se questo passaggio trova una soluzione, significa che esiste un "layout perfetto" e che non sono necessari ulteriori mappature o instradamenti. Tuttavia, non sempre esiste una soluzione possibile, oppure una soluzione potrebbe esistere ma non viene trovata entro i limiti specificati quando il passaggio viene chiamato.
Esempio
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);Sicurezza
Il comportamento è indefinito se circuit o non target è un puntatore valido e non nullo a QkCircuit e QkTarget. Il comportamento è indefinito se config è un puntatore non nullo che non punta a un oggetto QkVF2LayoutConfiguration valido (ma un puntatore nullo va bene).
Parametri
- circuito - Un puntatore al circuito su cui eseguire VF2Layout
- target - Un puntatore al target su cui eseguire il passaggio VF2Layout
- config – Un puntatore alla struttura
QkVF2LayoutConfigurationdi configurazione. Se questo puntatore è nullo, vengono utilizzati i valori predefiniti del passaggio. - strict_direction – Se
trueè impostato su, il passaggio terrà conto della direzione dei bordi nella connettività descritta neltarget. In genere, è preferibilefalseimpostare questo valore su, poiché l'euristica di errore è già molto approssimativa e le porte a due qubit possono quasi sempre essere sintetizzate in modo da "invertire" la direzione utilizzando solo porte locali a un qubit e la porta a due qubit nella direzione nativa.
Risultati
Un puntatore a un oggetto risultato che contiene i risultati del passaggio. Questo oggetto è allocato nell'heap e dovrà essere liberato con la qk_vf2_layout_result_free funzione.
qk_transpiler_pass_standalone_vf2_layout_exact
QkVF2LayoutResult *qk_transpiler_pass_standalone_vf2_layout_exact(const QkCircuit *circuit, const QkTarget *target, const QkVF2LayoutConfiguration *config)
Utilizzare l'algoritmo VF2 per scegliere un layout (se possibile) per il circuito di ingresso, utilizzando un punteggio euristico sensibile al rumore che richiede che il risultato sia già pienamente compatibile con l'hardware.
Questa funzione corrisponde al passaggio dello VF2PostLayout spazio Python con strict_direction=True.
Questa funzione è adatta per l'uso su circuiti che sono già stati completamente ridotti all'hardware e ora si sta cercando di vedere se una permutazione di qubit può portare a tassi di errore stimati migliori. Se il circuito è ancora in termini di operazioni non supportate dall'hardware, utilizzare qk_transpile_pass_standalone_vf2_layout_average invece.
In genere, questo passaggio viene eseguito dopo il layout, il routing, la traduzione in un set di base nativo e l'ottimizzazione, in modo che il circuito di input sia già eseguibile sull'hardware con gli indici dei qubit che fanno riferimento ai qubit fisici. Il pass restituirà un risultato che indicherà una delle seguenti opzioni:
- Esiste una scelta migliore per la mappatura iniziale da qubit virtuale a qubit fisico rispetto a quella attualmente utilizzata dal circuito.
- la scelta attuale dei qubit fisici è la migliore che il pass ha trovato entro il suo limite di chiamata.
- non esiste una mappatura virtuale-fisica valida che dia come risultato un circuito eseguibile (o almeno, il passaggio non è riuscito a trovarne una entro i limiti specificati).
In entrambi i primi due casi, qk_vf2_layout_has_match restituirà true. Solo nel primo caso, qk_vf2_layout_has_improvement restituirà true.
Esempio
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);Sicurezza
Il comportamento è indefinito se circuit o non target è un puntatore valido e non nullo a QkCircuit e QkTarget. Il comportamento è indefinito se config è un puntatore non nullo che non punta a un oggetto QkVF2LayoutConfiguration valido (ma un puntatore nullo va bene).
Parametri
- circuito – Un puntatore al circuito su cui eseguire la ricerca del layout.
- target – Un puntatore al target che rappresenta la QPU.
- config – Un puntatore alla struttura
QkVF2LayoutConfigurationdi configurazione. Se questo puntatore è nullo, vengono utilizzati i valori predefiniti del passaggio.
Risultati
Un puntatore a un oggetto risultato che contiene i risultati del passaggio. Questo oggetto è allocato nell'heap e dovrà essere liberato con la qk_vf2_layout_result_free funzione.
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)
Versione obsoleta di qk_transpiler_pass_standalone_vf2_layout_average.
Questa interfaccia legacy non utilizza QkVf2LayoutConfiguratione ha un nome che non chiarisce come gestisce l'euristica di errore (calcola la media su tutti i gate nel QkTarget per un dato qubit o collegamento).
Sostituito da qk_transpiler_pass_standalone_vf2_layout_average().
Sicurezza
I requisiti di sicurezza di qk_transpiler_pass_standalone_vf2_layout_average devono essere rispettati per circuit e target.
Parametri
- circuito – Come in
qk_transpiler_pass_standalone_vf2_layout_average. - target – Come in
qk_transpiler_pass_standalone_vf2_layout_average. - strict_direction – Come in
qk_transpiler_pass_standalone_vf2_layout_average. - call_limit – Come in
qk_vf2_layout_configuration_set_call_limit, ma lo stesso valore viene utilizzato siabeforeper che perafter. - time_limit – Come in
qk_vf2_layout_configuration_set_time_limit. - max_trials – Come in
qk_vf2_layout_configuration_set_max_trials.
Risultati
Come in qk_transpiler_pass_standalone_vf2_layout_average.