Přeskočit na hlavní obsah

Ansatz

Podívej se, jak Victoria Lipinska vysvětluje, co je ansatz a proč nás zajímá v kontextu variačního kvantového eigensolverů (VQE).

Reference

Následující články jsou citovány ve výše uvedeném videu.

Kód ansatzu

V předchozí lekci jsi vytvořil/a Hamiltonián, který popisuje energii molekuly, která tě zajímá, a namapoval/a jej do formátu vhodného pro kvantový počítač. VQE používá variační Circuit k přípravě kvantových stavů. Tyto stavy pak použijeme k určení střední hodnoty Hamiltoniánu (energie). Parametry ve variačním Circuit jsou měněny, dokud výpočet nekonverguje k minimální střední hodnotě. V kontextu kvantové chemie by to měla být energie základního stavu. Tato lekce se zaměřuje na variační Circuit, nazývaný také ansatz (německé slovo znamenající „přístup" nebo „metoda"). V této lekci se naučíš

  • sadu předpřipravených ansaetzů dostupných v knihovně Circuit
  • jak specifikovat nebo upravit vlastnosti ansatzu
  • jak sestavit vlastní ansatz
  • příklady dobrých a špatných ansaetzů

Knihovna Qiskit Circuit má mnoho kategorií Circuit, které lze použít jako ansatz. Zde omezíme naši diskuzi na dvoulokální Circuit (Circuit sestávající z Gate, které působí nanejvýš na dva Qubit najednou). Efficient SU2 je běžně používaný ansatz.

Circuit efficient_su_2 se skládá z vrstev jednoqubitových operací rozložených přes SU(2) (speciální unitární skupina stupně 2, jako jsou Pauliho rotační Gate) a CX provázání. Jedná se o heuristický vzor, který může být užitečný ve variačních kvantových algoritmech jako VQE a klasifikačních Circuit v kvantovém strojovém učení (QML).

Začneme čtyřqubitovým příkladem Circuit efficient_su2 se dvěma typy SU(2) Gate, řekněme rx a y. Také specifikujeme schéma provázání a počet opakování. Pokud jednoduše zavoláš .draw() na Circuit, dostaneš poměrně abstraktní reprezentaci. Přehlednější diagram Circuit získáš pomocí .decompose().draw(), a zde použijeme 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 ├
└──────────┘└───┘ └───┘ └──────────┘└───┘

Output of the previous code cell

Gate SU(2) se objevují na začátku a na konci v pořadí a prvcích specifikovaných v su2_gates = [...]. Schéma provázání linear znamená, že Gate CX prochází číslovanými Qubit, provazuje 0 a 1, pak 1 a 2 a tak dále po diagonální linii v Circuit. Jak asi očekáváš, nastavení reps = 2 jednoduše přidá vrstvu provázání a závěrečnou vrstvu SU(2). Nastavení reps = n odpovídá n vrstvám provázání, s vrstvami SU(2) mezi nimi a na každém konci.

SU2_ansatz2 = efficient_su2(
4, su2_gates=["rx", "y", "z"], entanglement="linear", reps=2
)
SU2_ansatz2.decompose().draw(output="mpl")

Output of the previous code cell

Existuje několik dalších schémat provázání. Dvě, která stojí za zmínku, jsou circular a full. Kruhové provázání je identické s lineárním provázáním, ale s přidaným Gate CX provazujícím první a poslední Qubit. Schéma plného provázání zahrnuje Gate CX mezi každým párem Qubit. Poznamenejme, že pro N-qubitový Circuit je to N(N1)/2N(N-1)/2 Gate CXCX, a může být výpočetně nákladné.

SU2_ansatz3 = efficient_su2(
4, su2_gates=["rx", "y", "z"], entanglement="circular", reps=1
)
SU2_ansatz3.decompose().draw(output="mpl")

Output of the previous code cell

SU2_ansatz4 = efficient_su2(4, su2_gates=["rx", "y", "z"], entanglement="full", reps=1)
SU2_ansatz4.decompose().draw(output="mpl")

Output of the previous code cell

Hloubku svého Circuit můžeš sledovat pomocí .depth(), nebo někdy .decompose().depth().

print(SU2_ansatz4.decompose().depth())
11

Zobecněním efficient_su2 je dvoulokální Circuit, který je sám o sobě speciálním případem n-lokálních Circuit. Dvoulokální Circuit také obsahuje bloky SU(2) (nebo rotační bloky) a bloky provázání. Zde máme volnost specifikovat typ Gate provázání, který chceme použít, například Gate CRX. V tomto příkladu všechny Gate přijímají parametr, ale to nemusí být vždy nutné. Například by bylo možné použít Gate Y rotace a Gate CX pro provázání.

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")

Output of the previous code cell

Posledním ansatzem, o kterém budeme mluvit jménem, je Pauli-two-design. Tento Circuit obsahuje počáteční rotaci RY(pi/4)RY(pi/4) a rotační vrstvy obsahují jednoqubitové Pauliho rotace, kde osa je zvolena rovnoměrně náhodně jako X, Y nebo Z. Vrstvy provázání jsou tvořeny párově CZ Gate s celkovou hloubkou dvě. Všimni si rozdílu v hloubce provázání (a celkového Circuit) mezi tímto pauli_two_design a například 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")

Output of the previous code cell

Tyto předpřipravené variační Circuit jsou užitečné heuristiky jak z hlediska dosažení požadované úrovně provázání, tak z hlediska omezení hloubky Circuit. Ale není na nich nic magického. Máš svobodu vytvořit si vlastní variační Circuit. To může být výhodné v případech, kdy víš něco o provázání cílového stavu svého systému.

Chceš-li si vytvořit vlastní ansatz, jednoduše sestavíš kvantový Circuit, kde určitá podmnožina Gate je funkcí prvků vektoru parametrů (ve třísbitovém příkladu níže „theta").

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

Output of the previous code cell

Obecně platí, že výběr nejlepšího ansatzu je umění; nejlepší ansatz je ten, který ti pomůže dosáhnout cíle v co nejmenším počtu optimalizačních kroků. Snáze se identifikují ansaetze, které pravděpodobně budou špatné. Například větší hloubka Circuit má tendenci vést k hromadění chyb. Zmírnění chyb s tím může pomoci, ale je dobrou praxí udržovat hloubku Circuit co nejnižší, jak je rozumné. Ale nevynechávej provázání, které je nezbytné. Můžeš mít cílový stav, který vyžaduje schéma plného provázání. Níže jsou uvedeny dva příklady, které jsou pravděpodobně špatnými volbami z celkem zřejmých důvodů. Výběr dobrého ansatzu bude znovu probrán v pozdějších sekcích v kontextu testů konvergence.

Tento první Circuit bude pravděpodobně špatnou volbou, protože poslední Qubit není vůbec propojen s ostatními. Ve skutečnosti na posledním Qubit neexistuje žádná výpočetně smysluplná akce. S největší pravděpodobností by měl být poslední Qubit buď propojen s ostatními, nebo odstraněn z výpočtu.

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

Output of the previous code cell

Tento poslední Circuit je pravděpodobně špatnou volbou, protože hloubka Gate je velmi vysoká a čtyřnásobné opakování vrstvy provázání pravděpodobně nepovede k podstatně lepší shodě s cílovým stavem než dvě nebo tři opakování.

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

Output of the previous code cell

Tyto Circuit nejsou „úplné" v tom smyslu, že do mnoha Gate je stále nutné vložit neznámé a proměnné parametry. Tyto parametry jsou voleny postupnými odhady a aktualizací parametrů za účelem snížení střední hodnoty účelové funkce (v chemickém kontextu typicky energie základního stavu). V jedné nebo dokonce několika dimenzích je to triviální. Ale výše uvedený Circuit má 20 variačních parametrů, což znamená, že nalezení cílového stavu s minimální energií vyžaduje prohledávání 20-dimenzionálního prostoru stavů (další důvod nezahrnovat zbytečné Gate do Circuit). Zde přicházejí ke slovu klasické optimalizační algoritmy, a to je téma další lekce.