Řezání drátů formulované jako dvouqubitová instrukce `Move`
V tomto tutoriálu rekonstruujeme očekávané hodnoty sedmiqubitového Circuit tím, že ho rozdělíme na dva čtyřqubitové Circuit pomocí řezání drátů.
Toto jsou kroky, které podnikneme v rámci tohoto Qiskit vzoru:
- Krok 1: Mapování problému na kvantové Circuit a operátory:
- Namapuj hamiltonián na kvantový Circuit.
- Krok 2: Optimalizace pro cílový hardware [Využívá addon pro řezání]:
- Rozřež Circuit a pozorovatelnou.
- Transpiluj dílčí experimenty pro hardware.
- Krok 3: Spuštění na cílovém hardware:
- Spusť dílčí experimenty získané v Kroku 2 pomocí primitiva
Sampler.
- Spusť dílčí experimenty získané v Kroku 2 pomocí primitiva
- Krok 4: Post-processing výsledků [Využívá addon pro řezání]:
- Zkombinuj výsledky Kroku 3 a rekonstruuj očekávanou hodnotu sledované pozorovatelné.
Krok 1: Mapování
Vytvoření Circuit k řezání
Nejprve vyjdeme z Circuit inspirovaného obr. 1(a) z arXiv:2302.03366v1.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-cutting qiskit-aer qiskit-ibm-runtime
import numpy as np
from qiskit import QuantumCircuit
qc_0 = QuantumCircuit(7)
for i in range(7):
qc_0.rx(np.pi / 4, i)
qc_0.cx(0, 3)
qc_0.cx(1, 3)
qc_0.cx(2, 3)
qc_0.cx(3, 4)
qc_0.cx(3, 5)
qc_0.cx(3, 6)
qc_0.cx(0, 3)
qc_0.cx(1, 3)
qc_0.cx(2, 3)
<qiskit.circuit.instructionset.InstructionSet at 0x7f16ab191a80>
qc_0.draw("mpl")

Specifikace pozorovatelné
from qiskit.quantum_info import SparsePauliOp
observable = SparsePauliOp(["ZIIIIII", "IIIZIII", "IIIIIIZ"])
Krok 2: Optimalizace
Vytvoření nového Circuit, kde byly instrukce Move umístěny na požadovaná místa řezu
Na základě výše uvedeného Circuit chceme umístit dva řezy drátů na prostřední qubitovou linku, aby se Circuit mohl rozdělit na dva Circuit o čtyřech Qubitech každý. Jedním ze způsobů, jak toho dosáhnout, je ručně umístit dvouqubitové instrukce Move, které přenesou stav z jednoho qubitového drátu na druhý. Instrukce Move je koncepčně ekvivalentní operaci reset na druhém Qubitu, po níž následuje Gate SWAP. Účinkem této instrukce je přenos stavu prvního (zdrojového) Qubitu na druhý (cílový) Qubit, přičemž příchozí stav druhého Qubitu je zahozen. Aby to fungovalo podle záměru, je důležité, aby druhý (cílový) Qubit nesdílel žádné provázání se zbytkem systému; v opačném případě by operace reset způsobila částečný kolaps stavu zbytku systému.
Zde sestavíme nový Circuit s jedním dalším Qubitem a s operacemi Move na příslušných místech. V tomto příkladu je možné Qubit znovu použít: zdrojový Qubit první instrukce Move se stane cílovým Qubitem druhé instrukce Move.
Poznámka: Jako alternativu k přímé práci s instrukcemi Move lze místa řezů drátů označit pomocí jednoqubitové instrukce CutWire. Funkce cut_wires slouží k transformaci instrukcí CutWire na instrukce Move na nově alokovaných Qubitech. Na rozdíl od ruční metody však tato automatická metoda neumožňuje opětovné použití qubitových drátů. Podrobnosti najdeš v návodech pro CutWire.
from qiskit_addon_cutting.instructions import Move
qc_1 = QuantumCircuit(8)
for i in [*range(4), *range(5, 8)]:
qc_1.rx(np.pi / 4, i)
qc_1.cx(0, 3)
qc_1.cx(1, 3)
qc_1.cx(2, 3)
qc_1.append(Move(), [3, 4])
qc_1.cx(4, 5)
qc_1.cx(4, 6)
qc_1.cx(4, 7)
qc_1.append(Move(), [4, 3])
qc_1.cx(0, 3)
qc_1.cx(1, 3)
qc_1.cx(2, 3)
qc_1.draw("mpl")

Vytvoření pozorovatelné k novému Circuit
Tato pozorovatelná odpovídá observable, ale musíme správně zohlednit přidaný extra qubitový drát (tj. vložíme „I" na index 4). Pozor, v Qiskitu odpovídá v řetězcové reprezentaci Qubit-0 znaku Pauliho operátoru zcela vpravo.
observable_expanded = SparsePauliOp(["ZIIIIIII", "IIIIZIII", "IIIIIIIZ"])
Oddělení Circuit a pozorovatelných
Stejně jako v předchozích tutoriálech budou Qubity sdílející stejný štítek oddílu seskupeny dohromady a nelokalní Gate přesahující více než jeden oddíl budou rozřezány.
from qiskit_addon_cutting import partition_problem
partitioned_problem = partition_problem(
circuit=qc_1, partition_labels="AAAABBBB", observables=observable_expanded.paulis
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
bases = partitioned_problem.bases
Vizualizace rozloženého problému
subobservables
{'A': PauliList(['IIII', 'ZIII', 'IIIZ']),
'B': PauliList(['ZIII', 'IIII', 'IIII'])}
subcircuits["A"].draw("mpl")

subcircuits["B"].draw("mpl")

Výpočet vzorkovací režie pro zvolené řezy
Zde řežeme dva dráty, což vede ke vzorkovací režii .
Více informací o vzorkovací režii způsobené řezáním Circuit najdeš ve vysvětlujících materiálech.
print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
Sampling overhead: 256.0