QkObs
typedef struct QkObs QkObsUn'osservabile su basi di Pauli che memorizza i suoi dati in un formato qubit-sparse.
Matematica
Questa osservabile rappresenta una somma di stringhe degli operatori di Pauli e dei proiettori di autovalori di Pauli, con ogni termine ponderato per un numero complesso. Cioè, l'osservabile completo è
per i numeri complessi e gli operatori single-qubit che agiscono sui qubit da un alfabeto ristretto . La somma su è la somma dei singoli termini e il prodotto tensoriale produce le stringhe di operatori. L'alfabeto degli operatori a singolo bit consentiti da cui è tratto è costituito dagli operatori di Pauli e dagli operatori di proiezione degli autostati di Pauli. Esplicitamente, questi sono:
Operatore | QkBitTerm | Valore numerico |
|---|---|---|
| (identità) | Non conservato. | Non conservato. |
| (Pauli X) | QkBitTerm_X | 0b0010 (2) |
| (Pauli Y) | QkBitTerm_Y | 0b0011 (3) |
| (Pauli Z) | QkBitTerm_Z | 0b0001 (1) |
| (proiettore all'autostato positivo di X) | QkBitTerm_Plus | 0b1010 (10) |
| (proiettore all'autostato negativo di X) | QkBitTerm_Minus | 0b0110 (6) |
| (proiettore all'autostato positivo di Y) | QkBitTerm_Right | 0b1011 (11) |
| (proiettore all'autostato negativo di Y) | QkBitTerm_Left | 0b0111 (7) |
| (proiettore verso un autostato positivo di Z) | QkBitTerm_Zero | 0b1001 (9) |
| (proiettore all'autostato negativo di Z) | QkBitTerm_One | 0b0101 (5) |
Poiché sono ammessi sia i Paoli che i loro proiettori, l'alfabeto ammesso forma una base sovra-completa dello spazio degli operatori. Ciò significa che non esiste un'unica sommatoria per rappresentare una determinata osservabile. Di conseguenza, il confronto richiede una maggiore attenzione e l'uso di qk_obs_canonicalize su due osservabili matematicamente equivalenti potrebbe non portare alla stessa rappresentazione.
QkObs utilizza la sua particolare base sovracompleta con l'obiettivo di rendere l'"efficienza della misurazione" equivalente all'"efficienza della rappresentazione". Ad esempio, l'osservabile può essere misurata in modo efficiente sull'hardware con semplici misure , ma può essere rappresentata in termini di Paulis solo come , che richiede termini memorizzati . QkObs richiede un solo termine per memorizzarlo. L'aspetto negativo è che non è pratico prendere una matrice arbitraria e trovare la migliore rappresentazione QkObs . In genere si vuole costruire direttamente un QkObs , piuttosto che cercare di decomporlo.
Rappresentazione
La rappresentazione interna di un QkObs memorizza solo gli operatori dei qubit non identici. Questo rende molto più efficiente la rappresentazione di osservabili come ; QkObs richiede una quantità di memoria lineare rispetto al numero totale di qubit. I termini vengono memorizzati compressi, in modo simile al formato compresso delle matrici rade. In questa analogia, i termini della somma sono le "righe" e i termini dei qubit sono le "colonne", dove una voce assente rappresenta l'identità piuttosto che uno zero. Più esplicitamente, la rappresentazione è costituita da quattro array contigui:
Attributo accessibile da | Lunghezza | Descrizione |
|---|---|---|
qk_obs_coeffs | Il moltiplicatore scalare complesso per ogni termine. | |
qk_obs_bit_terms | Ognuno dei termini non identici a singolo qubit per tutti gli operatori, nell'ordine. Questi corrispondono alla non identità nella descrizione della somma, dove le voci sono memorizzate in ordine crescente prima, e in ordine crescente all'interno di ogni termine. | |
qk_obs_indices | Il qubit corrispondente ( ) per ciascuno dei termini di bit. QkObs richiede che questo elenco sia ordinato per termini e gli algoritmi possono fare affidamento sul mantenimento di questo invariante. | |
qk_obs_boundaries | Gli indici che suddividono i termini e gli indici di bit in termini completi. Per il numero di termine , il suo coefficiente complesso è memorizzato all'indice i, e i suoi operatori single-qubit non identici e i loro qubit corrispondenti sono nell'intervallo [boundaries[i], boundaries[i+1]) nei termini e negli indici dei bit, rispettivamente. I confini hanno sempre uno 0 esplicito come primo elemento. |
Il parametro di lunghezza è il numero di termini della somma e può essere interrogato con qk_obs_num_terms. Il parametro è il numero totale di termini single-qubit non identitari e può essere interrogato con qk_obs_len.
Come esempi illustrativi:
- nel caso di un operatore zero, i confini sono di lunghezza 1 (un singolo 0) e tutti gli altri vettori sono vuoti.
- nel caso di un operatore identità completamente semplificato, i limiti sono
{0, 0}, i coefficienti hanno una sola voce e sia i termini di bit che gli indici sono vuoti. - per l'operatore , i confini sono
{0, 2, 4}, i coeff sono{1.0, -1.0}, i termini di bit sono{QkBitTerm_Z, QkBitTerm_Z, QkBitTerm_Y, QkBitTerm_X}e gli indici sono{0, 2, 1, 3}. L'operatore può agire su più di quattro qubit, a seconda del numero di qubit (vedereqk_obs_num_qubits). Si noti che i termini e gli indici a bit singolo sono ordinati in modo termale.
Questi casi non sono speciali, sono pienamente coerenti con le regole e non dovrebbero richiedere una gestione speciale.
Ordinamento canonico
Per una data osservabile matematica, esistono diversi modi di rappresentarla con QkObs. Ad esempio, lo stesso insieme di termini a bit singolo e i loro indici corrispondenti possono comparire più volte nell'osservabile. Dal punto di vista matematico, ciò equivale ad avere un solo termine con tutti i coefficienti sommati. Allo stesso modo, i termini della somma in un QkObs possono essere in qualsiasi ordine pur rappresentando lo stesso osservabile, poiché l'addizione è commutativa (sebbene l'addizione in virgola mobile non sia associativa, QkObs non fornisce garanzie sull'ordine della somma).
Queste due categorie di degenerazione della rappresentazione possono far sì che l'operatore di uguaglianza, qk_obs_equal, affermi che due osservabili non sono uguali, nonostante rappresentino lo stesso oggetto. In questi casi, può essere conveniente definire una forma canonica che permetta di confrontare strutturalmente le osservabili. È possibile mettere un QkObs in forma canonica utilizzando la funzione qk_obs_canonicalize . L'ordine preciso dei termini nell'ordinamento canonico non è specificato e può cambiare da una versione all'altra di Qiskit. All'interno della stessa versione di Qiskit, tuttavia, è possibile confrontare due osservabili dal punto di vista strutturale, confrontando le loro forme semplificate.
Se si desidera tenere conto della tolleranza in virgola mobile nel confronto, è più sicuro utilizzare una ricetta come:
bool equivalent(QkObs *left, QkObs *right, double tol) {
// compare a canonicalized version of left - right to the zero observable
QkObs *neg_right = qk_obs_multiply(right, &(QkComplex64){-1, 0});
QkObs *diff = qk_obs_add(left, neg_right);
QkObs *canonical = qk_obs_canonicalize(diff, tol);
QkObs *zero = qk_obs_zero(qk_obs_num_qubits(left));
bool equiv = qk_obs_equal(diff, zero);
// free all temporary variables
qk_obs_free(neg_right);
qk_obs_free(diff);
qk_obs_free(canonical);
qk_obs_free(zero);
return equiv;
}La forma canonica prodotta da qk_obs_canonicalize non è in grado di rilevare universalmente tutte le osservabili equivalenti a causa dell'alfabeto di basi troppo completo.
Indicizzazione
I singoli termini di somma osservabili in QkObs sono accessibili tramite qk_obs_term e restituiscono oggetti di tipo QkObsTerm. Questi termini contengono campi con il coefficiente del termine, i suoi termini di bit, gli indici e il numero di qubit su cui è definito. Insieme alle informazioni sul numero di termini, è possibile iterare su tutti i termini osservabili come
size_t num_terms = qk_obs_num_terms(obs); // obs is QkObs*
for (size_t i = 0; i < num_terms; i++) {
QkObsTerm term; // allocate term on stack
int exit = qk_obs_term(obs, i, &term); // get the term (exit > 0 upon index errors)
// do something with the term...
}Il popolamento di un QkObsTerm tramite qk_obs_term farà riferimento ai dati del QkObs originale. La modifica dei termini o degli indici dei bit cambia l'osservabile e può lasciarla in uno stato incoerente.
Costruzioni
QkObs può essere costruito inizializzando un'osservabile vuota (con qk_obs_zero) e aggiungendo iterativamente termini (con qk_obs_add_term). In alternativa, un'osservabile può essere costruita da dati "grezzi" (con qk_obs_new) se tutti i dati interni sono specificati. Ciò richiede attenzione per garantire che i dati siano coerenti e risultino in un osservabile valido.
Funzione | Riepilogo |
|---|---|
qk_obs_zero | Costruire un'osservabile vuota su un dato numero di qubit. |
qk_obs_identity | Costruire l'osservabile identità su un dato numero di qubit. |
qk_obs_new | Costruire un osservabile dagli array di dati grezzi. |
Manipolazione matematica
QkObs supporta le operazioni aritmetiche fondamentali tra osservabili o con scalari. Sarai in grado di:
- aggiungere due osservabili utilizzando
qk_obs_addeqk_obs_add_inplace - moltiplicare per un numero complesso con
qk_obs_multiplyeqk_obs_multiply_inplace - comporre (moltiplicare) due osservabili tramite
qk_obs_composeeqk_obs_compose_map - calcolare
left + scalar * rightper due grandezze osservabili e uno scalare complesso conqk_obs_scaled_addeqk_obs_scaled_add_inplace
Funzioni
qk_obs_zero
QkObs *qk_obs_zero(uint32_t num_qubits)
Costruire l'osservabile zero (senza termini).
Esempio
QkObs *zero = qk_obs_zero(100);Parametri
- num_qubit - Il numero di qubit su cui è definita l'osservabile.
Risultati
Un puntatore all'osservabile creato.
qk_obs_identity
QkObs *qk_obs_identity(uint32_t num_qubits)
Costruire l'osservabile identità.
Esempio
QkObs *identity = qk_obs_identity(100);Parametri
- num_qubit - Il numero di qubit su cui è definita l'osservabile.
Risultati
Un puntatore all'osservabile creato.
qk_obs_new
QkObs *qk_obs_new(uint32_t num_qubits, uint64_t num_terms, uint64_t num_bits, QkComplex64 *coeffs, QkBitTerm *bit_terms, uint32_t *indices, size_t *boundaries)
Costruire una nuova osservabile dai dati grezzi.
Uno qualsiasi degli argomenti di tipo puntatore può essere solo NULL se la sua lunghezza corrispondente è pari a zero.
Esempio
// define the raw data for the 100-qubit observable |01><01|_{0, 1} - |+-><+-|_{98, 99}
uint32_t num_qubits = 100;
uint64_t num_terms = 2; // we have 2 terms: |01><01|, -1 * |+-><+-|
uint64_t num_bits = 4; // we have 4 non-identity bits: 0, 1, +, -
QkComplex64 coeffs[] = {{1, 0}, {-1, 0}};
QkBitTerm bits[4] = {QkBitTerm_Zero, QkBitTerm_One, QkBitTerm_Plus, QkBitTerm_Minus};
uint32_t indices[4] = {0, 1, 98, 99}; // <-- e.g. {1, 0, 99, 98} would be invalid
size_t boundaries[3] = {0, 2, 4};
QkObs *obs = qk_obs_new(
num_qubits, num_terms, num_bits, coeffs, bits, indices, boundaries
);
qk_obs_free(obs);Sicurezza
Il comportamento è indefinito se una delle seguenti condizioni è violata:
coeffsè un puntatore ad una matriceQkComplex64di lunghezzanum_termsbit_termsè un puntatore a una matrice di elementi validi diQkBitTermdi lunghezzanum_bitsindicesè un puntatore a una matriceuint32_tdi lunghezzanum_bits, ordinata per termini in ordine rigorosamente crescente e ogni elemento è più piccolo dinum_qubitsboundariesè un puntatore a una matricesize_tdi lunghezzanum_terms + 1, ordinata in ordine crescente, il cui primo elemento è 0 e l'ultimo elemento è più piccolo dinum_terms
Parametri
- num_qubit - Il numero di qubit su cui è definita l'osservabile.
- num_termini - Il numero di termini.
- num_bits - Il numero totale di termini di bit non identici.
- coeff - Puntatore al primo elemento dell'array dei coefficienti, di lunghezza
num_terms. - bit_terms - Puntatore al primo elemento dell'array di termini di bit, di lunghezza
num_bits. - indici - Un puntatore al primo elemento dell'array degli indici, di lunghezza
num_bits. Si noti che, per ogni termine, questi devono essere ordinati in modo incrementale. - boundaries - Puntatore al primo elemento dell'array boundaries, di lunghezza
num_terms + 1.
Risultati
Se i dati di input sono coerenti e la costruzione ha successo, il risultato è un puntatore all'osservabile. Altrimenti viene restituito un puntatore nullo.
qk_obs_free
void qk_obs_free(QkObs *obs)
Liberare l'osservabile.
Esempio
QkObs *obs = qk_obs_zero(100);
qk_obs_free(obs);Sicurezza
Il comportamento è indefinito se obs non è nullo o un puntatore valido a un QkObs.
Parametri
- obs - Un puntatore all'osservabile da liberare.
qk_obs_add_term
QkExitCode qk_obs_add_term(QkObs *obs, const QkObsTerm *cterm)
Aggiungere un termine all'osservabile.
Esempio
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
QkExitCode exit_code = qk_obs_add_term(obs, &term);Sicurezza
Il comportamento è indefinito se viene violato uno dei seguenti punti:
obsè un puntatore valido e non nullo a un oggettoQkObsctermè un puntatore valido e non nullo a un oggettoQkObsTerm
Parametri
- obs - Un puntatore all'osservabile.
- cterm - Un puntatore al termine da aggiungere.
Risultati
Un codice di uscita. Questo è >0 se il termine è incoerente o se l'aggiunta del termine fallisce.
qk_obs_term
QkExitCode qk_obs_term(QkObs *obs, uint64_t index, QkObsTerm *out)
Ottenere un termine osservabile per riferimento.
Un QkObsTerm contiene puntatori agli indici e ai bit del termine, che possono essere utilizzati per modificare i dati interni dell'osservabile. Questo può lasciare l'osservabile in uno stato incoerente e dovrebbe essere evitato, a meno che non si presti molta attenzione. In genere è più sicuro costruire un nuovo osservabile invece di tentare modifiche in-place.
Esempio
QkObs *obs = qk_obs_identity(100);
QkObsTerm term;
QkExitCode exit_code = qk_obs_term(obs, 0, &term);
// out-of-bounds indices return an error code
// QkExitCode error = qk_obs_term(obs, 12, &term);Sicurezza
Il comportamento è indefinito se viene violato uno qualsiasi dei seguenti punti
obsè un puntatore valido e non nullo a un oggettoQkObsoutè un puntatore valido e non nullo a un oggettoQkObsTerm
Parametri
- obs - Un puntatore all'osservabile.
- indice - L'indice del termine da ottenere.
- out - Puntatore a
QkObsTermutilizzato per restituire il termine osservabile.
Risultati
Un codice di uscita.
qk_obs_num_terms
size_t qk_obs_num_terms(const QkObs *obs)
Ottenere il numero di termini dell'osservabile.
Esempio
QkObs *obs = qk_obs_identity(100);
size_t num_terms = qk_obs_num_terms(obs); // num_terms==1Sicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
Parametri
- obs - Un puntatore all'osservabile.
Risultati
Il numero di termini dell'osservabile.
qk_obs_num_qubits
uint32_t qk_obs_num_qubits(const QkObs *obs)
Ottiene il numero di qubit su cui è definita l'osservabile.
Esempio
QkObs *obs = qk_obs_identity(100);
uint32_t num_qubits = qk_obs_num_qubits(obs); // num_qubits==100Sicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
Parametri
- obs - Un puntatore all'osservabile.
Risultati
Il numero di qubit su cui è definita l'osservabile.
qk_obs_len
size_t qk_obs_len(const QkObs *obs)
Ottiene il numero di termini/indici di bit nell'osservabile.
Esempio
QkObs *obs = qk_obs_identity(100);
size_t len = qk_obs_len(obs); // len==0, as there are no non-trivial bit termsSicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
Parametri
- obs - Un puntatore all'osservabile.
Risultati
Il numero di termini dell'osservabile.
qk_obs_coeffs
QkComplex64 *qk_obs_coeffs(QkObs *obs)
Ottenere un puntatore ai coefficienti.
Questo può essere usato per leggere e modificare i coefficienti dell'osservabile. Il puntatore risultante è valido per la lettura di qk_obs_num_terms(obs) elementi di QkComplex64.
Esempio
QkObs *obs = qk_obs_identity(100);
size_t num_terms = qk_obs_num_terms(obs);
QkComplex64 *coeffs = qk_obs_coeffs(obs);
for (size_t i = 0; i < num_terms; i++) {
printf("%f + i%f\n", coeffs[i].re, coeffs[i].im);
}Sicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
Parametri
- obs - Un puntatore all'osservabile.
Risultati
Un puntatore ai coefficienti.
qk_obs_indices
uint32_t *qk_obs_indices(QkObs *obs)
Ottenere un puntatore agli indici.
Può essere usato per leggere e modificare gli indici dell'osservabile. Il puntatore risultante è valido per la lettura di qk_obs_len(obs) elementi di dimensione uint32_t.
Esempio
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t term_indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, term_indices, num_qubits};
qk_obs_add_term(obs, &term);
size_t len = qk_obs_len(obs);
uint32_t *indices = qk_obs_indices(obs);
for (size_t i = 0; i < len; i++) {
printf("index %i: %i\n", i, indices[i]);
}
qk_obs_free(obs);Sicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
Parametri
- obs - Un puntatore all'osservabile.
Risultati
Un puntatore agli indici.
qk_obs_boundaries
size_t *qk_obs_boundaries(QkObs *obs)
Ottenere un puntatore ai confini del termine.
Questo può essere usato per leggere e modificare i limiti dei termini dell'osservabile. Il puntatore risultante è valido per la lettura di qk_obs_num_terms(obs) + 1 elementi di dimensione size_t.
Esempio
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term);
size_t num_terms = qk_obs_num_terms(obs);
size_t *boundaries = qk_obs_boundaries(obs);
for (size_t i = 0; i < num_terms + 1; i++) {
printf("boundary %i: %i\n", i, boundaries[i]);
}Sicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
Parametri
- obs - Un puntatore all'osservabile.
Risultati
Un puntatore ai confini.
qk_obs_bit_terms
QkBitTerm *qk_obs_bit_terms(QkObs *obs)
Ottenere un puntatore ai termini di bit.
Questo può essere usato per leggere e modificare i termini di bit dell'osservabile. Il puntatore risultante è valido per la lettura di qk_obs_len(obs) elementi di dimensione uint8_t.
Esempio
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term);
size_t len = qk_obs_len(obs);
QkBitTerm *bits = qk_obs_bit_terms(obs);
for (size_t i = 0; i < len; i++) {
printf("bit term %i: %i\n", i, bits[i]);
}
qk_obs_free(obs);Sicurezza
Il comportamento è indefinito obs se il puntatore non è valido QkObs o non è nullo, oppure se nel puntatore QkBitTerm risultante vengono scritti valori non validi.
Parametri
- obs - Un puntatore all'osservabile.
Risultati
Un puntatore ai termini di bit.
qk_obs_multiply
QkObs *qk_obs_multiply(const QkObs *obs, const QkComplex64 *coeff)
Moltiplicare l'osservabile per un coefficiente complesso.
Esempio
QkObs *obs = qk_obs_identity(100);
QkComplex64 coeff = {2, 0};
QkObs *result = qk_obs_multiply(obs, &coeff);Sicurezza
Il comportamento è indefinito se viene violato uno qualsiasi dei seguenti punti
obsè un puntatore valido e non nullo a un oggettoQkObscoeffè un puntatore valido e non nullo a un oggettoQkComplex64
Parametri
- obs - Un puntatore all'osservabile.
- coeff - Il coefficiente con cui moltiplicare l'osservabile.
Risultati
Un puntatore al risultato obs * coeff.
qk_obs_multiply_inplace
void qk_obs_multiply_inplace(QkObs *obs, const QkComplex64 *coeff)
Moltiplica l'osservabile in loco per un coefficiente complesso.
Esempio
QkObs *obs = qk_obs_identity(100);
QkComplex64 coeff = {2, 0};
qk_obs_multiply_inplace(obs, &coeff);Sicurezza
Il comportamento è indefinito se viene violato uno qualsiasi dei seguenti punti
obsè un puntatore valido e non nullo a un oggettoQkObscoeffè un puntatore valido e non nullo a un oggettoQkComplex64
Parametri
- obs - Un puntatore all'osservabile.
- coeff - Il coefficiente con cui moltiplicare l'osservabile.
qk_obs_add
QkObs *qk_obs_add(const QkObs *left, const QkObs *right)
Aggiungere due osservabili.
Esempio
QkObs *left = qk_obs_identity(100);
QkObs *right = qk_obs_zero(100);
QkObs *result = qk_obs_add(left, right);Sicurezza
Il comportamento è indefinito se left o right non sono puntatori non nulli validi a QkObs.
Parametri
- left - Puntatore all'osservabile di sinistra.
- right - Puntatore all'osservabile destro.
Risultati
Un puntatore al risultato left + right.
qk_obs_add_inplace
void qk_obs_add_inplace(QkObs *left, const QkObs *right)
Aggiungi un osservabile a uno esistente.
Esempio
QkObs *left = qk_obs_identity(100);
QkObs *right = qk_obs_zero(100);
qk_obs_add_inplace(left, right);Sicurezza
Il comportamento è indefinito se left o right non sono puntatori non nulli validi a QkObs.
Parametri
- left - Puntatore all'osservabile di sinistra.
- right - Puntatore all'osservabile destro.
qk_obs_scaled_add
QkObs *qk_obs_scaled_add(const QkObs *left, const QkObs *right, const QkComplex64 *factor)
Aggiungi due osservabili modificando i coefficienti di quello a destra.
Esempio
QkObs *left = qk_obs_zero(100);
QkObs *right = qk_obs_identity(100);
QkComplex64 factor = {2, 0};
QkObs *result = qk_obs_scaled_add(left, right, &factor);Sicurezza
Il comportamento è indefinito se left o right non sono puntatori non nulli validi a QkObs.
Parametri
- left - Puntatore all'osservabile di sinistra.
- right - Puntatore all'osservabile destro.
- fattore – Il fattore con cui moltiplicare i coefficienti.
Risultati
Un puntatore di proprietà al risultato left + factor * right.
qk_obs_scaled_add_inplace
void qk_obs_scaled_add_inplace(QkObs *left, const QkObs *right, const QkComplex64 *factor)
Aggiungi un osservabile ridimensionato a uno esistente.
Esempio
QkObs *left = qk_obs_zero(100);
QkObs *right = qk_obs_identity(100);
QkComplex64 factor = {2, 0};
qk_obs_scaled_add_inplace(left, right, &factor);Sicurezza
Il comportamento è indefinito se left o right non sono puntatori non nulli validi a QkObs.
Parametri
- left - Puntatore all'osservabile di sinistra.
- right - Puntatore all'osservabile destro.
- fattore – Il fattore con cui moltiplicare i coefficienti.
qk_obs_compose
QkObs *qk_obs_compose(const QkObs *first, const QkObs *second)
Comporre (moltiplicare) due osservabili.
Esempio
QkObs *first = qk_obs_zero(100);
QkObs *second = qk_obs_identity(100);
QkObs *result = qk_obs_compose(first, second);Sicurezza
Il comportamento è indefinito se first o second non sono puntatori non nulli validi a QkObs.
Parametri
- primo - Un osservabile.
- secondo - L'altro osservabile.
Risultati
first.compose(second) che equivale all'osservabile result = second @ first, in termini di moltiplicazione matriciale @.
qk_obs_compose_map
QkObs *qk_obs_compose_map(const QkObs *first, const QkObs *second, const uint32_t *qargs)
Comporre (moltiplicare) due osservabili secondo un ordine di qubit personalizzato.
In particolare, ciò consente di comporre due osservabili di dimensioni diverse.
Esempio
QkObs *first = qk_obs_zero(100);
QkObs *second = qk_obs_identity(100);
QkObs *result = qk_obs_compose(first, second);Sicurezza
Per chiamare questa funzione in modo sicuro
firsteseconddevono essere puntatori validi e non nulli aQkObs\ sqargsdeve puntare a un array diuint32_t, leggibile per gli elementi diqk_obs_num_qubits(second)(cioè il numero di qubit insecond)
Parametri
- primo - Un osservabile.
- secondo - L'altro osservabile. Il numero di qubit deve corrispondere alla lunghezza di
qargs. - qargs - Gli argomenti dei qubit specificano quali indici in
firstassociare a quelli insecond.
Risultati
first.compose(second) che equivale all'osservabile result = second @ first, in termini di moltiplicazione matriciale @.
qk_obs_apply_layout
QkExitCode qk_obs_apply_layout(QkObs *obs, const uint32_t *layout, uint32_t num_qubits)
Applicare una nuova disposizione dei qubit all'osservabile.
Il layout è impostato da un array layout di nuovi indici, che specifica che il qubit all'indice corrente i è rietichettato all'indice layout[i]. Il numero di qubit su cui agisce l'osservabile può essere esteso impostando un num_qubits più grande di quello dell'osservabile corrente.
Esempio
Questa interfaccia consente di rietichettare ed estendere gli indici dei qubit:
QkObs *obs = qk_obs_zero(4);
// add a term to the observable
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t qubits[3] = {1, 2, 3};
complex double coeff = 1;
QkObsTerm term = {coeff, 3, bit_terms, qubits, 4};
qk_obs_add_term(obs, &term);
uint32_t layout[3] = {0, 10, 9}; // qubit mapping is: 0->0, 1->10, 2->9
uint32_t num_output_qubits = 11;
QkExitCode exit = qk_obs_apply_layout(obs, layout, num_output_qubits);In un flusso di lavoro del compilatore, questa funzione può essere utilizzata per applicare un QkTranspileLayout* ottenuto da un passaggio di transpiler, chiamato transpile_layout nell'esempio seguente:
// get the number of output qubits
uint32_t num_output_qubits = qk_transpile_layout_num_output_qubits(transpile_layout);
// get the layout including the ancillas (hence the ``false`` in the function call)
uint32_t *layout = malloc(sizeof(uint32_t) * num_output_qubits);
qk_transpile_layout_final_layout(transpile_layout, false, layout);
// apply the layout
QkExitCode exit = qk_obs_apply_layout(obs, layout, num_output_qubits);
// free the layout array
free(layout);Sicurezza
Il comportamento è indefinito se obs non è un puntatore valido e non nullo a QkObs o se layout non è un puntatore valido e non nullo a una sequenza di qk_obs_num_qubits(obs) elementi consecutivi di uint32_t.
Parametri
- obs - Un puntatore all'osservabile, che verrà modificato al suo posto in caso di successo. Controllare il codice di uscita per verificare che il layout sia stato applicato correttamente.
- layout - Un puntatore al layout. Il puntatore deve puntare a un array di
qk_obs_num_qubits(obs)elementi di tipouint32_t. Ogni elemento deve avere valori in[0, num_qubits). - num_qubit - Il numero di qubit in uscita.
Risultati
Un codice di uscita.
QkExitCode_Successin caso di successoQkExitCode_DuplicteIndexErrorse sono stati trovati indici di qubit duplicatiQkExitCode_MismatchedQubitssenum_qubitsè più piccolo del numero di qubit dell'osservabileQkExitCode_IndexErrorper qualsiasi altro errore di indice, come ad esempio valori non validi inlayout.
qk_obs_canonicalize
QkObs *qk_obs_canonicalize(const QkObs *obs, double tol)
Calcolare la rappresentazione canonica dell'osservabile.
Esempio
QkObs *iden = qk_obs_identity(100);
QkObs *two = qk_obs_add(iden, iden);
double tol = 1e-6;
QkObs *canonical = qk_obs_canonicalize(two, tol);Sicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
Parametri
- obs - Un puntatore all'osservabile.
- tol - La tolleranza al di sotto della quale i coefficienti sono considerati nulli.
Risultati
La rappresentazione canonica dell'osservabile.
qk_obs_copy
QkObs *qk_obs_copy(const QkObs *obs)
Copiare l'osservabile.
Esempio
QkObs *original = qk_obs_identity(100);
QkObs *copied = qk_obs_copy(original);Sicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
Parametri
- obs - Un puntatore all'osservabile.
Risultati
Un puntatore a una copia dell'osservabile.
qk_obs_equal
bool qk_obs_equal(const QkObs *obs, const QkObs *other)
Confrontare due osservabili per verificarne l'uguaglianza.
Si noti che questo non confronta l'uguaglianza matematica, ma l'uguaglianza dei dati. Ciò significa che due osservabili potrebbero rappresentare la stessa osservabile ma non essere paragonate come uguali.
Esempio
QkObs *observable = qk_obs_identity(100);
QkObs *other = qk_obs_identity(100);
bool are_equal = qk_obs_equal(observable, other);Sicurezza
Il comportamento è indefinito se obs o other non sono puntatori non nulli validi a QkObs.
Parametri
- obs - Puntatore a un osservabile.
- other - Puntatore a un altro osservabile.
Risultati
true se le osservabili sono uguali, false altrimenti.
qk_obs_str
char *qk_obs_str(const QkObs *obs)
Restituisce una rappresentazione in stringa di QkObs.
Esempio
QkObs *obs = qk_obs_identity(100);
char *string = qk_obs_str(obs);
qk_str_free(string);
qk_obs_free(obs);Sicurezza
Il comportamento è indefinito obs non è un puntatore non nullo valido a QkObs.
La stringa non deve essere liberata con il normale free del C, ma si deve usare qk_str_free per liberare la memoria consumata dalla stringa. La mancata chiamata a qk_str_free provoca una perdita di memoria.
Non modificare la lunghezza della stringa dopo che è stata restituita (scrivendo un byte nul da qualche parte all'interno della stringa o rimuovendo quello finale), anche se i valori possono essere mutati.
Parametri
- obs - Un puntatore a
QkObsper cui ottenere la stringa.
Risultati
Un puntatore a un array di caratteri nul-terminato della rappresentazione di stringa per obs
qk_str_free
void qk_str_free(char *string)
Libera una rappresentazione di stringa.
Sicurezza
Il comportamento è indefinito se str non è un puntatore restituito da qk_obs_str o qk_obsterm_str.
Parametri
- string - Un puntatore alla rappresentazione della stringa restituita da
qk_obs_stroqk_obsterm_str.
qk_obs_to_python
PyObject *qk_obs_to_python(QkObs *obs)
Trasferisci la proprietà di un QkObs oggetto a Python.
Non è sicuro utilizzare il QkObs puntatore dopo aver chiamato questa funzione. In particolare, non dovresti cercare di ripulirlo o liberarlo. Chi effettua la chiamata deve essere il proprietario dell'oggetto QkObs, non possedere un riferimento preso in prestito (ad esempio, un oggetto QkObs * recuperato da non qk_obs_borrow_from_python è di sua proprietà).
Sicurezza
Chi chiama deve essere collegato a un interprete dell' Python. Il comportamento è indefinito se non obs è un puntatore non nullo valido a un oggetto inizializzato e di proprietà dell'utente QkObs.
Parametri
- obs – L'oggetto di proprietà.
Risultati
Un riferimento di tipo " Python " all'oggetto.
qk_obs_borrow_from_python
QkObs *qk_obs_borrow_from_python(PyObject *ob)
Recupera un QkObs puntatore da un oggetto Python.
Questa operazione prende in prestito un riferimento a un oggetto di tipo Python ed estrae il QkObs puntatore corrispondente, se è del tipo corretto. Il puntatore restituito viene preso in prestito dal ob puntatore. Se il non PyObject è del tipo corretto, il valore restituito è NULL e viene impostato lo stato di eccezione dell'interprete di Python.
Per chiamare questa funzione è necessario essere collegati a un interprete Python.
È inoltre possibile utilizzare qk_obs_convert_from_python, che dal punto di vista logico è esattamente identico a questa funzione, ma può essere utilizzato direttamente come funzione di "conversione" per la PyArg_Parse* famiglia di funzioni di conversione di Python.
Sicurezza
Chi chiama deve essere collegato a un interprete dell' Python. Il comportamento è indefinito se non ob è un puntatore valido e non nullo a un oggetto Python.
Parametri
- ob – Un oggetto preso in prestito dall' Python.
Risultati
Un puntatore all'oggetto nativo, oppure NULL se l'oggetto Python è di tipo errato.
qk_obs_convert_from_python
int qk_obs_convert_from_python(PyObject *object, void *address)
Recupera un QkObs puntatore da un oggetto Python.
Questa operazione prende in prestito un riferimento di tipo Python ed estrae il QkObs puntatore corrispondente in address,, se è del tipo corretto. Il puntatore restituito viene preso in prestito dal object puntatore. Se il tipo PyObject non è corretto, il valore restituito è 1, viene impostato lo stato di eccezione dell'interprete di Python e e address rimane invariato.
Per chiamare questa funzione è necessario essere collegati a un interprete Python.
Puoi anche usare qk_obs_borrow_from_python, che dal punto di vista logico è esattamente uguale a questo, ma presenta una sintassi più intuitiva per l'uso diretto.
Sicurezza
Chi chiama deve essere collegato a un interprete dell' Python. Il comportamento è indefinito se non object è un puntatore valido e non nullo a un oggetto Python, oppure se non address è un puntatore a dati scrivibili del tipo corretto.
Parametri
- oggetto – Un oggetto Python preso in prestito.
- destinazione – La posizione in cui scrivere l'output.
Risultati
1 in caso di successo, 0 in caso di fallimento.