Lumaktaw sa pangunahing nilalaman
Ang proyektong ito ay nasa beta. Nakakita ng bug? Mag-bukas ng GitHub issue. May tanong o ideya? Magtanong sa Discussions — gusto naming marinig ang iyong feedback!
Gaano kaganda ang kalidad ng pagsasalin sa pahinang ito?

I-truncate ang mga Pauli term habang nagba-backpropagate

Ipinapaliwanag ng gabay na ito kung paano i-configure ang mekanismo ng Pauli term truncation na ibinibigay ng module na qiskit_addon_obp.utils.truncating.

Magagamit ang operator backpropagation (OBP) para bawasan ang depth ng mga quantum circuit kapalit ng mas masalimuot na observable. Para makakuha ng makabuluhang resulta mula sa OBP, karaniwang kailangang mag-truncate ng mga term mula sa observable para hindi ito lumaki nang sobra. Isang paraan para makapag-backpropagate nang mas malalim sa circuit habang pinipigilang lumaki nang sobra ang operator ay ang pag-truncate ng mga term na maliit ang coefficient, sa halip na idagdag ang mga ito sa operator. Ang pag-truncate ng mga term ay maaaring magresulta sa mas kaunting quantum circuit na kailangang i-execute, ngunit nagdudulot ito ng kaunting error sa huling kalkulasyon ng expectation value, na proporsyonal sa laki ng mga coefficient ng mga na-truncate na term.

Ang method na backpropagate ay tumatanggap ng opsyonal na TruncationErrorBudget, na nagko-configure ng pag-truncate ng mga low-weight na Pauli term para sa bawat observable pagkatapos ng matagumpay na backpropagation ng bawat slice. Ang dami ng mga term na na-truncate ay nakadepende sa iba't ibang configuration parameter na tinukoy ng user. Sa ngayon, iisang truncation strategy lang ang available - ang method na truncate_binary_search. Kapag binigyan ng isang observable at ilang budget, magsasagawa ito ng binary search sa mga Pauli term at coefficient sa loob ng observable na iyon para hanapin ang pinakamainam na threshold, such that the sum of the truncated coefficients is maximal but lower than the budget.

Tandaan: Bilang default, ginagamit ang L1 norm para i-evaluate at i-bound ang truncation error; gayunpaman, pinapayagan ng setting na p_norm na tukuyin ang Lp-norm na gagamitin. Para sa higit pang impormasyon kung paano gamitin ang setting na iyon, tingnan ang gabay na Use different Lp-norms for Pauli term truncation. Ilalarawan ng mga sumusunod na halimbawa ang iba't ibang paraan ng pagbuo ng TruncationErrorBudget gamit ang kasamang function na setup_budget.

Gumawa ng halimbawang circuit​

Ginagamit ng gabay na ito ang mga sumusunod na circuit slice:

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"matplotlib": "matplotlib", "qiskit": "qiskit", "qiskit_addon_obp": "qiskit-addon-obp", "qiskit_addon_utils": "qiskit-addon-utils", "rustworkx": "rustworkx"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import rustworkx.generators
from qiskit.synthesis import LieTrotter
from qiskit_addon_utils.problem_generators import (
PauliOrderStrategy,
generate_time_evolution_circuit,
generate_xyz_hamiltonian,
)
from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types

# Generate a linear chain of 10 qubits
linear_chain = rustworkx.generators.path_graph(10)

# Use an arbitrary XY model
hamiltonian = generate_xyz_hamiltonian(
linear_chain,
coupling_constants=(0.05, 0.02, 0.0),
ext_magnetic_field=(0.02, 0.08, 0.0),
pauli_order_strategy=PauliOrderStrategy.InteractionThenColor,
)
# Evolve for some time
circuit = generate_time_evolution_circuit(
hamiltonian, synthesis=LieTrotter(reps=3), time=2.0
)
# slice the circuit by gate type
slices = slice_by_gate_types(circuit)

# for visualization purposes, recombine the slices with barriers between them and draw the resulting circuit
combine_slices(slices, include_barriers=True).draw("mpl", fold=50, scale=0.6)

Output of the previous code cell

Titingnan natin ang isang simpleng observable:

from qiskit.quantum_info import SparsePauliOp

obs = SparsePauliOp("IIIIIZIIII")

Ang pinakasimpleng kaso: isang nakapirming truncation budget para sa bawat slice​

Ang magagamit na budget para sa pag-truncate ng mga Pauli term ay maaaring mag-iba sa bawat hakbang ng backpropagation. Para maintindihan kung paano ito gumagana, tingnan muna natin ang pinakasimpleng kaso ng nakapirming truncation budget na itinakda ng user.

Ang pinakadiretsong paraan para tukuyin ang truncation budget ay ang paggamit ng argument na max_error_per_slice. Sa katunayan, ito ang ginagawa sa tutorial na Reducing depth of circuits with operator backpropagation. Ang pagtatakda ng max_error_per_slice sa isang float ay nagreresulta sa bawat slice na binibigyan ng budget na katumbas ng halagang iyon. Sa halimbawa sa ibaba, itinakda natin ang halagang ito sa 0.001 na nagagarantiya ng implicit na truncation error na hindi hihigit sa 0.018, kung na-backpropagate ang lahat ng 18 slice.

Tandaan na ang anumang error budget na natitira matapos mag-backpropagate ng isang slice at mag-truncate ng mga term na maliit ang coefficient ay palaging idaragdag sa error budget ng susunod na slice.

from qiskit_addon_obp.utils.truncating import setup_budget

truncation_error_budget = setup_budget(max_error_per_slice=0.001)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.001], max_error_total=inf, p_norm=1)
from qiskit_addon_obp import backpropagate
from qiskit_addon_obp.utils.simplify import OperatorBudget

op_budget = OperatorBudget(max_qwc_groups=10)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 11 circuit slices.
New observable contains 29 terms and 10 commuting groups.

Susunod, gagamitin natin ang instance ng OBPMetadata at ang mga tool na ibinibigay ng module na visualization para i-visualize ang proseso ng backpropagation.

  • Ang plot sa itaas-kaliwa ay nagpapakitang may sapat tayong budget para magsimulang mag-truncate ng mga observable term pagkatapos i-backpropagate ang ikatlong slice. Simula sa ikatlong slice, alam nating may na-truncate tayong kahit isang term mula sa bawat slice na ibinabackpropagate natin dahil may truncation error tayong nagagawa pagkatapos ng bawat slice.

  • Ang plot sa itaas-kanan ay nagpapakitang lumalaki ang error budget hanggang .003 para sa ikatlong slice. Nakikita natin ang matarik na pagbaba sa natitirang budget, na nangangahulugang may mga term na na-truncate mula sa observable. Ito ay tugma sa nahinuha natin mula sa plot sa itaas-kaliwa.

  • Ang plot sa ibaba-kaliwa ay nagpapakitang habang nagta-truncate tayo ng mga term mula sa observable, patuloy na tumataas ang kabuuang naipon nating error. Kinukumpirma rin ng graph na ito na walang na-truncate na term hanggang matapos ma-backpropagate ang ikatlong slice.

  • Ang plot sa ibaba-kanan ay nagpapakitang ang bilang ng mga commuting Pauli group sa observable natin ay lumaki na hanggang sa tinukoy na limitasyon na 10. Ipinapakita rin ng plot na ito kung paanong ang pag-backpropagate ng isa pang layer ay magiging dahilan para lumampas ang observable natin sa tinukoy na bound, gaya ng makikita sa pagtatagpo ng itim at pulang linya.

Tandaan na sa lahat ng mga plot na ito, ang x-axis ay nag-eenumerate ng mga na-backpropagate na slice, pero dahil ang OBP ay gumagana sa dulo ng circuit, ang slice 1 ang pinakahuling slice, ang slice 2 ang nauuna rito, at iba pa.

from matplotlib import pyplot as plt
from qiskit_addon_obp.utils.visualization import (
plot_accumulated_error,
plot_left_over_error_budget,
plot_num_qwc_groups,
plot_slice_errors,
)

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Tukuyin nang tahasan ang slice budget​

Kung alam mo kung paano magtakda ng budget sa bawat slice para ma-optimize ang performance ng backpropagation, maaaring gusto mong tahasang magtakda ng budget para sa bawat slice. Para sa layunin ng demonstrasyon, bibigyan natin ang unang tatlong slice ng zero na budget at gagamit tayo ng budget na .001 kada slice para sa natitirang mga slice.

# Zero out the first 3 slices' budgets
max_error_per_slice = [0.0] * 3 + [0.001] * (len(slices) - 3)

truncation_error_budget = setup_budget(
max_error_per_slice=max_error_per_slice
)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.0, 0.0, 0.0, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001], max_error_total=inf, p_norm=1)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 11 circuit slices.
New observable contains 32 terms and 10 commuting groups.

Ang pag-alis ng budget sa unang tatlong layer ay nagresulta sa walang na-truncate na term hanggang matapos ang ikaapat na layer, gaya ng makukumpirma sa tatlo sa mga plot na ito. Maaaring medyo nakakagulat na kahit walang natirang budget na ipinasa sa ikaapat na slice, may term pa ring na-truncate gamit ang itinalagang budget na .001. Halata ito sa plot sa itaas-kaliwa, pero makikita rin sa plot sa itaas-kanan, dahil pumapatag ang kurba ng natirang budget sa pagitan ng ikatlo at ikaapat na slice. Isa pang kapansin-pansing detalye ay may na-truncate na kahit isang term mula sa puntong ito, tulad ng sa nakaraang halimbawa.

Ang pangunahing aral ay kahit mas kaunting truncation error ang nagawa natin sa ikalawang halimbawa dahil sa pag-zero ng budget ng ilang slice, nagawa pa rin nating i-backpropagate ang parehong bilang ng mga slice, at ang observable natin ay may parehong bilang ng mga commuting Pauli group. Makukumpirma nating mas maliit ang bound sa error natin sa ikalawang halimbawa sa pagsusuri ng plot sa ibaba-kaliwa.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Tukuyin ang budget nang paikot​

Kung may circuit kang may paulit-ulit na pattern, tulad ng Trotter circuit, maaaring gusto mong magtakda ng budget para sa paulit-ulit na subset ng mga slice na iyon at gamitin ang budget na iyon sa lahat ng sumusunod na pag-uulit ng mga slice na iyon.

Mas konkreto, ang halimbawang circuit na ginagamit natin ay may anim na slice na inuulit nang tatlong beses, para sa kabuuang 18 slice. Basta-basta tayong magtatalaga ng zero na budget sa mga single-qubit at RYY layer, at .003 na budget sa bawat isa sa mga RXX layer. Makikita natin kung paanong ang pagtukoy ng budget bilang sequence na may haba na 6 ay nagiging dahilan para ma-apply ang budget sa lahat ng 18 slice nang paikot.

Muli, tandaan na ang mga slice ay bina-backpropagate nang pabaliktad (ibig sabihin, simula sa dulo). Kaya, ang unang entry sa paikot nating budget ay talagang ginagamit para sa huling slice, ang ikalawang entry para sa slice na nauuna rito, at iba pa.

# Specify a length-6 per-slice budget.
# This will be cycled over three times to be applied to the 18 slices
max_error_per_slice = [0.0] * 4 + [0.003] * 2

truncation_error_budget = setup_budget(
max_error_per_slice=max_error_per_slice
)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.0, 0.0, 0.0, 0.0, 0.003, 0.003], max_error_total=inf, p_norm=1)
op_budget = OperatorBudget(max_qwc_groups=20)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 13 circuit slices.
New observable contains 49 terms and 14 commuting groups.

Gaya ng makikita sa mga larawan sa itaas-kaliwa at ibaba-kaliwa, walang truncation na ginawa sa unang apat na slice dahil wala silang itinalagang error budget. Ang mga slice lima at anim ay nagkaroon ng ilang na-truncate na term nang magkaroon ng budget.

Gaya ng makikita sa larawan sa itaas-kaliwa, medyo malaking error ang naganap pagkatapos i-backpropagate ang slice pito, kahit na walang budget na itinalaga sa slice na iyon. Ito ay dahil humigit-kumulang .002 lang sa kabuuang .006 na budget na itinalaga sa mga slice lima at anim ang nagamit, kaya ang natira ay ipinasa sa slice pito at halos nagastos, gaya ng makikita sa larawan sa itaas-kanan.

Ipinapakita ng mga larawan sa itaas-kaliwa at itaas-kanan na ang maliit na natirang budget ay nauubos sa pagitan ng mga slice 8-10, at may bagong budget na magagamit sa slice 11, gaya ng inaasahan. Ipinapakita ng mga larawan sa itaas-kaliwa, itaas-kanan, at ibaba-kaliwa ang paikot na pag-uugali ng argument na max_error_per_slice kapag mas maikli ang haba nito kaysa sa bilang ng mga slice. Magpapatuloy sana ang paikot na pag-uugaling ito sa lahat ng slice, pero naabot ang stopping criteria na max_qwc_groups matapos mag-backpropagate ng 13 slice, gaya ng makikita sa larawan sa ibaba-kanan.

Kapansin-pansin din na ang bilang ng mga Pauli group ay talagang bumababa pagkatapos magkaroon ng ikalawang round ng budget sa slice 11. Ito ay dahil may mga group na maliit ang coefficient na hindi ma-truncate hangga't wala pang mas maraming budget pagkatapos i-backpropagate ang slice 11, kaya naipon ang mga ito sa observable sa loob ng ilang iteration. Itinatampok din ng kasong ito na ang max_qwc_groups ay dapat lampasan para matapos ang algorithm.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Limitahan ang kabuuang error​

Bukod sa pagtukoy ng error budget kada slice, maaari ring tukuyin ang pinakamataas na dami ng error na maaaring idulot ng truncation. Kapag naabot na ang limitasyong iyon, wala nang gagawing truncation; gayunpaman, magpapatuloy ang backpropagation hanggang sa maging masyadong malaki ang observable at matugunan ang isa sa mga stopping criteria.

Susunod, muli nating pinapatakbo ang eksperimento sa itaas, na nagtatakda ng limitasyon sa max_error_total para maubos ang error budget pagkatapos i-backpropagate ang slice pito.

# Specify a length-6 per-slice budget.
# This will be cycled over 3 times to be applied to the 18 slices
max_error_per_slice = [0.0] * 4 + [0.003] * 2

truncation_error_budget = setup_budget(
max_error_per_slice=max_error_per_slice, max_error_total=0.006
)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.0, 0.0, 0.0, 0.0, 0.003, 0.003], max_error_total=0.006, p_norm=1)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 10 circuit slices.
New observable contains 67 terms and 20 commuting groups.

Gaya ng inaasahan, ang truncation error natin ay tumitigil sa .006 (chart sa ibaba-kaliwa). Kapansin-pansin na sa takbong ito ay hindi natin nagawang i-backpropagate ang slice 11. Ito ay dahil wala tayong sapat na budget para mag-truncate ng mga term at lumampas ang bilang ng mga commuting Pauli group sa limitasyong 20, gaya ng makikita sa larawan sa ibaba-kanan.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Maaaring gusto lang limitahan ang kabuuang budget gamit ang max_error_total nang hindi tinutukoy ang max_error_per_slice.

truncation_error_budget = setup_budget(max_error_total=0.018)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.018], max_error_total=0.018, p_norm=1)

Maaaring medyo nakakagulat ang output ng cell sa itaas dahil ang per_slice_budget ay itinakda sa max_error_total. Ipinapahiwatig nito na ang buong magagamit na budget ay uubusin nang greedy. Maaari mo itong isipin ganito: ang buong budget ay magagamit ng bawat slice (dahil nag-loop tayo sa per_slice_budget). Pero ang anumang budget na nagamit na ay ibabawas sa budget na magagamit sa puntong iyon ng algorithm.

op_budget = OperatorBudget(max_qwc_groups=10)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 9 circuit slices.
New observable contains 25 terms and 9 commuting groups.

Ipinapakita ng larawan sa itaas-kanan kung paanong ang buong .018 na error budget ay ibinibigay sa unang slice. Walang truncation na ginagawa hanggang sa ikatlong slice, kaya nananatiling pare-pareho ang natirang budget. Patuloy na bumababa ang budget, dahil ang buong budget ay ibinibigay sa bawat na-backpropagate na slice hanggang maubos ito.

Kapansin-pansin na ang eksperimentong ito ay nagbunga ng dalawang mas kaunting na-backpropagate na slice kumpara sa unang eksperimento sa notebook na ito, na halos magkapareho. Ipinapakita nito na para sa ilang problema, maaaring pinakamainam ang pantay na pamamahagi ng budget. Para sa ibang problema, ang pagpapahintulot sa mga slice na gastusin nang greedy ang buong budget ay maaaring magbunga ng mas mahusay na performance.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Limitahan ang bilang ng mga na-backpropagate na slice at ang kabuuang error nang magkasama​

Kung ayaw mong ipamahagi ang error budget mo sa buong circuit pero ayaw mo ring gastusin ito nang greedy, maaari mong tukuyin ang bilang ng mga slice na balak mong i-backpropagate (num_slices), kasama ang kabuuang error budget (max_error_total). Ipapamahagi nito nang pantay ang error budget (ayon sa p_norm) sa mga input slice.

Dito, lilimitahan natin ang bilang ng mga slice na maaari nating i-backpropagate sa 12, at pananatilihin natin ang parehong kabuuang error budget.

num_slices = 12

truncation_error_budget = setup_budget(
max_error_total=0.018, num_slices=num_slices, p_norm=1
)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.0014999999999999998], max_error_total=0.018, p_norm=1)

Ngayon, susubukan nating i-backpropagate ang 12 slice na pinaglaanan natin ng budget sa nakaraang hakbang. Ginagawa natin ito sa pamamagitan ng pagpapasa lang ng huling 12 slice sa ating circuit. Sa p_norm=1, ang bawat isa sa 12 slice ay may magagamit na budget na 0.018 / num_slices = 0.0015.

bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices[-num_slices:],
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)

Dahil nagpasa tayo ng subset ng ating mga slice (sa code na slices[-num_slices:]) sa backpropagate, kailangan nating pagsamahin ang mga slice na natira pagkatapos ng backpropagation sa mga slice na hindi kailanman ipinadala para sa backpropagation (sa code na slices[:-num_slices]).

Kapag naipagsama na natin ang lahat ng natitirang slice, magagamit natin ang combine_slices para buuin ang QuantumCircuit na may nabawasang depth. Susunod, susuriin natin kung ilang slice ang na-backpropagate kumpara sa kung gaano kalaki ang naging observable natin.

# Recombine the slices remaining after backprop with the rest of the original circuit
reduced_circuit = combine_slices(slices[:-num_slices] + remaining_slices)

print(f"Backpropagated {num_slices - len(remaining_slices)} circuit slices.")
print(
f"New observable contains {len(bp_obs)} terms and {len(bp_obs.group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 12 circuit slices.
New observable contains 29 terms and 9 commuting groups.

Ipinapakita ng mga plot na matagumpay naming na-backpropagate ang lahat ng 12 slice habang pinapanatili ang aming observable sa ilalim ng 10 commuting Pauli group. Makikita rin natin na ang paggamit ng num_slices kasama ang max_error_total ay nagreresulta sa distribusyon ng mga budget sa mga slice, at ang hindi nagamit na budget ay muling ipinapasa sa susunod na slice. Pinakamalinaw ito sa plot sa kanang itaas, dahil ang budget ay parehong nagagamit at napupunan muli sa buong backpropagation.

Kapansin-pansin na ang paraang ito ng pamamahagi ng error ang nagbigay ng pinakamahusay na resulta (mas maraming na-backpropagate na slice), kumpara sa unang eksperimento sa notebook na ito at sa halimbawang kasunod lang bago nito. Lahat ng mga halimbawang ito ay nagtalaga ng .018 na error budget, pero iba-iba ang naging performance ng backpropagation depende sa kung paano ipinamahagi ang budget na iyon.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell

Magtrabaho gamit ang maraming observable​

Ang method na qiskit_addon_obp.backpropagate ay nagpapahintulot na magpasa ng sequence ng mga observable. Pinapasimple nito ang workflow kapag maraming target na observable.

Tahasan naming binabanggit ito rito para ituro kung paano hinahawakan ng truncation strategy ang ganitong kaso. Para sa halimbawang ito, magdadagdag tayo ng isa pang observable sa ginagamit natin hanggang ngayon:

obs = [SparsePauliOp("IIIIIZIIII"), SparsePauliOp("IIIIIXIIII")]

Panghuli, uulitin natin ang unang eksperimento mula sa tutorial na ito, pero may dalawang observable na paglalagyan ng backpropagation ng circuit.

Sa halimbawang ito, hindi nito naaapektuhan ang bilang ng mga slice na na-backpropagate. Gayunpaman, makikita natin na ang dalawang observable ay nagresulta sa magkaibang bilang ng mga Pauli term at commuting group.

truncation_error_budget = setup_budget(max_error_per_slice=0.001)
print(truncation_error_budget)
TruncationErrorBudget(per_slice_budget=[0.001], max_error_total=inf, p_norm=1)
bp_obs, remaining_slices, metadata = backpropagate(
obs,
slices,
operator_budget=op_budget,
truncation_error_budget=truncation_error_budget,
)
reduced_circuit = combine_slices(remaining_slices)
print(f"Backpropagated {len(slices) - len(remaining_slices)} circuit slices.")
print(
f"The new first observable contains {len(bp_obs[0])} terms and {len(bp_obs[0].group_commuting(qubit_wise=True))} commuting groups."
)
print(
f"The new second observable contains {len(bp_obs[1])} terms and {len(bp_obs[1].group_commuting(qubit_wise=True))} commuting groups."
)
Backpropagated 11 circuit slices.
The new first observable contains 29 terms and 10 commuting groups.
The new second observable contains 23 terms and 8 commuting groups.

Tinutulungan ng mga plot sa ibaba na ilarawan kung paano hinahawakan ng backpropagation algorithm ang maraming observable.

Una, ipinapakita ng mga plot sa kaliwang itaas, kanang itaas, at kaliwang ibaba na ang budget para sa pag-truncate ng mga term ay itinatakda nang hiwalay para sa bawat observable. Sa madaling salita, parehong may kakayahan ang dalawang observable na mag-truncate ng mga term sa pag-aakalang may error na 0.001 bawat na-backpropagate na slice. Dahil sa magkaibang katangian ng mga observable, nagreresulta ito sa magkaibang paggamit ng budget. Sa halimbawang ito, malaki ang overlap nila, na hindi laging nangyayari.

Ipinapakita ng plot sa kanang ibaba na isinasaalang-alang ng max_qwc_groups ang lahat ng observable. Ibig sabihin, pinagsasama-sama ang mga term ng lahat ng observable para makarating sa iisang huling bilang ng qubit-wise commuting group, na ikinukumpara sa max_qwc_paulis. Ganito rin ang ginagawa para sa threshold na max_paulis (hindi tinalakay sa notebook na ito), na nagpapahintulot na magtakda ng limitasyon sa bilang ng mga Pauli term sa lahat ng observable.

fig, axes = plt.subplots(2, 2, figsize=(20, 10))
plot_slice_errors(metadata, axes[(0, 0)])
plot_left_over_error_budget(metadata, axes[(0, 1)])
plot_accumulated_error(metadata, axes[(1, 0)])
plot_num_qwc_groups(metadata, axes[(1, 1)])

Output of the previous code cell