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