Codificarea datelor
Introducere și notații
Pentru a folosi un algoritm cuantic, datele clasice trebuie aduse cumva într-un circuit cuantic. Acest proces este denumit de obicei codificarea datelor, dar mai este numit și încărcarea datelor. Reamintește-ți din lecțiile anterioare noțiunea de mapare a caracteristicilor, adică o mapare a trăsăturilor de date dintr-un spațiu în altul. Simpla transferare a datelor clasice pe un calculator cuantic este un tip de mapare și ar putea fi numită mapare a caracteristicilor. În practică, mapările de caracteristici încorporate în Qiskit (cum ar fi z_feature_map și zz_feature_map) vor include de obicei straturi de rotație și straturi de împletire care extind starea la multe dimensiuni în spațiul Hilbert. Acest proces de codificare este o parte critică a algoritmilor de învățare automată cuantică și le afectează direct capacitățile computaționale.
Unele dintre tehnicile de codificare de mai jos pot fi simulate eficient clasic; acest lucru este deosebit de ușor de observat în metodele de codificare care produc stări produs (adică nu împletesc qubiți). Și ține minte că utilitatea cuantică este cel mai probabil să apară acolo unde complexitatea de tip cuantic a setului de date este bine potrivită cu metoda de codificare. Astfel, este foarte probabil să ajungi să îți scrii propriile circuite de codificare. Aici prezentăm o varietate largă de strategii posibile de codificare doar pentru ca tu să le poți compara și contrasta, și să vezi ce este posibil. Există câteva afirmații foarte generale care pot fi făcute despre utilitatea tehnicilor de codificare. De exemplu, efficient_su2 (vezi mai jos) cu o schemă completă de împletire este mult mai probabil să capteze trăsăturile cuantice ale datelor decât metodele care produc stări produs (cum ar fi z_feature_map). Dar asta nu înseamnă că efficient_su2 este suficientă sau suficient de bine adaptată setului tău de date pentru a produce o accelerare cuantică. Asta necesită o analiză atentă a structurii datelor modelate sau clasificate. Există și un echilibru de găsit în privința adâncimii circuitului, deoarece multe mapări de caracteristici care împletesc complet qubiții dintr-un circuit produc circuite foarte adânci, prea adânci pentru a obține rezultate utilizabile pe calculatoarele cuantice actuale.
Notații
Un set de date este un ansamblu de vectori de date: , unde fiecare vector este -dimensional, adică . Aceasta ar putea fi extins la trăsături de date complexe. În această lecție, putem folosi ocazional aceste notații pentru setul complet și elementele sale specifice, cum ar fi . Dar ne vom referi în principal la încărcarea unui singur vector din setul nostru de date la un moment dat și vom face adesea referire pur și simplu la un singur vector de trăsături ca .
În plus, este obișnuit să se utilizeze simbolul pentru a face referire la maparea de caracteristici a vectorului de date . Specific în informatica cuantică, este obișnuit să se facă referire la mapările din informatica cuantică folosind o notație care subliniază natura unitară a acestor operații. Cineva ar putea folosi corect același simbol pentru ambele; ambele sunt mapări de caracteristici. Pe parcursul acestui curs, tindem să folosim:
- când discutăm mapările de caracteristici în învățarea automată, în general, și
- când discutăm implementările circuitelor de mapări de caracteristici.
Normalizare și pierdere de informații
În învățarea automată clasică, trăsăturile datelor de antrenament sunt adesea „normalizate" sau rescalate, ceea ce îmbunătățește adesea performanța modelului. O modalitate obișnuită de a face acest lucru este utilizarea normalizării min-max sau standardizarea. În normalizarea min-max, coloanele de trăsături ale matricei de date (să spunem trăsătura ) sunt normalizate:
unde min și max se referă la minimul și maximul trăsăturii pe cei vectori de date din setul de date . Toate valorile trăsăturilor cad apoi în intervalul unitar: pentru toți , .
Normalizarea este, de asemenea, un concept fundamental în mecanica cuantică și informatica cuantică, dar este ușor diferită de normalizarea min-max. Normalizarea în mecanica cuantică impune ca lungimea (în contextul informaticii cuantice, norma-2) a unui vector de stare să fie egală cu unitatea: , asigurând că probabilitățile de măsurare se sumează la 1. Starea este normalizată prin împărțirea la norma-2; adică prin rescalare:
În informatica cuantică și mecanica cuantică, aceasta nu este o normalizare impusă de oameni asupra datelor, ci o proprietate fundamentală a stărilor cuantice. În funcție de schema de codificare, această constrângere poate afecta modul în care datele tale sunt rescalate. De exemplu, în codificarea pe amplitudine (vezi mai jos), vectorul de date este normalizat conform cerinței din mecanica cuantică, iar aceasta afectează scalarea datelor care urmează să fie codificate. În codificarea pe fază, se recomandă rescalarea valorilor trăsăturilor astfel încât pentru a nu exista pierderi de informații din cauza efectului modulo- al codificării pe unghiul de fază al unui qubit[1,2].
Metode de codificare
În următoarele câteva secțiuni, vom face referire la un mic set de date clasic exemplu format din vectori de date, fiecare cu trăsături:
În notația introdusă mai sus, am putea spune că a trăsătură a celui de-al vector de date din setul nostru este de exemplu.
Codificarea pe bază
Codificarea pe bază codifică un șir clasic de biți într-o stare de bază computațională a unui sistem de qubiți. Luăm ca exemplu Aceasta poate fi reprezentată ca un șir de biți ca , și de un sistem de qubiți ca starea cuantică . Mai general, pentru un șir de biți: , starea corespunzătoare de qubiți este cu pentru . Rețineți că aceasta este doar pentru o singură trăsătură.
Codificarea pe bază în informatica cuantică reprezintă fiecare bit clasic ca un qubit separat, mapând direct reprezentarea binară a datelor pe stările cuantice din baza computațională. Când mai multe trăsături trebuie codificate, fiecare trăsătură este mai întâi convertită în forma sa binară și apoi atribuită unui grup distinct de qubiți — câte un grup per trăsătură — unde fiecare qubit reflectă un bit în reprezentarea binară a acelei trăsături.
Ca exemplu, să codificăm vectorul (5, 7, 0).
Presupunem că toate trăsăturile sunt stocate în patru biți (mai mult decât avem nevoie, dar suficient pentru a reprezenta orice număr întreg cu o singură cifră în baza 10):
5 → binar 0101
7 → binar 0111
0 → binar 0000
Aceste șiruri de biți sunt atribuite la trei seturi de câte patru qubiți, deci starea de bază globală de 12 qubiți este:
Aici, primii patru qubiți reprezintă prima trăsătură, următorii patru qubiți a doua trăsătură și ultimii patru qubiți a treia trăsătură. Codul de mai jos convertește vectorul de date (5,7,0) într-o stare cuantică și este generalizat pentru a face același lucru pentru alte trăsături cu o singură cifră.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit
from qiskit import QuantumCircuit
# Data point to encode
x = 5 # binary: 0101
y = 7 # binary: 0111
z = 0 # binary: 0000
# Convert each to 4-bit binary list
x_bits = [int(b) for b in format(x, "04b")] # [0,1,0,1]
y_bits = [int(b) for b in format(y, "04b")] # [0,1,1,1]
z_bits = [int(b) for b in format(z, "04b")] # [0,0,0,0]
# Combine all bits
all_bits = x_bits + y_bits + z_bits # [0,1,0,1,0,1,1,1,0,0,0,0]
# Initialize a 12-qubit quantum circuit
qc = QuantumCircuit(12)
# Apply x-gates where the bit is 1
for idx, bit in enumerate(all_bits):
if bit == 1:
qc.x(idx)
qc.draw("mpl")

Verifică-ți înțelegerea
Citește întrebarea de mai jos, gândește-te la răspuns, apoi apasă pe triunghi pentru a vedea soluția.
Scrie cod pentru a codifica primul vector din setul nostru de date exemplu :
folosind codificarea pe bază.
Răspuns:
import math
from qiskit import QuantumCircuit
# Data point to encode
x = 4 # binary: 0100
y = 8 # binary: 1000
z = 5 # binary: 0101
# Convert each to 4-bit binary list
x_bits = [int(b) for b in format(x, '04b')] # [0,1,0,0]
y_bits = [int(b) for b in format(y, '04b')] # [1,0,0,0]
z_bits = [int(b) for b in format(z, '04b')] # [0,1,0,1]
# Combine all bits
all_bits = x_bits + y_bits + z_bits # [0,1,0,0,1,0,0,0,0,1,0,1]
# Initialize a 12-qubit quantum circuit
qc = QuantumCircuit(12)
# Apply x-gates where the bit is 1
for idx, bit in enumerate(all_bits):
if bit == 1:
qc.x(idx)
qc.draw('mpl')
Codificarea pe amplitudine
Codificarea pe amplitudine codifică datele în amplitudinile unei stări cuantice. Reprezintă un vector de date clasic normalizat -dimensional, , ca amplitudinile unei stări cuantice de qubiți, :
unde este aceeași dimensiune a vectorilor de date ca înainte, este al -lea element al lui și este a -a stare de bază computațională. Aici, este o constantă de normalizare care urmează să fie determinată din datele ce urmează să fie codificate. Aceasta este condiția de normalizare impusă de mecanica cuantică:
În general, aceasta este o condiție diferită de normalizarea min/max utilizată pentru fiecare trăsătură pe toți vectorii de date. Modul precis în care se navighează această situație va depinde de problema ta. Dar nu există nicio cale de a ocoli condiția de normalizare din mecanica cuantică de mai sus.
În codificarea pe amplitudine, fiecare trăsătură dintr-un vector de date este stocată ca amplitudinea unei stări cuantice diferite. Deoarece un sistem de qubiți oferă amplitudini, codificarea pe amplitudine a trăsături necesită qubiți.
Ca exemplu, să codificăm primul vector din setul de date exemplu , folosind codificarea pe amplitudine. Normalizând vectorul rezultat, obținem:
și starea cuantică rezultată de 2 qubiți ar fi:
În exemplul de mai sus, numărul de trăsături din vector nu este o putere a lui 2. Când nu este o putere a lui 2, pur și simplu alegem o valoare pentru numărul de qubiți astfel încât și completăm vectorul de amplitudini cu constante neinformative (aici, un zero).
La fel ca în codificarea pe bază, odată ce calculăm ce stare va codifica setul nostru de date, în Qiskit putem folosi funcția initialize pentru a o pregăti:
import math
desired_state = [
1 / math.sqrt(105) * 4,
1 / math.sqrt(105) * 8,
1 / math.sqrt(105) * 5,
1 / math.sqrt(105) * 0,
]
qc = QuantumCircuit(2)
qc.initialize(desired_state, [0, 1])
qc.decompose(reps=5).draw(output="mpl")
Un avantaj al codificării pe amplitudine este cerința menționată anterior de doar qubiți pentru codificare. Cu toate acestea, algoritmii următori trebuie să opereze pe amplitudinile unei stări cuantice, iar metodele de pregătire și măsurare a stărilor cuantice tind să nu fie eficiente.
Verifică-ți înțelegerea
Citește întrebările de mai jos, gândește-te la răspunsuri, apoi apasă pe triunghiuri pentru a vedea soluțiile.
Scrie starea normalizată pentru codificarea următorului vector (alcătuit din doi vectori din setul nostru de date exemplu):
folosind codificarea pe amplitudine.
Răspuns:
Pentru a codifica 6 numere, va trebui să avem cel puțin 6 stări disponibile ale căror amplitudini le putem folosi pentru codificare. Aceasta va necesita 3 qubiți. Folosind un factor de normalizare necunoscut , putem scrie aceasta ca:
Rețineți că
Deci, în final,
Pentru același vector de date scrie cod pentru a crea un circuit care încarcă aceste trăsături de date folosind codificarea pe amplitudine.
Răspuns:
desired_state = [
9 / math.sqrt(270),
8 / math.sqrt(270),
6 / math.sqrt(270),
2 / math.sqrt(270),
9 / math.sqrt(270),
2 / math.sqrt(270),
0,
0,
]
print(desired_state)
qc = QuantumCircuit(3)
qc.initialize(desired_state, [0, 1, 2])
qc.decompose(reps=8).draw(output="mpl")
[0.5477225575051662, 0.48686449556014766, 0.36514837167011077, 0.12171612389003691, 0.5477225575051662, 0.12171612389003691, 0, 0]
S-ar putea să fie nevoie să lucrezi cu vectori de date foarte mari. Consideră vectorul
Scrie cod pentru a automatiza normalizarea și generează un circuit cuantic pentru codificarea pe amplitudine.
Răspuns:
Există multe răspunsuri posibile. Iată un cod care afișează câțiva pași intermediari:
import numpy as np
from math import sqrt
init_list = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0, 3, 7, 5]
qubits = round(np.log(len(init_list)) / np.log(2) + 0.4999999999)
need_length = 2**qubits
pad = need_length - len(init_list)
for i in range(0, pad):
init_list.append(0)
init_array = np.array(init_list) # Unnormalized data vector
length = sqrt(
sum(init_array[i] ** 2 for i in range(0, len(init_array)))
) # Vector length
norm_array = init_array / length # Normalized array
print("Normalized array:")
print(norm_array)
print()
qubit_numbers = []
for i in range(0, qubits):
qubit_numbers.append(i)
print(qubit_numbers)
qc = QuantumCircuit(qubits)
qc.initialize(norm_array, qubit_numbers)
qc.decompose(reps=7).draw(output="mpl")
Normalized array: [0.17342199 0.34684399 0.21677749 0.39019949 0.34684399 0.26013299 0.086711 0.39019949 0.086711 0.21677749 0.30348849 0. 0.1300665 0.30348849 0.21677749 0. ]
[0, 1, 2, 3]

Observi avantaje ale codificării pe amplitudine față de codificarea pe bază? Dacă da, explică.
Răspuns:
Pot exista mai multe răspunsuri. Un răspuns este că, dată fiind ordinea fixă a stărilor de bază, această codificare pe amplitudine păstrează ordinea numerelor codificate. Adesea va fi și mai densă.
Un beneficiu al codificării pe amplitudine este că sunt necesari doar qubiți pentru un vector de date -dimensional ( trăsături) . Cu toate acestea, codificarea pe amplitudine este în general o procedură ineficientă care necesită pregătirea arbitrară a stării, care este exponențială în numărul de porți CNOT. Altfel spus, pregătirea stării are o complexitate de timp de execuție polinomială de în numărul de dimensiuni, unde , iar este numărul de qubiți. Codificarea pe amplitudine „oferă o economie exponențială de spațiu cu prețul unei creșteri exponențiale a timpului"[3]; totuși, creșteri ale timpului de execuție la sunt realizabile în anumite cazuri[4]. Pentru o accelerare cuantică end-to-end, trebuie luată în considerare complexitatea timpului de execuție al încărcării datelor.
Codificarea pe unghi
Codificarea pe unghi prezintă interes în multe modele QML care utilizează mapări de caracteristici Pauli, cum ar fi mașinile vectoriale de suport cuantice (QSVM) și circuitele cuantice variaționale (VQC), printre altele. Codificarea pe unghi este strâns legată de codificarea pe fază și codificarea densă pe unghi, care sunt prezentate mai jos. Aici vom folosi „codificarea pe unghi" pentru a face referire la o rotație în , adică o rotație departe de axa realizată, de exemplu, printr-o poartă sau o poartă [1,3]. De fapt, se pot codifica date în orice rotație sau combinație de rotații. Dar este obișnuită în literatură, deci o subliniem aici.
Când este aplicată unui singur qubit, codificarea pe unghi imprimă o rotație pe axa Y proporțională cu valoarea datei. Considerăm codificarea unei singure trăsături (a -a trăsătură) din al -lea vector de date dintr-un set de date, :
Alternativ, codificarea pe unghi poate fi realizată folosind porți , deși starea codificată ar avea o fază relativă complexă față de .
Codificarea pe unghi diferă de cele două metode anterioare discutate în mai multe moduri. În codificarea pe unghi:
- Fiecare valoare a trăsăturii este mapată unui qubit corespunzător, , lăsând qubiții într-o stare produs.
- O singură valoare numerică este codificată la un moment dat, în loc de un set întreg de trăsături dintr-un punct de date.
- Sunt necesari qubiți pentru trăsături de date, unde . Adesea se aplică egalitatea. Vom vedea cum este posibil în secțiunile următoare.
- Circuitul cuantic rezultat are o adâncime constantă (de obicei adâncimea este 1 înainte de transpilare).
Circuitul cuantic cu adâncime constantă îl face deosebit de potrivit pentru hardware-ul cuantic actual. O caracteristică suplimentară a codificării datelor noastre folosind (și, în mod specific, alegerea noastră de a utiliza codificarea pe unghi pe axa Y) este că creează stări cuantice cu valori reale care pot fi utile pentru anumite aplicații. Pentru rotația pe axa Y, datele sunt mapate cu o poartă de rotație pe axa Y printr-un unghi real (Qiskit RYGate). Ca și în cazul codificării pe fază (vezi mai jos), recomandăm rescalarea datelor astfel încât , prevenind pierderea de informații și alte efecte nedorite.
Următorul cod Qiskit rotește un singur qubit dintr-o stare inițială pentru a codifica o valoare de date .
from qiskit.quantum_info import Statevector
from math import pi
qc = QuantumCircuit(1)
state1 = Statevector.from_instruction(qc)
qc.ry(pi / 2, 0) # Phase gate rotates by an angle pi/2
state2 = Statevector.from_instruction(qc)
states = state1, state2
Vom defini o funcție pentru a vizualiza acțiunea asupra vectorului de stare. Detaliile definiției funcției nu sunt importante, dar capacitatea de a vizualiza vectorii de stare și modificările lor este importantă.
import numpy as np
from qiskit.visualization.bloch import Bloch
from qiskit.visualization.state_visualization import _bloch_multivector_data
def plot_Nstates(states, axis, plot_trace_points=True):
"""This function plots N states to 1 Bloch sphere"""
bloch_vecs = [_bloch_multivector_data(s)[0] for s in states]
if axis is None:
bloch_plot = Bloch()
else:
bloch_plot = Bloch(axes=axis)
bloch_plot.add_vectors(bloch_vecs)
if len(states) > 1:
def rgba_map(x, num):
g = (0.95 - 0.05) / (num - 1)
i = 0.95 - g * num
y = g * x + i
return (0.0, y, 0.0, 0.7)
num = len(states)
bloch_plot.vector_color = [rgba_map(x, num) for x in range(1, num + 1)]
bloch_plot.vector_width = 3
bloch_plot.vector_style = "simple"
if plot_trace_points:
def trace_points(bloch_vec1, bloch_vec2):
# bloch_vec = (x,y,z)
n_points = 15
thetas = np.arccos([bloch_vec1[2], bloch_vec2[2]])
phis = np.arctan2(
[bloch_vec1[1], bloch_vec2[1]], [bloch_vec1[0], bloch_vec2[0]]
)
if phis[1] < 0:
phis[1] = phis[1] + 2 * pi
angles0 = np.linspace(phis[0], phis[1], n_points)
angles1 = np.linspace(thetas[0], thetas[1], n_points)
xp = np.cos(angles0) * np.sin(angles1)
yp = np.sin(angles0) * np.sin(angles1)
zp = np.cos(angles1)
pnts = [xp, yp, zp]
bloch_plot.add_points(pnts)
bloch_plot.point_color = "k"
bloch_plot.point_size = [4] * len(bloch_plot.points)
bloch_plot.point_marker = ["o"]
for i in range(len(bloch_vecs) - 1):
trace_points(bloch_vecs[i], bloch_vecs[i + 1])
bloch_plot.sphere_alpha = 0.05
bloch_plot.frame_alpha = 0.15
bloch_plot.figsize = [4, 4]
bloch_plot.render()
plot_Nstates(states, axis=None, plot_trace_points=True)
Aceasta a fost doar o singură trăsătură a unui singur vector de date. Când se codifică trăsături în unghiurile de rotație ale qubiți, să spunem pentru al -lea vector de date starea produs codificată va arăta astfel:
Remarcăm că aceasta este echivalentă cu
Verifică-ți înțelegerea
Citește întrebările de mai jos, gândește-te la răspunsuri, apoi apasă pe triunghiuri pentru a vedea soluțiile.
Codifică vectorul de date folosind codificarea pe unghi, așa cum este descrisă mai sus.
Răspuns:
qc = QuantumCircuit(3)
qc.ry(0, 0)
qc.ry(2 * math.pi / 4, 1)
qc.ry(2 * math.pi / 2, 2)
qc.draw(output="mpl")
Folosind codificarea pe unghi descrisă mai sus, câți qubiți sunt necesari pentru a codifica 5 trăsături?
Răspuns: 5
Codificarea pe fază
Codificarea pe fază este foarte similară cu codificarea pe unghi descrisă mai sus. Unghiul de fază al unui qubit este un unghi real în jurul axei față de axa +. Datele sunt mapate cu o rotație de fază, , unde (vezi Qiskit PhaseGate pentru mai multe informații). Se recomandă rescalarea datelor astfel încât . Aceasta previne pierderea de informații și alte efecte potențial nedorite[1,2].
Un qubit este adesea inițializat în starea , care este o stare proprie a operatorului de rotație de fază, ceea ce înseamnă că starea qubitului trebuie mai întâi rotită pentru ca codificarea pe fază să fie implementată. Prin urmare, are sens să se inițializeze starea cu o poartă Hadamard: . Codificarea pe fază pe un singur qubit înseamnă imprimarea unei faze relative proporționale cu valoarea datei:
Procedura de codificare pe fază mapează fiecare valoare a trăsăturii la faza unui qubit corespunzător, . În total, codificarea pe fază are o adâncime a circuitului de 2, incluzând stratul Hadamard, ceea ce o face o schemă de codificare eficientă. Starea cu mai mulți qubiți codificată pe fază ( qubiți pentru trăsături) este o stare produs:
Următorul cod Qiskit pregătește mai întâi starea inițială a unui singur qubit rotindu-l cu o poartă Hadamard, apoi îl rotește din nou folosind o poartă de fază pentru a codifica o trăsătură de date .
qc = QuantumCircuit(1)
qc.h(0) # Hadamard gate rotates state down to Bloch equator
state1 = Statevector.from_instruction(qc)
qc.p(pi / 2, 0) # Phase gate rotates by an angle pi/2
state2 = Statevector.from_instruction(qc)
states = state1, state2
qc.draw("mpl", scale=1)
Putem vizualiza rotația în folosind funcția plot_Nstates pe care am definit-o.
plot_Nstates(states, axis=None, plot_trace_points=True)
Graficul sferei Bloch arată rotația pe axa Z unde . Săgeata verde deschis arată starea finală.
Codificarea pe fază este folosită în multe mapări de caracteristici cuantice, în special mapările de caracteristici și , și mapările de caracteristici Pauli generale, printre altele.
Verifică-ți înțelegerea
Citește întrebările de mai jos, gândește-te la răspunsuri, apoi apasă pe triunghiuri pentru a vedea soluțiile.
Câți qubiți sunt necesari pentru a folosi codificarea pe fază, așa cum este descrisă mai sus, pentru a stoca 8 trăsături?
Răspuns: 8
Scrie cod pentru a codifica vectorul folosind codificarea pe fază.
Răspuns:
Pot exista mai multe răspunsuri. Iată un exemplu:
phase_data = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0]
qc = QuantumCircuit(len(phase_data))
for i in range(0, len(phase_data)):
qc.h(i)
qc.rz(phase_data[i] * 2 * math.pi / float(max(phase_data)), i)
qc.draw(output="mpl")
Codificarea densă pe unghi
Codificarea densă pe unghi (DAE) este o combinație a codificării pe unghi și a codificării pe fază. DAE permite codificarea a două valori de trăsături într-un singur qubit: una cu un unghi de rotație pe axa Y și cealaltă cu un unghi de rotație pe axa : . Codifică două trăsături astfel:
Codificarea a două trăsături de date pe un qubit duce la o reducere de a numărului de qubiți necesari pentru codificare. Extinzând aceasta la mai multe trăsături, vectorul de date poate fi codificat ca:
DAE poate fi generalizată la funcții arbitrare ale celor două trăsături în locul funcțiilor sinusoidale utilizate aici. Aceasta se numește codificare generală pe qubit[7].
Ca exemplu de DAE, codul de mai jos codifică și vizualizează codificarea trăsăturilor și .
qc = QuantumCircuit(1)
state1 = Statevector.from_instruction(qc)
qc.ry(3 * pi / 8, 0)
state2 = Statevector.from_instruction(qc)
qc.rz(7 * pi / 4, 0)
state3 = Statevector.from_instruction(qc)
states = state1, state2, state3
plot_Nstates(states, axis=None, plot_trace_points=True)
Verifică-ți înțelegerea
Citește întrebările de mai jos, gândește-te la răspunsuri, apoi apasă pe triunghiuri pentru a vedea soluțiile.
Ținând cont de tratamentul de mai sus, câți qubiți sunt necesari pentru a codifica 6 trăsături folosind codificarea densă?
Răspuns: 3
Scrie cod pentru a încărca vectorul folosind codificarea densă pe unghi.
Răspuns:
Rețineți că am completat lista cu un „0" pentru a evita problema existenței unui singur parametru nefolosit în schema noastră de codificare.
dense_data = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0, 3, 7, 5, 0]
qc = QuantumCircuit(int(len(dense_data) / 2))
entry = 0
for i in range(0, int(len(dense_data) / 2)):
qc.ry(dense_data[entry] * 2 * math.pi / float(max(dense_data)), i)
entry = entry + 1
qc.rz(dense_data[entry] * 2 * math.pi / float(max(dense_data)), i)
entry = entry + 1
qc.draw(output="mpl")
Codificare cu hărți de caracteristici încorporate
Codificare în puncte arbitrare
Codificarea unghiulară, codificarea de fază și codificarea densă au pregătit stări produs cu o caracteristică codificată pe fiecare qubit (sau două caracteristici pe qubit). Aceasta diferă de codificarea în bază și codificarea de amplitudine, deoarece acele metode utilizează stări entanglate. Nu există o corespondență 1:1 între caracteristica datelor și qubit. În codificarea de amplitudine, de exemplu, o caracteristică poate fi amplitudinea stării , iar alta poate fi amplitudinea stării . În general, metodele care codifică în stări produs produc circuite mai puțin adânci și pot stoca 1 sau 2 caracteristici pe fiecare qubit. Metodele care folosesc entanglarea și asociază o caracteristică cu o stare, nu cu un qubit, duc la circuite mai adânci și pot stoca în medie mai multe caracteristici pe qubit.
Dar codificarea nu trebuie să fie în întregime în stări produs sau în întregime în stări entanglate, cum ar fi codificarea de amplitudine. Într-adevăr, multe scheme de codificare încorporate în Qiskit permit codificarea atât înainte, cât și după un strat de entangalare, nu doar la început. Aceasta se numește „reîncărcarea datelor" (data reuploading). Pentru lucrări conexe, consultă referințele [5] și [6].
În această secțiune, vom folosi și vizualiza câteva dintre schemele de codificare încorporate. Toate metodele din această secțiune codifică caracteristici ca rotații pe porți parametrizate pe qubiți, unde . Reține că maximizarea încărcării datelor pentru un număr dat de qubiți nu este singurul criteriu. În multe cazuri, adâncimea circuitului poate fi o considerație chiar mai importantă decât numărul de qubiți.
Efficient SU2
Un exemplu comun și util de codificare cu entanglare este circuitul efficient_su2 din Qiskit. Remarcabil, acest circuit poate, de exemplu, codifica 8 caracteristici pe doar 2 qubiți. Să vedem acest lucru și apoi să încercăm să înțelegem cum este posibil.
from qiskit.circuit.library import efficient_su2
circuit = efficient_su2(num_qubits=2, reps=1, insert_barriers=True)
circuit.decompose().draw(output="mpl")
Pe măsură ce scriem starea noastră, vom folosi convenția Qiskit conform căreia qubiții cei mai puțin semnificativi sunt ordonați la dreapta, ca în sau Aceste stări pot deveni foarte complicate foarte repede, iar acest exemplu rar poate ajuta la explicarea motivului pentru care astfel de stări sunt rareori scrise explicit.
Sistemul nostru pornește din starea Până la prima barieră (un punct pe care îl etichetăm ), stările noastre sunt:
Aceasta este doar codificarea densă, pe care am văzut-o înainte. Acum, după poarta CNOT, la a doua barieră (), starea noastră este
Acum aplicăm ultimul set de rotații pe qubit singur și colectăm stările similare pentru a obține:
Aceasta este probabil prea complicată pentru a fi analizată. În schimb, fă un pas înapoi și gândește-te câți parametri am încărcat în stare: opt. Dar avem doar patru stări de bază computaționale. La prima vedere, poate părea că am încărcat mai mulți parametri decât ar fi logic, deoarece starea finală poate fi scrisă ca . Rețineți însă că fiecare factor prefix este complex! Scrisă astfel:
Poți vedea că avem, într-adevăr, opt parametri în stare, pe care să codificăm cele opt caracteristici ale noastre.
Prin creșterea numărului de qubiți și a numărului de repetări ale straturilor de entanglare și rotație, se pot codifica mult mai multe date. Scrierea funcțiilor de undă devine rapid intractabilă. Dar putem vedea în continuare codificarea în acțiune.
Aici codificăm vectorul de date cu 12 caracteristici, pe un circuit efficient_su2 de 3 qubiți, folosind fiecare dintre porțile parametrizate pentru a codifica o caracteristică diferită.
În acest vector de date, caracteristicile sunt prezentate într-o anumită ordine. Izolat, nu contează dacă sunt codificate în această ordine sau în ordine inversă. Ce este important este să ții evidența și să fii consistent. Observă în diagrama circuitului că efficient_su2 presupune o anumită ordine de codificare, umplând în mod specific primul strat de porți parametrizate de la qubit 0 la qubit 2, și apoi trecând la stratul următor. Aceasta nu este nici consistent, nici inconsistent cu notația little-endian, deoarece caracteristicile de date nu pot fi ordonate după qubit a priori, înainte ca un circuit de codificare să fi fost specificat.
x = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2]
circuit = efficient_su2(num_qubits=3, reps=1, insert_barriers=True)
encode = circuit.assign_parameters(x)
encode.decompose().draw(output="mpl")
În loc să crești numărul de qubiți, ai putea alege să mărești numărul de repetări ale straturilor de entanglare și rotație. Dar există limite ale numărului de repetări utile. Cum s-a menționat anterior, există un compromis: circuitele cu mai mulți qubiți sau mai multe repetări ale straturilor de entanglare și rotație pot stoca mai mulți parametri, dar o fac cu o adâncime mai mare a circuitului. Ne vom întoarce la adâncimile unor hărți de caracteristici încorporate mai jos. Câteva dintre metodele de codificare următoare care sunt încorporate în Qiskit au „hartă de caracteristici" (feature map) ca parte a numelor lor. Să subliniem că codificarea datelor într-un circuit cuantic este o mapare de caracteristici, în sensul că duce datele într-un nou spațiu: spațiul Hilbert al qubiților implicați. Relația dintre dimensionalitatea spațiului original de caracteristici și cea a spațiului Hilbert va depinde de circuitul pe care îl folosești pentru codificare.
Harta de caracteristici
Harta de caracteristici (ZFM) poate fi interpretată ca o extensie naturală a codificării de fază. ZFM constă din straturi alternante de porți cu un singur qubit: straturi de porți Hadamard și straturi de porți de fază. Fie vectorul de date cu caracteristici. Circuitul cuantic care realizează maparea de caracteristici este reprezentat ca un operator unitar care acționează asupra stării inițiale:
unde este starea fundamentală de qubiți. Această notație este folosită pentru consistență cu referința [4] Havlicek et al. Caracteristicile de date sunt mapate unu-la-unu cu qubiții corespunzători. De exemplu, dacă ai 8 caracteristici într-un vector de date, atunci ai folosi 8 qubiți. Circuitul ZFM este compus din repetări ale unui subcircuit format din straturi de porți Hadamard și straturi de porți de fază. Un strat Hadamard este alcătuit dintr-o poartă Hadamard care acționează asupra fiecărui qubit dintr-un registru de qubiți, , în aceeași etapă a algoritmului. Această descriere se aplică și unui strat de porți de fază în care qubit-ul este acționat de . Fiecare poartă are o caracteristică ca argument, dar stratul de porți de fază () este o funcție a vectorului de date. Unitarul complet al circuitului ZFM cu o singură repetare este:
Atunci repetări ale acestui unitar ar fi
Caracteristicile de date, , sunt mapate la porțile de fază în același mod în toate cele repetări. Starea hărții de caracteristici ZFM este o stare produs și este eficientă pentru simularea clasică[4].
Pentru a începe cu un exemplu mic, un circuit ZFM de doi qubiți este codat folosind Qiskit și desenat pentru a afișa structura simplă a circuitului. În exemplu, o singură repetare, , este implementată cu vectorul de date . Rețineți că aceasta este scrisă în ordinea standard a unui vector în Python, adică elementul este Suntem liberi să codificăm această caracteristică pe qubit-ul nostru , sau pe al -lea. Din nou, nu poate exista întotdeauna o singură mapare 1:1 de la ordinea caracteristicilor la ordinea qubiților, deoarece diferite hărți de caracteristici codifică numere diferite de caracteristici pe fiecare qubit. Din nou, ceea ce este important este să fim conștienți de locul unde este codificată fiecare caracteristică. Când furnizezi o listă de parametri hărții de caracteristici , aceasta va codifica caracteristica 0 din listă pe qubit-ul cel mai puțin semnificativ cu o poartă parametrizată, adică qubit 0. Deci vom urma această convenție când facem aceasta manual. Vom codifica pe qubit-ul și pe qubit-ul .
Operatorul unitar al circuitului ZFM acționează asupra stării inițiale în felul următor:
Formula a fost rearanjată în jurul produsului tensorial pentru a evidenția operațiile pe fiecare qubit. Următorul cod Qiskit folosește porțile Hadamard și de fază în mod explicit pentru a arăta structura ZFM:
qc0 = QuantumCircuit(1)
qc1 = QuantumCircuit(1)
qc0.h(0)
qc0.p(pi / 2, 0)
qc1.h(0)
qc1.p(pi / 3, 0)
# Combine circuits qc0 and qc1 into 1 circuit
qc = QuantumCircuit(2)
qc.compose(qc0, [0], inplace=True)
qc.compose(qc1, [1], inplace=True)
qc.draw("mpl", scale=1)
Acum codificăm același vector de date pe un circuit ZFM cu trei repetări, , folosind clasa Qiskit z_feature_map, care împreună ne dă harta de caracteristici cuantice . În mod implicit în clasa z_feature_map, parametrii sunt înmulțiți cu 2 înainte de a fi mapați la poarta de fază . Pentru a reproduce aceleași codificări ca mai sus, împărțim la 2.
from qiskit.circuit.library import z_feature_map
zfeature_map = z_feature_map(feature_dimension=2, reps=3)
zfeature_map = zfeature_map.assign_parameters([(1 / 2) * pi / 2, (1 / 2) * pi / 3])
zfeature_map.decompose().draw("mpl")
Evident, aceasta este o mapare diferită față de cea realizată manual mai sus, dar observați consistența în ordinea parametrilor: a fost din nou codificat pe qubit-ul .
Poți folosi ZFM prin clasa ZFM a Qiskit; poți folosi, de asemenea, această structură ca sursă de inspirație pentru a-ți construi propria mapare de caracteristici.
Harta de caracteristici
Harta de caracteristici (ZZFM) extinde ZFM cu includerea porților de entanglare cu doi qubiți, în special poarta de rotație , . Se presupune că ZZFM este în general costisitoare de calculat pe un calculator clasic, spre deosebire de ZFM.
implementează o interacțiune și este maximal entanglatoare pentru . poate fi descompusă într-o serie de porți pe doi qubiți, după cum se arată în următorul cod Qiskit folosind poarta RZZ și metoda clasei QuantumCircuit decompose. Codificăm o singură caracteristică a vectorului de date :
qc = QuantumCircuit(2)
qc.rzz(pi, 0, 1)
qc.draw("mpl", scale=1)
Cum se întâmplă adesea, o vedem reprezentată ca o unitate asemănătoare unei porți, până când folosim .decompose() pentru a vedea toate porțile componente.
qc.decompose().draw("mpl", scale=1)
Datele sunt mapate cu o rotație de fază pe al doilea qubit. Poarta entanglează cei doi qubiți pe care operează, cu un grad de entanglare determinat de valoarea caracteristicii codificate.
Circuitul complet ZZFM constă dintr-o poartă Hadamard și o poartă de fază, ca în ZFM, urmată de entanglarea descrisă mai sus. O singură repetare a circuitului ZZFM este:
unde conține un strat de porți ZZ structurat printr-o schemă de entanglare. Mai jos sunt prezentate mai multe scheme de entanglare în blocuri de cod. Structura lui include, de asemenea, o funcție care combină caracteristicile de date din qubiții entanglați în felul următor. Să spunem că poarta urmează să fie aplicată qubiților și . În stratul de fază, acești qubiți au porți de fază care codifică și pe ei, respectiv. Argumentul al lui nu va fi pur și simplu una dintre aceste caracteristici sau cealaltă, ci o funcție deseori notată prin (a nu se confunda cu unghiul azimutal):
Vom vedea aceasta în mai multe exemple de mai jos. Extensia la repetări multiple este aceeași ca în cazul z_feature_map:
Pe măsură ce operatorii au crescut în complexitate, să codificăm mai întâi un vector de date cu un ZZFM de doi qubiți și o repetare folosind următorul cod:
from qiskit.circuit.library import zz_feature_map
feature_dim = 2
zzfeature_map = zz_feature_map(
feature_dimension=feature_dim, entanglement="linear", reps=1
)
zzfeature_map.decompose(reps=1).draw("mpl", scale=1)
În mod implicit în Qiskit, caracteristicile sunt mapate împreună la prin această funcție de mapare . Qiskit permite utilizatorului să personalizeze funcția (sau unde este mulțimea perechilor de qubiți cuplaţi prin porți ) ca pas de preprocesare.
Trecând la un vector de date cu patru dimensiuni și mapând la un ZZFM cu patru qubiți și o repetare, putem începe să vedem maparea pentru diverse perechi de qubiți. Putem vedea, de asemenea, semnificația entanglării „liniare":
feature_dim = 4
zzfeature_map = zz_feature_map(
feature_dimension=feature_dim, entanglement="linear", reps=1
)
zzfeature_map.decompose().draw("mpl", scale=1)
În schema de entanglare liniară, perechile de qubiți vecini (numerotați) din acest circuit sunt entanglați. Există și alte scheme de entanglare încorporate în Qiskit, inclusiv circular și full.
Harta de caracteristici Pauli
Harta de caracteristici Pauli (PFM) este generalizarea ZFM și ZZFM pentru a folosi porți Pauli arbitrare. Harta de caracteristici Pauli are o formă foarte similară cu cele două hărți de caracteristici anterioare. Pentru repetări ale codificării celor caracteristici ale vectorului
Pentru PFM, este generalizat la un operator unitar de expansiune Pauli. Iată o formă mai generalizată a hărților de caracteristici considerate până acum:
unde este un operator Pauli, . Aici este mulțimea tuturor conectivităților de qubiți, determinată de harta de caracteristici, inclusiv mulțimea de qubiți acționați de porți cu un singur qubit. Adică, pentru o hartă de caracteristici în care qubit-ul 0 a fost acționat de o poartă de fază, iar qubiții 2 și 3 au fost acționați de o poartă , mulțimea ar include . parcurge toate elementele acelei mulțimi. În hărțile de caracteristici anterioare, funcția era implicată fie exclusiv cu porți cu un singur qubit, fie exclusiv cu porți cu doi qubiți. Iată cum o definim în general:
Pentru documentație, consultă documentația clasei Qiskit Pauli feature map). În ZZFM, operatorul este restricționat la .
O modalitate de a înțelege unitarul de mai sus este prin analogie cu propagatorul dintr-un sistem fizic. Unitarul de mai sus este un operator de evoluție unitară, , pentru un Hamiltonian, , similar cu modelul Ising, unde parametrul de timp, , este înlocuit cu valorile datelor pentru a conduce evoluția. Expansiunea acestui operator unitar dă circuitul PFM. Conectivitățile de entanglare din pot fi interpretate ca cuplaje Ising într-o rețea de spini.
Să considerăm un exemplu de operatori Pauli și reprezentând acele interacțiuni de tip Ising. Qiskit oferă o clasă pauli_feature_map pentru instanțierea unui PFM cu o alegere de porți cu un singur qubit și qubiți, care în acest exemplu vor fi transmise ca șiruri Pauli 'Y' și 'XX'. De obicei, este 1 sau 2 pentru interacțiuni cu un singur qubit și, respectiv, doi qubiți. Schema de entanglare este „liniară", adică doar qubiții vecini din circuitul cuantic sunt cuplați. Rețineți că aceasta nu corespunde qubiților vecini pe calculatorul cuantic însuși, deoarece acest circuit cuantic este un nivel de abstractizare.
from qiskit.circuit.library import pauli_feature_map
feature_dim = 3
pfmap = pauli_feature_map(
feature_dimension=feature_dim, entanglement="linear", reps=1, paulis=["Y", "XX"]
)
pfmap.decompose().draw("mpl", scale=1.5)
Qiskit oferă un parametru, , în hărțile de caracteristici Pauli pentru a controla scalarea rotațiilor Pauli.
Valoarea implicită a lui este . Optimizând valoarea sa în intervalul, de exemplu, se poate alinia mai bine un nucleu cuantic la date.
Galerie de hărți de caracteristici Pauli
Iată că vizualizăm diverse hărți de caracteristici Pauli pentru circuite de doi qubiți, pentru a obține o imagine mai bună a gamei de posibilități.
from qiskit.visualization import circuit_drawer
import matplotlib.pyplot as plt
feature_dim = 2
fig, axs = plt.subplots(9, 2)
i_plot = 0
for paulis in [
["I"],
["X"],
["Y"],
["Z"],
["XX"],
["XY"],
["XZ"],
["YY"],
["YZ"],
["ZZ"],
["X", "ZZ"],
["Y", "ZZ"],
["Z", "ZZ"],
["X", "YZ"],
["Y", "YZ"],
["Z", "YZ"],
["YY", "ZZ"],
["XY", "ZZ"],
]:
pfmap = pauli_feature_map(feature_dimension=feature_dim, paulis=paulis, reps=1)
circuit_drawer(
pfmap.decompose(),
output="mpl",
style={"backgroundcolor": "#EEEEEE"},
ax=axs[int((i_plot - i_plot % 2) / 2), i_plot % 2],
)
axs[int((i_plot - i_plot % 2) / 2), i_plot % 2].title.set_text(paulis)
i_plot += 1
fig.set_figheight(16)
fig.set_figwidth(16)

Cele de mai sus pot, desigur, fi extinse pentru a include alte permutări și repetări ale matricelor Pauli. Cursanții sunt încurajați să experimenteze cu acele opțiuni.
Recapitularea hărților de caracteristici încorporate
Ai văzut mai multe scheme de codificare a datelor într-un circuit cuantic:
- Codificare în bază
- Codificare de amplitudine
- Codificare unghiulară
- Codificare de fază
- Codificare densă
Ai văzut cum să îți construiești propriile hărți de caracteristici folosind aceste scheme de codificare și ai văzut patru hărți de caracteristici încorporate care profită de codificarea unghiulară și de fază:
- Efficient SU2
- Harta de caracteristici Z
- Harta de caracteristici ZZ
- Harta de caracteristici Pauli
Aceste hărți de caracteristici încorporate s-au deosebit una de alta în mai multe moduri:
- Adâncimea pentru un număr dat de caracteristici codificate
- Numărul de qubiți necesar pentru un număr dat de caracteristici
- Gradul de entanglare (evident legat de celelalte diferențe)
Codul de mai jos aplică aceste patru hărți de caracteristici încorporate la codificarea unui set de caracteristici și trasează adâncimea cu doi qubiți a circuitului rezultat. Deoarece ratele de eroare cu doi qubiți sunt mult mai mari decât ratele de eroare ale porților cu un singur qubit, cineva ar putea fi cel mai interesat în mod rezonabil de adâncimea porților cu doi qubiți. În codul de mai jos, obținem numărătoarea tuturor porților dintr-un circuit prin descompunerea mai întâi a circuitului și apoi folosind count_ops(), după cum se arată mai jos. Iată că porțile cu doi qubiți care ne interesează sunt porțile 'cx':
# Initializing parameters and empty lists for depths
x = [0.1, 0.2]
n_data = []
zz2gates = []
su22gates = []
z2gates = []
p2gates = []
# Generating feature maps
for n in range(3, 10):
x.append(n / 10)
zzcircuit = zz_feature_map(n, reps=1, insert_barriers=True)
zcircuit = z_feature_map(n, reps=1, insert_barriers=True)
su2circuit = efficient_su2(n, reps=1, insert_barriers=True)
pcircuit = pauli_feature_map(n, reps=1, paulis=["XX"], insert_barriers=True)
# Getting the cx depths
zzcx = zzcircuit.decompose().count_ops().get("cx")
zcx = zcircuit.decompose().count_ops().get("cx")
su2cx = su2circuit.decompose().count_ops().get("cx")
pcx = pcircuit.decompose().count_ops().get("cx")
# Appending the cx gate counts to the lists. We shift the zz and Pauli data points,
# because they overlap.
n_data.append(n)
zz2gates.append(zzcx - 0.5)
z2gates.append(0)
su22gates.append(su2cx)
p2gates.append(pcx + 0.5)
# Plot the output
plt.plot(n_data, p2gates, "bo")
plt.plot(n_data, zz2gates, "ro")
plt.plot(n_data, su22gates, "yo")
plt.plot(n_data, z2gates, "go")
plt.ylabel("CX Gates")
plt.xlabel("Data elements")
plt.legend(["Pauli", "ZZ", "SU2", "Z"])
# plt.suptitle('zz_feature_map(n)')
plt.show()
În general, hărțile de caracteristici Pauli și ZZ vor rezulta în adâncimi mai mari ale circuitului și un număr mai mare de porți cu 2 qubiți față de efficient_su2 și hărțile de caracteristici Z.
Deoarece hărțile de caracteristici încorporate în Qiskit sunt aplicabile pe scară largă, de multe ori nu va trebui să ne concepem propriile, mai ales în faza de învățare. Cu toate acestea, experții în învățarea automată cuantică se vor întoarce probabil la subiectul proiectării propriilor mapări de caracteristici, pe măsură ce abordează două provocări complicate:
-
Hardware modern: prezența zgomotului și suprasarcina mare a codului de corectare a erorilor înseamnă că aplicațiile actuale vor trebui să ia în considerare lucruri precum eficiența hardware și minimizarea adâncimii porților cu doi qubiți.
-
Mapări care se potrivesc problemei la îndemână: este un lucru să spui că
zz_feature_map, de exemplu, este dificil de simulat clasic și, prin urmare, interesant. Este cu totul altceva cazz_feature_mapsă fie ideal potrivit sarcinii tale de învățare automată sau setului de date. Performanța diferitelor circuite cuantice parametrizate pe diferite tipuri de date este un domeniu activ de investigare.
Încheiem cu o notă privind eficiența hardware.
Maparea caracteristicilor eficientă hardware
O mapare a caracteristicilor eficientă hardware este una care ține cont de constrângerile calculatoarelor cuantice reale, cu scopul de a reduce zgomotul și erorile din calcul. Atunci când rulezi circuite cuantice pe calculatoare cuantice de generație apropiată, există multe strategii pentru a reduce zgomotul inerent hardware-ului. O strategie principală pentru eficiența hardware este minimizarea adâncimii circuitului cuantic, astfel încât zgomotul și decoerența să aibă mai puțin timp să corupă calculul. Adâncimea unui circuit cuantic reprezintă numărul de pași de porți aliniați temporal necesari pentru a finaliza întregul calcul (după optimizarea circuitului)[5]. Reamintește-ți că adâncimea circuitului abstract, logic poate fi mult mai mică decât adâncimea după ce circuitul este transpilat pentru un calculator cuantic real.
Transpilarea este procesul de conversie a circuitului cuantic dintr-o abstractizare de nivel înalt într-unul pregătit să ruleze pe un calculator cuantic real, ținând cont de constrângerile hardware-ului. Un calculator cuantic are un set nativ de porți cu un qubit și cu doi qubiți. Asta înseamnă că toate porțile din codul Qiskit trebuie transpilate în setul de porți hardware native. De exemplu, în ibm_torino, un QPU dotat cu un procesor Heron r1, finalizat în 2023, porțile native sau de bază sunt {CZ, ID, RZ, SX, X}. Acestea sunt poarta cu doi qubiți controlled-Z și porțile cu un qubit numite identitate, rotație-, rădăcina pătrată a lui NOT și NOT, respectiv, oferind un set universal. Când implementezi porți cu mai mulți qubiți ca un subcircuit echivalent, sunt necesare porți fizice cu doi qubiți, împreună cu alte porți cu un qubit disponibile în hardware. În plus, pentru a efectua o poartă cu doi qubiți pe o pereche de qubiți care nu sunt cuplați fizic, se adaugă porți SWAP pentru a muta stările qubiților între qubiți pentru a permite cuplarea, ceea ce duce la o extensie inevitabilă a circuitului. Folosind argumentul optimization care poate fi setat de la 0 până la un nivel maxim de 3. Pentru un control și o personalizare mai mari, pipeline-ul de transpilare poate fi gestionat cu Qiskit Pass Manager. Consultă documentația Qiskit Transpiler pentru mai multe informații despre transpilare.
În Havlicek et al. 2019 [2], unul dintre modurile în care autorii obțin eficiența hardware este prin utilizarea mapei de caracteristici , deoarece aceasta este o expansiune de ordinul doi (vezi secțiunea „Mapa de caracteristici " de mai sus). O expansiune de ordinul are porți cu qubiți. Calculatoarele cuantice IBM® nu au porți native cu qubiți, unde , deci pentru a le implementa ar fi necesară descompunerea în porți CNOT cu doi qubiți disponibile în hardware. O a doua modalitate prin care autorii minimizează adâncimea este alegerea unei topologii de cuplare care se mapează direct la cuplările arhitecturii. O optimizare suplimentară pe care o realizează este țintirea unui subcircuit hardware de înaltă performanță, adecvat conectat. Alte aspecte de luat în considerare sunt minimizarea numărului de repetiții ale mapei de caracteristici și alegerea unei scheme de întrețesere personalizate de adâncime redusă sau „liniare" în locul schemei „complete" care întrețese toți qubiții.

Graficul de mai sus arată o rețea de noduri și muchii care reprezintă qubiți fizici, respectiv cuplări hardware. Harta de cuplare și performanța ibm_torino sunt prezentate cu toate posibilele porți de cuplare CZ cu doi qubiți. Qubiții sunt codificați cromatic pe o scală bazată pe timpul de relaxare T1 în microsecunde (μs), unde timpii T1 mai lungi sunt mai buni și sunt în nuanțe mai deschise. Muchiile de cuplare sunt codificate cromatic în funcție de eroarea CZ, unde nuanțele mai închise sunt mai bune. Informațiile despre specificațiile hardware pot fi accesate în schema de configurare a backend-ului hardware IBMQBackend.configuration().
Referințe
- Maria Schuld and Francesco Petruccione, Supervised Learning with Quantum Computers, Springer 2018, doi:10.1007/978-3-319-96424-9.
- Vojtech Havlicek et al., "Supervised Learning with Quantum Enhanced Feature Spaces." Nature, vol. 567 (2019): 209–212. https://arxiv.org/abs/1804.11326.
- Ryan LaRose and Brian Coyle, "Robust data encodings for quantum classifiers", Physical Review A 102, 032420 (2020), doi:10.1103/PhysRevA.102.032420, arXiv:2003.01695.
- Lou Grover and Terry Rudolph. "Creating Superpositions That Correspond to Efficiently Integrable Probability Distributions." arXiv:quant-ph/0208112, August 15, 2002, https://arxiv.org/abs/quant-ph/0208112.
- Adrián Pérez-Salinas, Alba Cervera-Lierta, Elies Gil-Fuster, José I. Latorre, "Data re-uploading for a universal quantum classifier", Quantum 4, 226 (2020), ArXiv.org/abs/1907.02085.
- Maria Schuld, Ryan Sweke, Johannes Jakob Meyer, "The effect of data encoding on the expressive power of variational quantum machine learning models", Phys. Rev. A 103, 032430 (2021), arxiv.org/abs/2008.08605
import qiskit
qiskit.version.get_version_info()