Lumaktaw sa pangunahing nilalaman

Pagputol ng circuit para sa pagbawas ng lalim

Tinantyang paggamit: Walong minuto sa isang Eagle processor (PAUNAWA: Ito ay tantiya lamang. Maaaring mag-iba ang inyong runtime.)

Pinagmulan​

Ipinakikita ng tutorial na ito kung paano bumuo ng Qiskit pattern para sa pagputol ng mga gate sa quantum circuit upang bawasan ang lalim ng circuit. Para sa mas malalim na talakayan tungkol sa pagputol ng circuit, bisitahin ang circuit cutting Qiskit addon docs.

Mga Kinakailangan​

Bago magsimula sa tutorial na ito, siguraduhing mayroon kayong naka-install na sumusunod:

  • Qiskit SDK v2.0 o mas bago, na may suportang visualization
  • Qiskit Runtime v0.22 o mas bago (pip install qiskit-ibm-runtime)
  • Circuit cutting Qiskit addon v0.9.0 o mas bago (pip install qiskit-addon-cutting)

Pag-setup​

# Added by doQumentation β€” required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-cutting qiskit-ibm-runtime
import numpy as np

from qiskit.circuit.library import EfficientSU2
from qiskit.quantum_info import PauliList, Statevector, SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

from qiskit_addon_cutting import (
cut_gates,
generate_cutting_experiments,
reconstruct_expectation_values,
)

from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2

Hakbang 1: Magtakda ng classical inputs sa quantum problem​

Isasagawa natin ang ating Qiskit pattern gamit ang apat na hakbang na nakabalangkas sa docs. Sa kasong ito, sisimulahin natin ang mga expectation value sa isang circuit na may tiyak na lalim sa pamamagitan ng pagputol ng mga gate na nagreresulta sa swap gates at pagsasagawa ng mga subexperiment sa mas mababaw na mga circuit. Ang pagputol ng gate ay nauugnay sa Hakbang 2 (mag-optimize ng circuit para sa quantum execution sa pamamagitan ng pagbubukod ng mga malayong gate) at 4 (post-processing upang muling itayo ang mga expectation value sa orihinal na circuit). Sa unang hakbang, bubuo tayo ng circuit mula sa Qiskit circuit library at magtakda ng ilang mga observable.

  • Input: Mga classical parameter upang tukuyin ang isang circuit
  • Output: Abstract circuit at mga observable
circuit = EfficientSU2(num_qubits=4, entanglement="circular").decompose()
circuit.assign_parameters([0.4] * len(circuit.parameters), inplace=True)
observables = PauliList(["ZZII", "IZZI", "IIZZ", "XIXI", "ZIZZ", "IXIX"])
circuit.draw("mpl", scale=0.8, style="iqp")

Output of the previous code cell

Hakbang 2: I-optimize ang problema para sa quantum hardware execution​

  • Input: Abstract circuit at mga observable
  • Output: Target circuit at mga observable na ginawa sa pamamagitan ng pagputol ng mga malayong gate upang bawasan ang transpiled circuit depth

Pumipili tayo ng paunang layout na nangangailangan ng dalawang swap upang maisagawa ang mga gate sa pagitan ng mga qubit 3 at 0 at isa pang dalawang swap upang ibalik ang mga qubit sa kanilang mga paunang posisyon. Pumipili tayo ng optimization_level=3, na siyang pinakamataas na antas ng optimization na magagamit sa preset pass manager.

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, min_num_qubits=circuit.num_qubits, simulator=False
)

pm = generate_preset_pass_manager(
optimization_level=3, initial_layout=[0, 1, 2, 3], backend=backend
)
transpiled_qc = pm.run(circuit)

Coupling map showing the qubits that will need to be swapped

print(f"Transpiled circuit depth: {transpiled_qc.depth()}")
transpiled_qc.draw("mpl", scale=0.4, idle_wires=False, style="iqp", fold=-1)
Transpiled circuit depth: 103

Output of the previous code cell

Hanapin at putulin ang mga malayong gate: Papalitan natin ang mga malayong gate (mga gate na nag-uugnay ng mga non-local qubit, 0 at 3) ng mga TwoQubitQPDGate object sa pamamagitan ng pagtukoy ng kanilang mga indise. Ang cut_gates ay papalitan ang mga gate sa tinukoy na mga indise ng mga TwoQubitQPDGate object at magbabalik din ng listahan ng mga QPDBasis instance -- isa para sa bawat gate decomposition. Ang QPDBasis object ay naglalaman ng impormasyon tungkol sa kung paano bubuuin ang mga pinutol na gate sa mga single-qubit operation.

# Find the indices of the distant gates
cut_indices = [
i
for i, instruction in enumerate(circuit.data)
if {circuit.find_bit(q)[0] for q in instruction.qubits} == {0, 3}
]

# Decompose distant CNOTs into TwoQubitQPDGate instances
qpd_circuit, bases = cut_gates(circuit, cut_indices)

qpd_circuit.draw("mpl", scale=0.8)

Output of the previous code cell

Bumuo ng mga subexperiment na isasagawa sa backend: Tumatanggap ang generate_cutting_experiments ng circuit na naglalaman ng mga TwoQubitQPDGate instance at mga observable bilang PauliList.

Upang simulahin ang expectation value ng buong circuit, maraming subexperiment ang nabubuo mula sa joint quasiprobability distribution ng mga nabukod na gate at pagkatapos ay isinasagawa sa isa o higit pang mga backend. Ang bilang ng mga sample na kinuha mula sa distribusyon ay kontrolado ng num_samples, at isang pinagsama na coefficient ang ibinibigay para sa bawat natatanging sample. Para sa higit pang impormasyon tungkol sa kung paano kinakalkula ang mga coefficient, sumangguni sa explanatory material.

# Generate the subexperiments and sampling coefficients
subexperiments, coefficients = generate_cutting_experiments(
circuits=qpd_circuit, observables=observables, num_samples=np.inf
)

Para sa paghahambing, nakikita natin na ang mga QPD subexperiment ay magiging mas mababa pagkatapos ng pagputol ng mga malayong gate: Narito ang isang halimbawa ng isang arbitraryong piniling subexperiment na nabuo mula sa QPD circuit. Ang lalim nito ay nabawasan ng higit sa kalahati. Maraming ganitong probabilistic subexperiment ang dapat buuin at suriin upang muling itayo ang expectation value ng mas malalim na circuit.

# Transpile the decomposed circuit to the same layout
transpiled_qpd_circuit = pm.run(subexperiments[100])

print(f"Original circuit depth after transpile: {transpiled_qc.depth()}")
print(
f"QPD subexperiment depth after transpile: {transpiled_qpd_circuit.depth()}"
)
transpiled_qpd_circuit.draw(
"mpl", scale=0.6, style="iqp", idle_wires=False, fold=-1
)
Original circuit depth after transpile: 103
QPD subexperiment depth after transpile: 46

Output of the previous code cell

Sa kabilang banda, ang pagputol ay nagreresulta sa pangangailangan ng karagdagang sampling. Dito ay pinutol natin ang tatlong CNOT gate, na nagreresulta sa sampling overhead na 939^3. Para sa higit pa tungkol sa sampling overhead na dala ng pagputol ng circuit, sumangguni sa Circuit Knitting Toolbox documentation.

print(f"Sampling overhead: {np.prod([basis.overhead for basis in bases])}")
Sampling overhead: 729.0

Hakbang 3: Isagawa gamit ang Qiskit primitives​

Isagawa ang mga target circuit ("subexperiments") gamit ang Sampler Primitive.

  • Input: Mga target circuit
  • Output: Mga quasi-probability distribution
# Transpile the subexperiments to the backend's instruction set architecture (ISA)
isa_subexperiments = pm.run(subexperiments)

# Set up the Qiskit Runtime Sampler primitive. For a fake backend, this will use a local simulator.
sampler = SamplerV2(backend)

# Submit the subexperiments
job = sampler.run(isa_subexperiments)
# Retrieve the results
results = job.result()
print(job.job_id())
czypg1r6rr3g008mgp6g

Hakbang 4: Mag-post-process at ibalik ang resulta sa nais na classical format​

Gamitin ang mga resulta ng subexperiment, mga subobservable, at mga sampling coefficient upang muling itayo ang expectation value ng orihinal na circuit.

Input: Mga quasi-probability distribution Output: Muling itinayong mga expectation value

reconstructed_expvals = reconstruct_expectation_values(
results,
coefficients,
observables,
)
# Reconstruct final expectation value
final_expval = np.dot(reconstructed_expvals, [1] * len(observables))
print("Final reconstructed expectation value")
print(final_expval)
Final reconstructed expectation value
1.0751342773437473
ideal_expvals = [
Statevector(circuit).expectation_value(SparsePauliOp(observable))
for observable in observables
]
print("Ideal expectation value")
print(np.dot(ideal_expvals, [1] * len(observables)).real)
Ideal expectation value
1.2283177520039992

Survey ng tutorial​

Mangyaring sagutin ang maikling survey na ito upang magbigay ng feedback sa tutorial na ito. Ang inyong mga pananaw ay makakatulong sa amin na mapabuti ang aming mga content offering at karanasan ng user.

Link sa survey