Lumaktaw sa pangunahing nilalaman

Gate Cutting para Bawasan ang Circuit Width

Sa notebook na ito, dadaan tayo sa mga hakbang ng isang Qiskit pattern habang ginagamit ang circuit cutting upang bawasan ang bilang ng mga qubit sa isang circuit. Magpuputol tayo ng mga gate upang ma-reconstruct natin ang expectation value ng isang four-qubit circuit gamit lamang ang two-qubit experiments.

Ito ang mga hakbang na gagawin natin:

  • Hakbang 1: I-map ang problema sa quantum circuits at operators:
    • I-map ang hamiltonian sa isang quantum circuit.
  • Hakbang 2: I-optimize para sa target hardware [Ginagamit ang cutting addon]:
    • Putulin ang circuit at observable.
    • I-transpile ang mga subexperiment para sa hardware.
  • Hakbang 3: Isagawa sa target hardware:
    • Patakbuhin ang mga subexperiment na nakuha sa Hakbang 2 gamit ang isang Sampler primitive.
  • Hakbang 4: I-post-process ang mga resulta [Ginagamit ang cutting addon]:
    • Pagsamahin ang mga resulta ng Hakbang 3 upang ma-reconstruct ang expectation value ng observable na pinag-uusapan.

Hakbang 1: Map​

Gumawa ng circuit na puputulin​

# Added by doQumentation β€” required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-cutting qiskit-aer qiskit-ibm-runtime
from qiskit.circuit.library import efficient_su2

qc = efficient_su2(4, entanglement="linear", reps=2)
qc.assign_parameters([0.4] * len(qc.parameters), inplace=True)

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

Quantum circuit diagram

Tukuyin ang isang observable​

from qiskit.quantum_info import SparsePauliOp

observable = SparsePauliOp(["ZZII", "IZZI", "-IIZZ", "XIXI", "ZIZZ", "IXIX"])

Hakbang 2: Optimize​

Paghiwalayin ang circuit at observable ayon sa isang tinukoy na qubit partitioning​

Bawat label sa partition_labels ay tumutugma sa circuit qubit sa parehong index. Ang mga qubit na naghahati ng karaniwang partition label ay pagsasama-samahin, at ang mga non-local gate na sumasaklaw sa higit sa isang partition ay puputulin.

Tandaan: Ang observables kwarg sa partition_problem ay may type na PauliList. Ang mga observable term coefficient at phase ay binabalewala sa panahon ng decomposition ng problema at execution ng mga subexperiment. Maaari silang ilapat muli sa panahon ng reconstruction ng expectation value.

from qiskit_addon_cutting import partition_problem

partitioned_problem = partition_problem(
circuit=qc, partition_labels="AABB", observables=observable.paulis
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
bases = partitioned_problem.bases

I-visualize ang decomposed na problema​

subobservables
{'A': PauliList(['II', 'ZI', 'ZZ', 'XI', 'ZZ', 'IX']),
'B': PauliList(['ZZ', 'IZ', 'II', 'XI', 'ZI', 'IX'])}
subcircuits["A"].draw("mpl", scale=0.8)

Quantum circuit diagram

subcircuits["B"].draw("mpl", scale=0.8)

Quantum circuit diagram

Kalkulahin ang sampling overhead para sa napiling mga cut​

Dito, pinuputol natin ang dalawang CNOT gate, na nagreresulta sa sampling overhead na 929^2.

Para sa higit pa tungkol sa sampling overhead na nakukuha mula sa circuit cutting, sumangguni sa explanatory material.

import numpy as np

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

Bumuo ng mga subexperiment na patatakbuhin sa backend​

Ang generate_cutting_experiments ay tumatanggap ng circuits/observables args bilang mga dictionary na nagma-map sa qubit partition labels patungo sa mga kaukulang subcircuit/subobservables.

Upang i-simulate ang expectation value ng full-sized na circuit, maraming subexperiment ang nabubuo mula sa joint quasiprobability distribution ng mga decomposed na gate at pagkatapos ay isinasagawa sa isa o higit pang backend. Ang bilang ng mga sample na kinukuha mula sa distribution ay kinokontrol ng num_samples, at isang combined coefficient ang ibinibigay para sa bawat unique sample. Para sa karagdagang impormasyon kung paano kinakalkula ang mga coefficient, sumangguni sa explanatory material.

from qiskit_addon_cutting import generate_cutting_experiments

subexperiments, coefficients = generate_cutting_experiments(
circuits=subcircuits, observables=subobservables, num_samples=np.inf
)

Pumili ng backend​

Dito ay gumagamit tayo ng fake backend, na magreresulta sa Qiskit Runtime na tumatakbo sa local mode (i.e., sa isang local simulator).

from qiskit_ibm_runtime.fake_provider import FakeManilaV2

backend = FakeManilaV2()

Ihanda ang mga subexperiment para sa backend​

Kailangan nating i-transpile ang mga circuit gamit ang ating backend bilang target bago isumite ang mga ito sa Qiskit Runtime.

from qiskit.transpiler import generate_preset_pass_manager

# Transpile the subexperiments to ISA circuits
pass_manager = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_subexperiments = {
label: pass_manager.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}

Hakbang 3: Execute​

Patakbuhin ang mga subexperiment gamit ang Qiskit Runtime Sampler primitive​

from qiskit_ibm_runtime import SamplerV2, Batch

# Submit each partition's subexperiments to the Qiskit Runtime Sampler
# primitive, in a single batch so that the jobs will run back-to-back.
with Batch(backend=backend) as batch:
sampler = SamplerV2(mode=batch)
jobs = {
label: sampler.run(subsystem_subexpts, shots=2**12)
for label, subsystem_subexpts in isa_subexperiments.items()
}
/home/garrison/Qiskit/qiskit-ibm-runtime/qiskit_ibm_runtime/session.py:157: UserWarning: Session is not supported in local testing mode or when using a simulator.
warnings.warn(
# Retrieve results
results = {label: job.result() for label, job in jobs.items()}

Hakbang 4: Post-process​

I-reconstruct ang expectation value​

I-reconstruct ang expectation values para sa bawat observable term at pagsamahin ang mga ito upang ma-reconstruct ang expectation value para sa orihinal na observable.

from qiskit_addon_cutting import reconstruct_expectation_values

# Get expectation values for each observable term
reconstructed_expval_terms = reconstruct_expectation_values(
results,
coefficients,
subobservables,
)

# Reconstruct final expectation value
reconstructed_expval = np.dot(reconstructed_expval_terms, observable.coeffs)

Ikumpara ang reconstructed expectation value sa exact expectation value mula sa orihinal na circuit at observable​

from qiskit_aer.primitives import EstimatorV2

estimator = EstimatorV2()
exact_expval = estimator.run([(qc, observable)]).result()[0].data.evs
print(f"Reconstructed expectation value: {np.real(np.round(reconstructed_expval, 8))}")
print(f"Exact expectation value: {np.round(exact_expval, 8)}")
print(f"Error in estimation: {np.real(np.round(reconstructed_expval-exact_expval, 8))}")
print(
f"Relative error in estimation: {np.real(np.round((reconstructed_expval-exact_expval) / exact_expval, 8))}"
)
Reconstructed expectation value: 0.6991539
Exact expectation value: 0.56254612
Error in estimation: 0.13660778
Relative error in estimation: 0.24283836