Ansatz-ul
Urmărește-o pe Victoria Lipinska explicând ce este un ansatz și de ce ne interesează în contextul unui solver cuantic variațional (VQE).
Referințe
Articolele de mai jos sunt menționate în videoclipul de mai sus.
- The theory of variational hybrid quantum-classical algorithms, McClean, et al.
- Quantum Chemistry in the Age of Quantum Computing, Cao, et al.
- Noisy intermediate-scale quantum (NISQ) algorithms, Bharti, et al.
- The Variational Quantum Eigensolver: A review of methods and best practices, Tilly, et al.
- Hardware-efficient Variational Quantum Eigensolver for Small Molecules and Quantum Magnets, Kandala, et al.
- Quantum computational chemistry, McArdle, et al.
Codul ansatz-ului
În lecția anterioară ai creat un Hamiltonian care descrie energia moleculei de interes și l-ai mapat într-un format util pentru un calculator cuantic. VQE folosește un circuit variațional pentru a pregăti stări cuantice. Aceste stări sunt apoi folosite pentru a determina valoarea de așteptare a Hamiltonianului (energia). Parametrii din circuitul variațional sunt variați până când calculul converge la o valoare de așteptare minimă. În contextul chimiei cuantice, aceasta ar trebui să fie energia stării fundamentale. Această lecție se concentrează pe circuitul variațional, numit și ansatz (un cuvânt german care înseamnă „abordare" sau „metodă"). În această lecție vei învăța
- setul de ansaetze pre-construite disponibile în biblioteca de circuite
- Cum să specifici sau să modifici caracteristicile unui ansatz
- Cum să îți construiești propriul ansatz
- exemple de ansaetze bune și proaste
Biblioteca de circuite Qiskit conține multe categorii de circuite care pot fi utilizate ca ansatz. Aici, vom restrânge discuția la circuite bi-locale (circuite formate din porți care acționează pe cel mult doi qubiți deodată). Efficient SU2 este un ansatz frecvent utilizat.
Un circuit efficient_su_2 constă din straturi de operații pe qubiți individuali generate de SU(2) (grupul unitar special de gradul 2, precum porțile de rotație Pauli) și entanglări CX. Acesta este un tipar euristic care poate fi util în algoritmii cuantici variționali precum VQE și circuitele de clasificare din învățarea automată cuantică (QML).
Vom începe cu un exemplu de circuit efficient_su2 cu patru qubiți și două tipuri de porți SU(2), să zicem rx și y. De asemenea, specificăm o schemă de entanglare și numărul de repetiții. Dacă pur și simplu .draw() circuitele, vei obține o reprezentare destul de abstractă. O diagramă de circuit mai ușor de înțeles se obține folosind .decompose().draw(), iar aici vom folosi `output = "mpl"'.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit.circuit.library import efficient_su2
SU2_ansatz = efficient_su2(4, su2_gates=["rx", "y"], entanglement="linear", reps=1)
print(SU2_ansatz.draw())
SU2_ansatz.decompose().draw(output="mpl")
┌──────────┐┌───┐ ┌──────────┐ ┌───┐
q_0: ┤ Rx(θ[0]) ├┤ Y ├──■──┤ Rx(θ[4]) ├───┤ Y ├─────────────────────
├──────────┤├───┤┌─┴─┐└──────────┘┌──┴───┴───┐ ┌───┐
q_1: ┤ Rx(θ[1]) ├┤ Y ├┤ X ├─────■──────┤ Rx(θ[5]) ├───┤ Y ├─────────
├──────────┤├───┤└───┘ ┌─┴─┐ └──────────┘┌──┴───┴───┐┌───┐
q_2: ┤ Rx(θ[2]) ├┤ Y ├────────┤ X ├─────────■──────┤ Rx(θ[6]) ├┤ Y ├
├──────────┤├───┤ └───┘ ┌─┴─┐ ├──────────┤├───┤
q_3: ┤ Rx(θ[3]) ├┤ Y ├────────────────────┤ X ├────┤ Rx(θ[7]) ├┤ Y ├
└──────────┘└───┘ └───┘ └──────────┘└───┘
Porțile SU(2) apar la început și la sfârșit, în ordinea și cu elementele specificate în su2_gates = [...]. Schema de entanglare linear înseamnă că porțile CX parcurg qubiții numerotați, entanglând 0 & 1, apoi 1 & 2, și tot așa, în diagonală de-a lungul circuitului. Așa cum te-ai putea aștepta, setând reps = 2 se adaugă pur și simplu un strat de entanglare și un strat SU(2) final. Setând reps = n se obțin n straturi de entanglare, cu straturi SU(2) între ele și la fiecare capăt.
SU2_ansatz2 = efficient_su2(
4, su2_gates=["rx", "y", "z"], entanglement="linear", reps=2
)
SU2_ansatz2.decompose().draw(output="mpl")
Există și alte scheme de entanglement. Două care merită menționate sunt circular și full. Entanglementul circular este identic cu cel liniar, dar cu o poartă CX suplimentară care entanglează primul și ultimul Qubit. Schema de entanglement complet include o poartă CX între fiecare pereche de Qubiți. Rețineți că pentru un Circuit de N Qubiți, aceasta înseamnă porți , ceea ce poate deveni costisitor din punct de vedere computațional.
SU2_ansatz3 = efficient_su2(
4, su2_gates=["rx", "y", "z"], entanglement="circular", reps=1
)
SU2_ansatz3.decompose().draw(output="mpl")
SU2_ansatz4 = efficient_su2(4, su2_gates=["rx", "y", "z"], entanglement="full", reps=1)
SU2_ansatz4.decompose().draw(output="mpl")
Poți monitoriza adâncimile Circuit-ului tău folosind .depth(), sau uneori .decompose().depth().
print(SU2_ansatz4.decompose().depth())
11
O generalizare a efficient_su2 este circuitul two-local, care este el însuși un caz particular al circuitelor n-local. Circuitele two-local conțin, de asemenea, blocuri SU(2) (sau blocuri de rotație) și blocuri de entanglement. Aici ești liber să specifici tipul de porți de entanglement pe care dorești să le folosești, de exemplu porțile CRX. În acest exemplu, toate porțile acceptă un parametru, dar nu trebuie neapărat să fie așa. Ai putea folosi, de exemplu, porți de rotație Y și porți de entanglement CX.
from qiskit.circuit.library import n_local
rotation_blocks = ["ry"]
entanglement_blocks = ["crx"]
two_ansatz = n_local(
4, rotation_blocks, entanglement_blocks, "linear", insert_barriers=True, reps=2
)
two_ansatz.decompose().draw(output="mpl")
Ultimul ansatz despre care vom vorbi după nume este Pauli-two-design. Acest Circuit conține o rotație inițială , iar straturile de rotație conțin rotații Pauli pe un singur Qubit, unde axa este aleasă uniform la întâmplare dintre X, Y sau Z. Straturile de entanglement sunt compuse din porți CZ aplicate pe perechi, cu o adâncime totală de două. Observă diferența de adâncime a entanglementului (și a Circuit-ului total) între acest pauli_two_design și, de exemplu, efficient_su2.
from qiskit.circuit.library import pauli_two_design
PtwoD_ansatz = pauli_two_design(5, reps=1, seed=10599, insert_barriers=True)
PtwoD_ansatz.decompose().draw(output="mpl")
Aceste circuite variționale prefabricate sunt euristici utile atât pentru atingerea unui nivel dorit de entanglement, cât și pentru limitarea adâncimii Circuit-ului. Dar nu există nimic magic în ele. Ești liber să îți construiești propriul Circuit variațional. Într-adevăr, aceasta poate fi avantajoasă în cazurile în care știi ceva despre entanglementul stării țintă a sistemului tău.
Pentru a-ți construi propriul ansatz, pur și simplu construiești un Circuit cuantic în care un subset de porți sunt funcții ale elementelor unui vector de parametri ("theta" în exemplul cu trei Qubiți de mai jos).
from qiskit import QuantumCircuit
from qiskit.circuit import ParameterVector
n = 3
theta = ParameterVector("θ", length=n)
qc = QuantumCircuit(n)
qc.h(0)
qc.h(2)
for i in range(n - 1):
qc.cx(i, i + 1)
qc.cz(0, n - 1)
qc.barrier()
for i in range(n):
qc.ry(theta[i], i)
qc.barrier()
qc.cz(0, n - 1)
for i in reversed(range(n - 1)):
qc.cx(i, i + 1)
qc.h(0)
qc.h(1)
own_ansatz = qc
print(own_ansatz.depth())
qc.draw("mpl")
9
În general, selectarea celui mai bun ansatz este o artă; cel mai bun ansatz este orice ansatz care te ajută să atingi ținta în cel mai mic număr de pași de optimizare. Este mai ușor să identifici ansatz-uri care sunt probabil proaste. De exemplu, o adâncime mai mare a Circuit-ului tinde să ducă la acumularea erorilor. Mitigarea erorilor poate ajuta cu aceasta, dar este o bună practică să menții adâncimea Circuit-ului cât mai mică posibil. Dar nu sări peste entanglementul necesar. S-ar putea să ai o stare țintă care necesită o schemă completă de entanglement. Două exemple sunt prezentate mai jos care sunt probabil alegeri proaste din motive destul de evidente. Alegerea unui ansatz bun va fi reluată în secțiunile ulterioare în contextul testelor de convergență.
Acest prim Circuit este probabil o alegere proastă deoarece ultimul qubit nu este entanglat deloc cu ceilalți. Într-adevăr, nu există nicio acțiune semnificativă din punct de vedere computațional asupra ultimului qubit. Cu toată probabilitatea, ultimul qubit ar trebui fie entanglat cu ceilalți, fie eliminat din calcul.
n = 4
theta = ParameterVector("θ", length=n)
qc = QuantumCircuit(n)
qc.h(0)
qc.h(2)
for i in range(n - 2):
qc.cx(i, i + 1)
qc.cz(0, n - 2)
qc.barrier()
for i in range(n):
qc.ry(theta[i], i)
qc.barrier()
qc.cz(0, n - 2)
for i in reversed(range(n - 2)):
qc.cx(i, i + 1)
qc.h(0)
qc.h(1)
own_ansatz2 = qc
print(own_ansatz2.depth())
qc.draw("mpl")
9
Acest ultim Circuit este probabil o alegere proastă, deoarece adâncimea porților este foarte mare, iar repetarea stratului de entanglement de patru ori nu este probabil să producă o potrivire substanțial mai bună cu starea țintă decât două sau trei repetări.
su2_ansatz_long = efficient_su2(
4, su2_gates=["rx", "y", "z"], entanglement="linear", reps=4
)
print(su2_ansatz_long.decompose().depth())
su2_ansatz_long.decompose().draw(output="mpl")
24
Aceste circuite nu sunt „complete" în sensul că mai există parametri necunoscuți și variabili care trebuie inserați în multe dintre porți. Acei parametri sunt aleși făcând presupuneri succesive și actualizând parametrii pentru a reduce valoarea de așteptare a funcției de cost (în contextul chimiei, de obicei energia stării fundamentale). Într-una sau chiar câteva dimensiuni, aceasta este trivială. Dar circuitul de mai sus are 20 de parametri variționali, ceea ce înseamnă că găsirea stării țintă cu energia minimă presupune căutarea într-un spațiu de stare cu 20 de dimensiuni (un alt motiv pentru a nu include porți de Circuit inutile). Aici intră în joc algoritmii de optimizare clasică, iar acesta este subiectul lecției următoare.