Algoritmul lui Shor
Pentru acest modul Qiskit în Sală de Clasă, studenții trebuie să aibă un mediu Python funcțional cu următoarele pachete instalate:
qiskitv2.1.0 sau mai nouqiskit-ibm-runtimev0.40.1 sau mai nouqiskit-aerv0.17.0 sau mai nouqiskit.visualizationnumpypylatexenc
Pentru a configura și instala pachetele de mai sus, consultă ghidul Instalează Qiskit. Pentru a rula joburi pe calculatoare cuantice reale, studenții vor trebui să își creeze un cont IBM Quantum® urmând pașii din ghidul Configurează-ți contul IBM Cloud.
Acest modul a fost testat și a folosit trei secunde de timp QPU. Aceasta este doar o estimare. Utilizarea ta reală poate varia.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'
Introducere
La începutul anilor 1990, entuziasmul față de potențialul calculatoarelor cuantice de a rezolva probleme dificile pentru calculatoarele clasice era în creștere. Câțiva informaticieni talentați concepuseră algoritmi care demonstrau puterea calculului cuantic pentru unele probleme de nișă și artificiale, dar nimeni nu găsise o singură „aplicație ucigașă" a calculului cuantic care să fie sigur că va revoluționa domeniul. Asta până în 1994, când Peter Shor a elaborat ceea ce este acum cunoscut ca algoritmul lui Shor pentru factorizarea numerelor mari.
Era bine știut la acea vreme că găsirea factorilor primi ai unui număr mare era extrem de dificilă pentru un calculator clasic. De fapt, protocoalele de securitate pe internet se bazau pe această dificultate. Shor a găsit o modalitate de a descoperi acești factori exponențial mai eficient, delegând unii dintre pașii mai dificili unui calculator cuantic teoretic, din viitor.
În acest modul, vom explora algoritmul lui Shor. Mai întâi, vom oferi puțin mai mult context algoritmului, formalizând problema pe care o rezolvă și explicând relevanța pentru securitatea cibernetică. Apoi, vom face o introducere în matematica modulară și cum să o aplicăm problemei de factorizare, arătând cum factorizarea se reduce la o altă problemă numită „găsirea ordinului". Vom arăta cum intervin Transformata Fourier Cuantică și Estimarea Fazei Cuantice, pe care le-am studiat într-un modul anterior, și cum să le folosim pentru a rezolva problema găsirii ordinului.
În final, vom rula algoritmul lui Shor pe un calculator cuantic real! Ține minte, totuși, că acest algoritm va fi cu adevărat util abia când vom avea un calculator cuantic mare, tolerant la defecte, lucru care mai este încă la câțiva ani distanță. Prin urmare, vom factoriza doar un număr mic pentru a demonstra cum funcționează algoritmul.
Problema factorizării
Scopul problemei de factorizare este de a găsi factorii primi ai unui număr . Pentru unele numere , acest lucru este destul de simplu. De exemplu, dacă este par, unul dintre factorii săi primi va fi 2. Dacă este o putere a unui număr prim, adică pentru un număr prim , este, de asemenea, destul de ușor de găsit : aproximăm pur și simplu rădăcina a lui și căutăm numere prime apropiate care ar putea fi .
Unde calculatoarele clasice întâmpină dificultăți este atunci când este impar și nu este o putere a unui număr prim. Acesta este cazul cu care se ocupă algoritmul lui Shor. Algoritmul găsește doi factori și astfel încât . El poate fi aplicat recursiv până când toți factorii sunt primi. În secțiunile următoare vom vedea cum este abordată această problemă.
Relevanța pentru securitatea cibernetică
Multe scheme criptografice au fost construite pe baza faptului că factorizarea numerelor mari este dificilă, inclusiv una utilizată frecvent astăzi, numită RSA. În RSA, o cheie publică este creată prin înmulțirea a două numere prime mari pentru a obține . Apoi, oricine poate folosi această cheie publică pentru a cripta date. Dar numai cineva care deține cheia privată, și , poate decripta acele date.
Dacă ar fi ușor de factorizat, atunci oricine ar putea determina valorile lui și și ar sparge criptarea. Dar nu este. Aceasta este o problemă de notorietate pentru dificultatea sa. De fapt, factorii primi ai unui număr numit RSA1024, care are 1024 de cifre binare și 309 de cifre zecimale, nu au fost găsiți până în prezent, în ciuda unui premiu de $100.000 oferit pentru factorizarea sa încă din 1991.
Soluția lui Shor
În 1994, Peter Shor și-a dat seama că un calculator cuantic poate factoriza un număr mare exponențial mai eficient decât un calculator clasic. Intuiția sa s-a bazat pe relația dintre această problemă de factorizare și aritmetica modulară. Vom trece printr-o scurtă introducere în aritmetica modulară, apoi vom vedea cum putem folosi acest lucru pentru a factoriza .
Aritmetica modulară
Aritmetica modulară este un sistem de numărare ciclic, adică, deși numărătoarea începe în mod obișnuit, cu numerele întregi 0, 1, 2 etc., la un moment dat, după o perioadă , numărătoarea reîncepe de la capăt. Să vedem cum funcționează cu un exemplu. Să spunem că perioada noastră este 5. Atunci, pe măsură ce numărăm, acolo unde în mod normal am ajunge la 5, reîncepem de la 0:
Aceasta se datorează faptului că în lumea „modulo-5", 5 este echivalent cu 0. Spunem că . De fapt, toate multiplele lui 5 vor fi echivalente cu .
Verifică-ți înțelegerea
Citește întrebarea (întrebările) de mai jos, gândește-te la răspuns, apoi dă clic pe triunghi pentru a dezvălui soluția.
Folosește aritmetica modulară pentru a rezolva următoarea problemă:
Pleci într-o călătorie lungă cu trenul transcontinental la ora 8 dimineața. Călătoria cu trenul durează 60 de ore. La ce oră ajungi?
Răspuns:
Perioada este 24, deoarece într-o zi sunt 24 de ore. Astfel, această problemă poate fi scrisă în aritmetică modulară ca:
Deci, ai ajunge la destinație la ora 20:00, adică 8 seara.
și
Este adesea util să introducem două mulțimi, și . este pur și simplu mulțimea numerelor care există într-o lume „modulo-". De exemplu, când număram modulo-5, mulțimea ar fi . Un alt exemplu: . Putem efectua adunări și înmulțiri (modulo ) pe elementele din , iar rezultatul fiecăreia dintre aceste operații este, de asemenea, un element din , ceea ce face din un obiect matematic numit inel.
Există un subset special al lui care prezintă un interes deosebit pentru noi în cazul algoritmului lui Shor. Acesta este subsetul numerelor din astfel încât cel mai mare divizor comun dintre fiecare element și este 1, deci fiecare element este „coprim" cu . Dacă luăm mulțimea acestor numere împreună cu operația de înmulțire modulară, aceasta formează un alt obiect matematic, numit grup. Numim acest grup . Se dovedește că în cazul (și al grupurilor finite în general), dacă alegem orice element și îl înmulțim repetat cu el însuși, vom obține întotdeauna în cele din urmă numărul . Numărul minim de ori de câte ori trebuie să înmulțești cu el însuși pentru a obține se numește ordinul lui . Acest fapt va fi foarte important în discuția noastră despre cum să factorizăm numerele de mai jos.
Verifică-ți înțelegerea
Citește întrebarea (întrebările) de mai jos, gândește-te la răspuns, apoi dă clic pe triunghi pentru a dezvălui soluția.
Care este ?
Răspuns:
Am exclus următoarele numere:
Care este ordinul fiecăruia dintre elementele din ?
Răspuns:
Ordinul este cel mai mic număr astfel încât pentru fiecare element .
Reține că, deși am reușit să găsim ordinul numerelor din , aceasta NU este o sarcină ușoară în general, pentru mai mare. Acesta este miezul problemei de factorizare și motivul pentru care avem nevoie de un calculator cuantic. Vom vedea de ce pe măsură ce parcurgem restul notebook-ului.
Aplică aritmetica modulară problemei de factorizare
Cheia pentru găsirea factorilor și astfel încât constă în găsirea unui alt număr întreg astfel încât
și
Cum ne ajută găsirea lui să găsim factorii și ? Să parcurgem argumentul acum. Deoarece , înseamnă că . Cu alte cuvinte, este un multiplu al lui . Deci, pentru un număr întreg ,
Putem factoriza pentru a obține:
Din ipotezele noastre inițiale știm că , deci nu se împarte exact în nici , nici . Astfel, cei doi factori ai lui , și , trebuie să se împartă fiecare în și . Fie este un factor al lui și este un factor al lui , fie invers. Prin urmare, dacă calculăm cel mai mare divizor comun (CMMDC) dintre și atât , cât și , vom obține factorii și . Calcularea CMMDC dintre două numere este o sarcină clasic ușoară, care poate fi realizată, de exemplu, folosind algoritmul lui Euclid.
Verifică-ți înțelegerea
Citește întrebarea (întrebările) de mai jos, gândește-te la răspuns, apoi dă clic pe triunghi pentru a dezvălui soluția.
Poate fi dificil să înțelegi fiecare pas din logica de mai sus, deci încearcă să parcurgi un exemplu. Folosește și . Mai întâi, verifică că și . Apoi continuă să verifici fiecare pas. În final, calculează și verifică că aceștia sunt factorii lui .
Răspuns:
, care este , deci .
, care nu este echivalent cu .
, care nu este echivalent cu .
Acum, știm că pentru un număr întreg . Aceasta se verifică când introducem și : când .
Acum, trebuie să calculăm și .
Astfel, am găsit factorii lui !
Algoritmul
Acum că am văzut cum găsirea unui întreg astfel încât ne ajută să factorizăm , putem parcurge algoritmul lui Shor. Practic, totul se reduce la găsirea lui :
- Alege un întreg aleatoriu Alege un întreg aleatoriu astfel încât .
- Calculează clasic.
- Dacă , ai găsit deja un factor. Oprește-te.
- Altfel, continuă.
-
Găsește ordinul al lui modulo Găsește cel mai mic întreg pozitiv care satisface .
-
Verifică dacă ordinul este par
- Dacă este impar, întoarce-te la pasul 1 și alege un nou .
- Dacă este par, continuă la pasul 4.
- Calculează
- Verifică că și .
- Dacă , întoarce-te la pasul 1 și alege un nou .
- Altfel, calculează cel mai mare divizor comun pentru a extrage factorii:
Aceștia vor fi factori netriviali ai lui .
- Factorizează recursiv dacă este necesar
- Dacă și/sau nu sunt primi, aplică algoritmul recursiv pentru a-i factoriza complet.
- Odată ce toți factorii sunt primi, factorizarea este completă.
Pe baza acestei proceduri, s-ar putea să nu fie evident de ce este nevoie de un calculator cuantic pentru a finaliza această sarcină. Este necesar deoarece pasul 2, găsirea ordinului lui modulo , este clasic o problemă foarte dificilă. Complexitatea scalează exponențial în funcție de . Dar cu un calculator cuantic, trebuie doar să folosim Estimarea de Fază Cuantică pentru a o rezolva. Pasul 4, găsirea celui mai mare divizor comun a două numere întregi, este de fapt un lucru destul de ușor de făcut clasic. Astfel, singurul pas care necesită cu adevărat puterea unui calculator cuantic este pasul de găsire a ordinului. Spunem că problema factorizării „se reduce" la problema găsirii ordinului.
Partea dificilă: găsirea ordinului
Acum vom parcurge modul în care putem folosi un calculator cuantic în găsirea ordinului. Mai întâi, să clarificăm ce înțelegem prin „ordin." Bineînțeles, ți-am spus deja ce înseamnă ordinul matematic: este primul întreg non-zero astfel încât Dar haideți să vedem dacă putem câștiga puțin mai multă intuiție pentru acest concept.
Pentru suficient de mic, putem determina ordinul pur și simplu calculând fiecare putere a lui , luând modulul al acelui număr, apoi oprindu-ne când găsim puterea care satisface . Asta am făcut cu exemplul nostru, , mai sus. Să aruncăm o privire la câteva grafice ale acestor puteri modulare pentru câteva valori de exemplu ale lui și :
Observi ceva? Acestea sunt funcții periodice! Și ordinul este același cu perioada! Deci, găsirea ordinului este echivalentă cu găsirea perioadei.
Calculatoarele cuantice sunt foarte bine adaptate pentru găsirea perioadei funcțiilor. Pentru aceasta, putem folosi o subrutină algoritmică numită Estimarea de Fază Cuantică. Am discutat QPE și relația sa cu Transformata Fourier Cuantică în modulul precedent. Pentru o recapitulare detaliată, mergi la modulul QFT sau la lecția lui John Watrous despre Estimarea de Fază Cuantică din cursul său de Algoritmi Cuantici. Vom trece prin esența procedurii acum:
În Estimarea de Fază Cuantică (QPE), pornim cu un unitar și o stare proprie a acelui unitar . Apoi, folosim QPE pentru a aproxima valoarea proprie corespunzătoare, care, deoarece operatorul este unitar, va fi de forma . Deci, găsirea valorii proprii este echivalentă cu găsirea valorii în funcția periodică. Circuitul arată astfel:

unde numărul de qubiți de control (cei qubiți din vârf în figura de mai sus) determină precizia aproximării.
În algoritmul lui Shor, folosim QPE pe operatorul unitar :
Aici, denotă o stare de bază computațională a registrului multi-qubit, unde valoarea binară a qubiților corespunde întregului . De exemplu, dacă și , atunci este reprezentat de starea de bază cu patru qubiți , deoarece patru qubiți sunt necesari pentru a codifica numere până la 15. (Dacă acest concept nu îți este familiar, consultă modulul introductiv Qiskit în clase pentru o recapitulare a codificării binare a stărilor cuantice.)
Acum, trebuie să identificăm o stare proprie a acestui unitar. Dacă am porni din starea , putem vedea că fiecare aplicare succesivă a lui va înmulți starea registrului nostru cu , și după aplicări vom ajunge din nou la starea . De exemplu cu și :
Deci superpozițiile stărilor din acest ciclu () de forma:
sunt toate stări proprii ale lui . (Există mai multe stări proprii decât doar acestea. Dar ne interesează doar cele de forma de mai sus.)
Verifică-ți înțelegerea
Citește întrebarea (întrebările) de mai jos, gândește-te la răspuns, apoi apasă pe triunghi pentru a dezvălui soluția.
Găsește o stare proprie a unitarului corespunzător lui și .
Răspuns:
Deci, ordinul . Stările proprii care ne interesează vor fi o superpoziție egală a tuturor stărilor prin care s-a trecut mai sus, cu diverse faze:
Să presupunem că am fi capabili să inițializăm starea qubitului nostru într-una din aceste stări proprii (spoiler — nu putem. Sau, cel puțin nu ușor. Vom explica de ce și ce putem face în schimb în scurt timp). Atunci am putea folosi QPE pentru a estima valoarea proprie corespunzătoare, unde . Apoi, vom putea determina ordinul prin simpla ecuație:
Dar ține minte, am spus că QPE estimează — nu ne oferă o valoare exactă. Avem nevoie ca estimarea să fie suficient de bună pentru a diferenția între și . Cu cât avem mai mulți Qubiți de control , cu atât estimarea va fi mai bună. În problemele de la sfârșitul lecției, ți se va cere să determini -ul minim necesar pentru a factoriza un număr .
Acum, trebuie să rezolvăm o problemă. Toată explicația de mai sus despre cum să găsim începe cu pregătirea stării proprii . Dar nu știm cum să facem asta fără să cunoaștem deja . Logica este circulară. Avem nevoie de o modalitate de a estima valoarea proprie fără a inițializa starea proprie.
În loc să pornim cu o stare proprie a lui , putem pregăti starea inițială în starea de Qubiți corespunzătoare lui în binar (adică ). Deși această stare în sine nu este în mod evident o stare proprie a lui , ea este o superpoziție peste toate stările proprii :
Verifică-ți înțelegerea
Citește întrebarea (întrebările) de mai jos, gândește-te la răspuns, apoi apasă pe triunghi pentru a dezvălui soluția.
Verifică că este echivalent cu superpoziția peste stările proprii pe care le-ai găsit pentru și în întrebarea de verificare anterioară.
Răspuns:
Cele patru stări proprii au fost:
Deci,
Cum ne ajută asta să găsim ordinul ? Deoarece starea de pornire este o superpoziție peste toate stările proprii de forma listată mai sus, atunci algoritmul QPE estimează simultan fiecare dintre corespunzătoare acestor stări proprii. Deci, măsurarea celor Qubiți de control la final va produce o aproximare a valorii unde este una dintre valorile proprii alese aleatoriu. Dacă repetăm acest circuit de câteva ori și obținem câteva eșantioane cu valori diferite ale lui , vom putea deduce rapid .
Implementează în Qiskit
Așa cum am menționat mai devreme, hardware-ul nostru nu este la punctul în care putem factoriza numere uriașe precum RSA1024. Vom factoriza doar un număr mic pentru a demonstra cum funcționează algoritmul. Pentru această demonstrație, vom folosi o versiune simplificată a codului prezentat în tutorialul algoritmului lui Shor. Dacă vrei mai multe detalii, te rog să vizitezi tutorialul.
Vom rula algoritmul folosind cadrul nostru standard pentru rezolvarea problemelor cuantice, numit cadrul de tipare Qiskit. Acesta constă din patru pași:
- Maparea problemei tale la un circuit cuantic
- Optimizarea circuitului pentru a fi rulat pe hardware cuantic
- Executarea circuitului tău pe calculatorul cuantic
- Post-procesarea măsurătorilor
1. Mapare
Să factorizăm , selectând ca număr întreg co-prim.
Mai întâi, trebuie să construim circuitul care va implementa unitarul de înmulțire modulară, . Aceasta este de fapt partea cea mai dificilă a întregii implementări și poate fi foarte costisitoare din punct de vedere computațional, în funcție de modul în care este realizată. Pentru aceasta, vom trișa puțin: știm că pornim din starea , și dintr-o întrebare de verificare anterioară,
Deci, vom construi un unitar care efectuează operațiile corecte pe aceste patru stări, dar lasă toate celelalte stări neschimbate. Aceasta este o trișare deoarece folosim cunoștințele noastre despre ordinul lui pentru a simplifica unitarul. Dacă am încerca de fapt să factorizăm un număr ai cărui factori ne sunt necunoscuți, nu am putea face acest lucru.
Verifică-ți înțelegerea
Citește întrebarea(întrebările) de mai jos, gândește-te la răspuns, apoi apasă triunghiul pentru a dezvălui soluția.
Cu cunoștințele tale despre modul în care operatorul transformă stările de mai sus, construiește operatorul dintr-o serie de gate-uri SWAP, care schimbă stările a doi qubiți. (Indiciu: rescrierea fiecărei stări în binar te va ajuta.)
Răspuns:
Să rescriem acțiunea lui asupra stărilor în binar:
Fiecare dintre aceste acțiuni poate fi realizată cu un simplu SWAP. se obține prin schimbarea stărilor qubitului și . se obține prin schimbarea stărilor qubitului și . Și așa mai departe. Astfel, putem descompune matricea în următoarea serie de gate-uri SWAP:
Amintindu-ne că operatorii acționează de la dreapta la stânga, să verificăm că aceasta are efectul dorit asupra fiecărei stări:
Acum putem scrie codul circuitului echivalent cu acest operator în Qiskit.
Mai întâi, importăm pachetele necesare:
# Import necessary packages
import numpy as np
from fractions import Fraction
from math import floor, gcd, log
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.library import QFTGate
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.visualization import plot_histogram
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler
Apoi, construim operatorul :
def M2mod15():
"""
M2 (mod 15)
"""
b = 2
U = QuantumCircuit(4)
U.swap(2, 3)
U.swap(1, 2)
U.swap(0, 1)
U = U.to_gate()
U.name = f"M_{b}"
return U
# Get the M2 operator
M2 = M2mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(4)
circ.compose(M2, inplace=True)
circ.decompose(reps=2).draw(output="mpl", fold=-1)
Algoritmul QPE folosește un poartă controlled-. Acum că avem un circuit , trebuie să îl transformăm într-un circuit controlled-:
def controlled_M2mod15():
"""
Controlled M2 (mod 15)
"""
b = 2
U = QuantumCircuit(4)
U.swap(2, 3)
U.swap(1, 2)
U.swap(0, 1)
U = U.to_gate()
U.name = f"M_{b}"
c_U = U.control()
return c_U
# Get the controlled-M2 operator
controlled_M2 = controlled_M2mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(5)
circ.compose(controlled_M2, inplace=True)
circ.decompose(reps=1).draw(output="mpl", fold=-1)
Acum avem gate-ul nostru controlled-. Dar pentru a rula algoritmul de Estimare Cuantică a Fazei, vom avea nevoie de controlled-, controlled-, până la controlled-, unde este numărul de qubiți folosiți pentru estimarea fazei. Cu cât mai mulți qubiți, cu atât mai precisă va fi estimarea fazei. Vom folosi qubiți de control pentru procedura noastră de estimare a fazei. Deci, avem nevoie de:
unde indicele , cu , corespunde qubitului de control. Acum să calculăm pentru fiecare valoare a lui :
def a2kmodN(a, k, N):
"""Compute a^{2^k} (mod N) by repeated squaring"""
for _ in range(k):
a = int(np.mod(a**2, N))
return a
k_list = range(8)
b_list = [a2kmodN(2, k, 15) for k in k_list]
print(b_list)
[2, 4, 1, 1, 1, 1, 1, 1]
Deoarece pentru , toți operatorii corespunzători ( și mai mari) sunt echivalenți cu identitatea. Deci, trebuie să construim încă o singură matrice, Notă: Această simplificare funcționează aici doar pentru că ordinul lui este . Odată ce (adică ), fiecare putere ulterioară a operatorului este identitatea. În general, pentru numere mai mari sau alegeri diferite ale lui , nu poți sări peste construirea puterilor superioare. Acesta este unul dintre motivele pentru care acesta este considerat un exemplu didactic: numerele mici permit scurtături care nu ar funcționa pentru cazuri mai mari.
def M4mod15():
"""
M4 (mod 15)
"""
b = 4
U = QuantumCircuit(4)
U.swap(1, 3)
U.swap(0, 2)
U = U.to_gate()
U.name = f"M_{b}"
return U
# Get the M4 operator
M4 = M4mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(4)
circ.compose(M4, inplace=True)
circ.decompose(reps=2).draw(output="mpl", fold=-1)
Și ca înainte, îl transformăm într-un operator controlat-:
def controlled_M4mod15():
"""
Controlled M4 (mod 15)
"""
b = 4
U = QuantumCircuit(4)
U.swap(1, 3)
U.swap(0, 2)
U = U.to_gate()
U.name = f"M_{b}"
c_U = U.control()
return c_U
# Get the controlled-M4 operator
controlled_M4 = controlled_M4mod15()
# Add it to a circuit and plot
circ = QuantumCircuit(5)
circ.compose(controlled_M4, inplace=True)
circ.decompose(reps=1).draw(output="mpl", fold=-1)
Acum putem pune totul laolaltă pentru a găsi ordinul lui cu un circuit cuantic, folosind estimarea de fază:
# Order finding problem for N = 15 with a = 2
N = 15
a = 2
# Number of qubits
num_target = floor(log(N - 1, 2)) + 1 # for modular exponentiation operators
num_control = 2 * num_target # for enough precision of estimation
# List of M_b operators in order
k_list = range(num_control)
b_list = [a2kmodN(2, k, 15) for k in k_list]
# Initialize the circuit
control = QuantumRegister(num_control, name="C")
target = QuantumRegister(num_target, name="T")
output = ClassicalRegister(num_control, name="out")
circuit = QuantumCircuit(control, target, output)
# Initialize the target register to the state |1>
circuit.x(num_control)
# Add the Hadamard gates and controlled versions of the
# multiplication gates
for k, qubit in enumerate(control):
circuit.h(k)
b = b_list[k]
if b == 2:
circuit.compose(
M2mod15().control(), qubits=[qubit] + list(target), inplace=True
)
elif b == 4:
circuit.compose(
M4mod15().control(), qubits=[qubit] + list(target), inplace=True
)
else:
continue # M1 is the identity operator
# Apply the inverse QFT to the control register
circuit.compose(QFTGate(num_control).inverse(), qubits=control, inplace=True)
# Measure the control register
circuit.measure(control, output)
circuit.draw("mpl", fold=-1)
2. Optimizează
Acum că am mapat circuitul nostru, următorul pas este să îl optimizăm pentru a rula pe un anumit calculator cuantic. Mai întâi trebuie să încărcăm backend-ul.
service = QiskitRuntimeService()
backend = service.backend("ibm_marrakesh")
Dacă nu ai timp disponibil în contul tău sau dorești să folosești un simulator din orice motiv, poți rula celula de mai jos pentru a configura un simulator care va imita dispozitivul cuantic pe care l-am selectat mai sus:
pm = generate_preset_pass_manager(optimization_level=2, backend=backend)
transpiled_circuit = pm.run(circuit)
print(f"2q-depth: {transpiled_circuit.depth(lambda x: x.operation.num_qubits==2)}")
print(f"2q-size: {transpiled_circuit.size(lambda x: x.operation.num_qubits==2)}")
print(f"Operator counts: {transpiled_circuit.count_ops()}")
transpiled_circuit.draw(output="mpl", fold=-1, style="clifford", idle_wires=False)
2q-depth: 188
2q-size: 281
Operator counts: OrderedDict({'sx': 548, 'rz': 380, 'cz': 281, 'measure': 8, 'x': 6})

3. Execută
# Sampler primitive to obtain the probability distribution
sampler = Sampler(backend)
# Turn on dynamical decoupling with sequence XpXm
sampler.options.dynamical_decoupling.enable = True
sampler.options.dynamical_decoupling.sequence_type = "XpXm"
# Enable gate twirling
sampler.options.twirling.enable_gates = True
pub = transpiled_circuit
job = sampler.run([pub], shots=1024)
result = job.result()[0]
counts = result.data["out"].get_counts()
plot_histogram(counts, figsize=(35, 5))

Vedem patru vârfuri clare la 00000000, 01000000, 10000000 și 11000000, cu câteva numărători în alte șiruri de biți din cauza zgomotului din calculatorul cuantic. Le vom ignora pe acestea și vom păstra doar cele patru dominante impunând un prag: doar numărătorile de peste acest prag sunt considerate un semnal real peste zgomot.
# Dictionary of bitstrings and their counts to keep
counts_keep = {}
# Threshold to filter
threshold = np.max(list(counts.values())) / 2
for key, value in counts.items():
if value > threshold:
counts_keep[key] = value
print(counts_keep)
4. Post-procesare
Pentru algoritmul lui Shor, o mare parte din algoritm se execută clasic. Prin urmare, vom pune restul în pasul de „post-procesare", după ce am obținut măsurătorile de la calculatorul cuantic. Fiecare dintre măsurătorile de mai sus poate fi convertită în numere întregi care, după ce le împărțim la , reprezintă aproximările noastre pentru , unde este aleatoriu de fiecare dată.
a = 2
N = 15
FACTOR_FOUND = False
num_attempt = 0
while not FACTOR_FOUND:
print(f"\nATTEMPT {num_attempt}:")
# Here, we get the bitstring by iterating over outcomes
# of a previous hardware run with multiple shots.
# Instead, we can also perform a single-shot measurement
# here in the loop.
bitstring = list(counts_keep.keys())[num_attempt]
num_attempt += 1
# Find the phase from measurement
decimal = int(bitstring, 2)
phase = decimal / (2**num_control) # phase = k / r
print(f"Phase: theta = {phase}")
# Guess the order from phase
frac = Fraction(phase).limit_denominator(N)
r = frac.denominator # order = r
print(f"Order of {a} modulo {N} estimated as: r = {r}")
if phase != 0:
# Guesses for factors are gcd(a^{r / 2} ± 1, 15)
if r % 2 == 0:
x = pow(a, r // 2, N) - 1
d = gcd(x, N)
if d > 1:
FACTOR_FOUND = True
print(f"*** Non-trivial factor found: {x} ***")
ATTEMPT 0:
Phase: theta = 0.0
Order of 2 modulo 15 estimated as: r = 1
ATTEMPT 1:
Phase: theta = 0.75
Order of 2 modulo 15 estimated as: r = 4
*** Non-trivial factor found: 3 ***
Concluzie
După parcurgerea acestui modul, s-ar putea să ai o nouă apreciere pentru strălucirea lui Peter Shor, care a venit cu un algoritm atât de ingenios. Dar sperăm că ai atins și un nou nivel de înțelegere a simplității sale înșelătoare. Deși algoritmul poate părea impresionant de complex (sau intimidant), dacă îl descompui în fiecare pas de logică și îl parcurgi încet, vei reuși și tu să rulezi algoritmul lui Shor.
Deși suntem departe de a folosi acest algoritm pentru a factoriza numere precum RSA1024, calculatoarele noastre cuantice devin mai bune în fiecare zi, iar odată ce se atinge un prag numit toleranță la defecte, algoritmi precum aceștia vor urma în scurt timp. Este o perioadă entuziasmantă în care să înveți despre calculul cuantic!
Probleme
Concepte esențiale:
- Sistemele criptografice moderne se bazează pe dificultatea clasică a factorizării numerelor întregi mari.
- Aritmetica modulară — inclusiv structurile și — furnizează fundația matematică a algoritmului lui Shor.
- Problema factorizării unui număr întreg poate fi redusă la problema găsirii ordinului unui număr modulo .
- Găsirea cuantică a ordinului folosește tehnici de estimare cuantică a fazei pentru a determina perioada funcției .
- Algoritmul lui Shor constă dintr-un flux de lucru hibrid clasic-cuantic care selectează o bază, efectuează găsirea cuantică a ordinului și apoi calculează clasic factorii din rezultat.
Adevărat/Fals:
- A/F Eficiența algoritmului lui Shor amenință securitatea criptării RSA.
- A/F Algoritmul lui Shor poate fi executat eficient pe orice calculator cuantic modern.
- A/F Algoritmul lui Shor utilizează estimarea cuantică a fazei (QPE) ca subrutină esențială.
- A/F Partea clasică a algoritmului lui Shor implică calcularea celui mai mare divizor comun (CMDC).
- A/F Algoritmul lui Shor funcționează numai pentru factorizarea numerelor pare.
- A/F O rulare reușită a algoritmului lui Shor garantează întotdeauna factorii corecți.
Răspuns scurt:
- De ce este considerat algoritmul lui Shor o potențială amenințare viitoare la adresa criptării RSA?
- De ce este utilă găsirea perioadei, sau ordinului, a unei funcții exponențiale modulare pentru factorizarea unui număr în algoritmul lui Shor?
Probleme de provocare:
-
De câți Qubiți de control avem nevoie pentru un număr dat pe care încercăm să îl factorizăm, pentru a obține precizia în QPE necesară găsirii valorii corecte a ordinului ?
-
Urmând procedura pe care am descris-o aici pentru a factoriza 15, încearcă acum să factorizezi 21.