Mga multi-product formula para mabawasan ang Trotter error
Tinatayang paggamit ng QPU: Apat na minuto sa isang Heron r2 processor (TANDAAN: Tantiya lamang ito. Maaaring mag-iba ang inyong runtime.)
Pangkalahatang-ideya
Ipinapakita ng tutorial na ito kung paano gamitin ang isang Multi-Product Formula (MPF) upang makamit ang mas mababang Trotter error sa ating observable kumpara sa error na maidudulot ng pinakamalalim na Trotter circuit na ating isasagawa. Binabawasan ng mga MPF ang Trotter error ng Hamiltonian dynamics sa pamamagitan ng may-timbang na kombinasyon ng ilang circuit execution. Isaalang-alang ang gawain ng paghahanap ng mga inaasahang halaga ng observable para sa quantum state na may Hamiltonian na . Maaaring gumamit ng mga Product Formula (PF) upang tantiyahin ang time-evolution na sa pamamagitan ng sumusunod:
- Isulat ang Hamiltonian na bilang kung saan ang ay mga Hermitian operator na ang bawat katumbas na unitary ay maaaring mahusay na maipatupad sa isang quantum device.
- Tantiyahin ang mga terminong na hindi nag-commute sa isa't isa.
Kaya naman, ang first-order PF (Lie-Trotter formula) ay:
na may quadratic error term na . Maaari ring gumamit ng higher-order PF (Lie-Trotter-Suzuki formula), na mas mabilis na magkakalapit, at tinukoy nang rekursibo bilang:
kung saan ang ay ang order ng symmetric PF at . Para sa matagalang time-evolution, maaaring hatiin ang time interval na sa na interval, na tinatawag na mga Trotter step, na may tagal na at tantiyahin ang time-evolution sa bawat interval gamit ang order product formula na . Kaya naman, ang PF ng order na para sa time-evolution operator sa Trotter step ay:
kung saan ang error term ay bumababa kasabay ng bilang ng mga Trotter step na at ng order na ng PF.
Kapag may ibinigay na integer na at isang product formula na , ang tinantyang time-evolved state na ay maaaring makuha mula sa sa pamamagitan ng pag-apply ng ulit ng product formula na .
Ang ay isang tantiya para sa na may Trotter approximation error na ||. Kung isasaalang-alang natin ang isang linear na kombinasyon ng mga Trotter approximation ng :
kung saan ang ay ang ating mga weighting coefficient, ang ay ang density matrix na katumbas ng pure state na nakuha sa pamamagitan ng pag-evolve ng initial state gamit ang product formula, , na nagsasangkot ng Trotter step, at ang ay nag-i-index ng bilang ng mga PF na bumubuo sa MPF. Lahat ng termino sa ay gumagamit ng parehong product formula na bilang basehan. Ang layunin ay mapabuti ang || sa pamamagitan ng paghahanap ng na may mas mababang .
- Hindi kailangang maging pisikal na estado ang dahil hindi kailangang positibo ang . Ang layunin dito ay mabawasan ang error sa inaasahang halaga ng mga observable at hindi upang makahanap ng pisikal na kapalit para sa .
- Tinutukoy ng ang parehong circuit depth at antas ng Trotter approximation. Ang mas maliit na halaga ng ay nagbubunga ng mas maikling mga circuit, na nagdudulot ng mas kaunting circuit error ngunit magiging mas hindi tumpak na tantiya ng nais na estado.
Ang susi dito ay ang natitirang Trotter error na ibinibigay ng ay mas maliit kaysa sa Trotter error na makukuha kung gagamitin lamang ang pinakamataas na halaga ng .
Maaaring tingnan ang kapaki-pakinabang nito mula sa dalawang perspektibo:
- Para sa isang nakapirming badyet ng Trotter step na maisasagawa, makakakuha ng mga resulta na may mas maliit na Trotter error sa kabuuan.
- Kung may target na bilang ng Trotter step na masyadong malaki upang maisagawa, maaaring gamitin ang MPF upang makahanap ng isang koleksyon ng mas mababang-lalim na mga circuit na nagbubunga ng katulad na Trotter error.
Mga Kinakailangan
Bago simulan ang tutorial na ito, tiyakin na naka-install ang mga sumusunod:
- Qiskit SDK v1.0 o mas bago, na may suporta sa visualization
- Qiskit Runtime v0.22 o mas bago (
pip install qiskit-ibm-runtime) - MPF Qiskit addons (
pip install qiskit_addon_mpf) - Qiskit addons utils (
pip install qiskit_addon_utils) - Quimb library (
pip install quimb) - Qiskit Quimb library (
pip install qiskit-quimb) - Numpy v0.21 para sa compatibility sa iba't ibang package (
pip install numpy==0.21)
Bahagi I. Maliit na halimbawa
Suriin ang katatagan ng MPF
Walang malinaw na limitasyon sa pagpili ng bilang ng mga Trotter step na na bumubuo sa MPF state na . Gayunpaman, dapat itong maingat na piliin upang maiwasan ang kawalang-tatag sa mga inaasahang halagang kinakalkula mula sa . Ang isang magandang pangkalahatang tuntunin ay itakda ang pinakamaliit na Trotter step na upang . Kung nais ninyong matuto pa tungkol dito at kung paano pipiliin ang inyong iba pang na halaga, sumangguni sa gabay na How to choose the Trotter steps for an MPF.
Sa halimbawa sa ibaba, sinusuri natin ang katatagan ng MPF solution sa pamamagitan ng pagkalkula ng inaasahang halaga ng magnetisasyon para sa isang hanay ng mga oras gamit ang iba't ibang time-evolved state. Partikular, inihahambing natin ang mga inaasahang halagang kinakalkula mula sa bawat isa sa mga tinantyang time-evolution na isinagawa gamit ang katumbas na Trotter step at ang iba't ibang MPF model (static at dynamic na coefficient) kasama ang eksaktong halaga ng time-evolved observable. Una, tukuyin natin ang mga parameter para sa mga Trotter formula at ang mga oras ng evolution.
# Added by doQumentation — installs packages not in the Binder environment
%pip install -q qiskit-addon-mpf
import numpy as np
mpf_trotter_steps = [1, 2, 4]
order = 2
symmetric = False
trotter_times = np.arange(0.5, 1.55, 0.1)
exact_evolution_times = np.arange(trotter_times[0], 1.55, 0.05)
Para sa halimbawang ito, gagamitin natin ang Neel state bilang initial state na at ang Heisenberg model sa isang linya ng 10 site para sa Hamiltonian na namamahala sa time-evolution
kung saan ang ay ang coupling strength para sa mga pinakamalapit na gilid.
from qiskit.transpiler import CouplingMap
from rustworkx.visualization import graphviz_draw
from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian
import numpy as np
L = 10
# Generate some coupling map to use for this example
coupling_map = CouplingMap.from_line(L, bidirectional=False)
graphviz_draw(coupling_map.graph, method="circo")
# Get a qubit operator describing the Heisenberg field model
hamiltonian = generate_xyz_hamiltonian(
coupling_map,
coupling_constants=(1.0, 1.0, 1.0),
ext_magnetic_field=(0.0, 0.0, 0.0),
)
print(hamiltonian)
SparsePauliOp(['IIIIIIIXXI', 'IIIIIIIYYI', 'IIIIIIIZZI', 'IIIIIXXIII', 'IIIIIYYIII', 'IIIIIZZIII', 'IIIXXIIIII', 'IIIYYIIIII', 'IIIZZIIIII', 'IXXIIIIIII', 'IYYIIIIIII', 'IZZIIIIIII', 'IIIIIIIIXX', 'IIIIIIIIYY', 'IIIIIIIIZZ', 'IIIIIIXXII', 'IIIIIIYYII', 'IIIIIIZZII', 'IIIIXXIIII', 'IIIIYYIIII', 'IIIIZZIIII', 'IIXXIIIIII', 'IIYYIIIIII', 'IIZZIIIIII', 'XXIIIIIIII', 'YYIIIIIIII', 'ZZIIIIIIII'],
coeffs=[1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j,
1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j])
Ang observable na ating susukat ay ang magnetisasyon sa isang pares ng qubit sa gitna ng chain.
from qiskit.quantum_info import SparsePauliOp
observable = SparsePauliOp.from_sparse_list(
[("ZZ", (L // 2 - 1, L // 2), 1.0)], num_qubits=L
)
print(observable)
SparsePauliOp(['IIIIZZIIII'],
coeffs=[1.+0.j])
Nagtatakda tayo ng transpiler pass upang kolektahin ang mga XX at YY rotation sa circuit bilang isang XX+YY gate. Papayagan nito tayong samantalahin ang mga katangian ng spin conservation ng TeNPy sa panahon ng MPO computation, na lubos na nagpapabilis ng pagkalkula.
from qiskit.circuit.library import XXPlusYYGate
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes.optimization.collect_and_collapse import (
CollectAndCollapse,
collect_using_filter_function,
collapse_to_operation,
)
from functools import partial
def filter_function(node):
return node.op.name in {"rxx", "ryy"}
collect_function = partial(
collect_using_filter_function,
filter_function=filter_function,
split_blocks=True,
min_block_size=1,
)
def collapse_to_xx_plus_yy(block):
param = 0.0
for node in block.data:
param += node.operation.params[0]
return XXPlusYYGate(param)
collapse_function = partial(
collapse_to_operation,
collapse_function=collapse_to_xx_plus_yy,
)
pm = PassManager()
pm.append(CollectAndCollapse(collect_function, collapse_function))
Pagkatapos ay lilikha tayo ng mga circuit na nagpapatupad ng mga tinantyang Trotter time-evolution.
from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
)
from qiskit import QuantumCircuit
# Initial Neel state preparation
initial_state_circ = QuantumCircuit(L)
initial_state_circ.x([i for i in range(L) if i % 2 != 0])
all_circs = []
for total_time in trotter_times:
mpf_trotter_circs = [
generate_time_evolution_circuit(
hamiltonian,
time=total_time,
synthesis=SuzukiTrotter(reps=num_steps, order=order),
)
for num_steps in mpf_trotter_steps
]
mpf_trotter_circs = pm.run(
mpf_trotter_circs
) # Collect XX and YY into XX + YY
mpf_circuits = [
initial_state_circ.compose(circuit) for circuit in mpf_trotter_circs
]
all_circs.append(mpf_circuits)
mpf_circuits[-1].draw("mpl", fold=-1)

Susunod, kinakalkula natin ang mga time-evolved na inaasahang halaga mula sa mga Trotter circuit.
from copy import deepcopy
from qiskit_aer import AerSimulator
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
aer_sim = AerSimulator()
estimator = Estimator(mode=aer_sim)
mpf_expvals_all_times, mpf_stds_all_times = [], []
for t, mpf_circuits in zip(trotter_times, all_circs):
mpf_expvals = []
circuits = [deepcopy(circuit) for circuit in mpf_circuits]
pm_sim = generate_preset_pass_manager(
backend=aer_sim, optimization_level=3
)
isa_circuits = pm_sim.run(circuits)
result = estimator.run(
[(circuit, observable) for circuit in isa_circuits], precision=0.005
).result()
mpf_expvals = [res.data.evs for res in result]
mpf_stds = [res.data.stds for res in result]
mpf_expvals_all_times.append(mpf_expvals)
mpf_stds_all_times.append(mpf_stds)
Kinakalkula rin natin ang mga eksaktong inaasahang halaga para sa paghahambing.
from scipy.linalg import expm
from qiskit.quantum_info import Statevector
exact_expvals = []
for t in exact_evolution_times:
# Exact expectation values
exp_H = expm(-1j * t * hamiltonian.to_matrix())
initial_state = Statevector(initial_state_circ).data
time_evolved_state = exp_H @ initial_state
exact_obs = (
time_evolved_state.conj()
@ observable.to_matrix()
@ time_evolved_state
).real
exact_expvals.append(exact_obs)
Mga static na MPF coefficient
Ang mga static MPF ay ang mga kung saan ang mga halaga ng ay hindi nakasalalay sa oras ng evolution na . Isaalang-alang ang order na PF na may Trotter step, maaari itong isulat bilang:
kung saan ang ay mga matrix na nakasalalay sa mga commutator ng mga na termino sa decomposition ng Hamiltonian. Mahalaga pong tandaan na ang mismo ay independyente sa oras at sa bilang ng mga Trotter step na . Kaya naman, posibleng kanselahin ang mga lower-order error term na nag-aambag sa sa pamamagitan ng maingat na pagpili ng mga timbang na ng linear na kombinasyon. Upang kanselahin ang Trotter error para sa unang na termino (ang mga ito ay magbibigay ng pinakamalaking kontribusyon dahil katumbas ang mga ito ng mas mababang bilang ng Trotter step) sa expression para sa , ang mga coefficient na ay dapat matugunan ang mga sumusunod na equation:
na may . Tinitiyak ng unang equation na walang bias sa constructed state na , habang tinitiyak ng pangalawang equation ang pagkansela ng mga Trotter error. Para sa higher-order PF, ang pangalawang equation ay nagiging kung saan ang para sa mga symmetric PF at kung hindi, na may . Ang resulta na error (Refs. [1],[2]) ay
Ang pagtatukoy ng mga static MPF coefficient para sa isang ibinigay na hanay ng mga halaga ng ay katumbas ng paglutas ng linear system ng mga equation na tinukoy ng dalawang equation sa itaas para sa mga variable na : . Kung saan ang ang ating mga coefficient ng interes, ang ay isang matrix na nakasalalay sa at sa uri ng PF na ating ginagamit (), at ang ay isang vector ng mga constraint. Partikular:
kung saan ang ay ang order, ang ay kung ang symmetric ay True at kung hindi, ang ay ang trotter_steps, at ang ay ang mga variable na lulutas. Ang mga indeks na at ay nagsisimula sa . Maaari rin nating visualisahin ito sa matrix form:
at
Para sa karagdagang detalye, sumangguni sa dokumentasyon ng Linear System of Equations (LSE).
Maaari tayong makahanap ng solusyon para sa nang analitiko bilang ; tingnan halimbawa ang Refs. [1] o [2]. Gayunpaman, ang eksaktong solusyong ito ay maaaring "ill-conditioned", na nagbubunga ng napakalaking L1-norm ng ating mga coefficient na , na maaaring magdulot ng masamang pagganap ng MPF. Sa halip, maaari ring makakuha ng tinantyang solusyon na nagpapaliit ng L1-norm ng upang subukang i-optimize ang gawi ng MPF.
I-set up ang LSE
Ngayon na napili na natin ang ating mga halaga ng , kailangan muna nating itayo ang LSE, gaya ng ipinaliwanag sa itaas.
Ang matrix na ay nakasalalay hindi lamang sa kundi pati na rin sa ating pagpili ng PF, partikular ang order nito.
Bukod pa rito, maaari rin ninyong isaalang-alang kung ang PF ay symmetric o hindi (tingnan ang [1]) sa pamamagitan ng pagtatakda ng symmetric=True/False.
Gayunpaman, hindi ito kinakailangan, gaya ng ipinapakita ng Ref. [2].
from qiskit_addon_mpf.static import setup_static_lse
lse = setup_static_lse(mpf_trotter_steps, order=order, symmetric=symmetric)
Suriin natin ang mga halagang pinili sa itaas upang itayo ang matrix na at ang vector na . Sa Trotter step na , order na at pagpili ng non-symmetric Trotter step (), makikita natin na ang mga matrix element ng sa ibaba ng unang row ay tinutukoy ng expression na , partikular:
o sa matrix form:
Maaari itong makita sa pamamagitan ng pagsusuri ng lse object:
lse.A
array([[1. , 1. , 1. ],
[1. , 0.25 , 0.0625 ],
[1. , 0.125 , 0.015625]])
Habang ang vector ng mga constraint na ay may mga sumusunod na elemento:
Kaya naman,
At katulad nito sa lse:
lse.b
array([1., 0., 0.])
Ang lse object ay may mga pamamaraan para sa paghahanap ng mga static na coefficient na na natutugunan ang sistema ng mga equation.
mpf_coeffs = lse.solve()
print(
f"The static coefficients associated with the ansatze are: {mpf_coeffs}"
)
The static coefficients associated with the ansatze are: [ 0.04761905 -0.57142857 1.52380952]
I-optimize ang gamit ang isang eksaktong modelo
Bilang alternatibo sa pagkalkula ng , maaari rin ninyong gamitin ang setup_exact_model upang itayo ang isang cvxpy.Problem instance na gumagamit ng LSE bilang mga constraint at ang optimal na solusyon nito ay magbubunga ng .
Sa susunod na seksyon, magiging malinaw kung bakit umiiral ang interface na ito.
from qiskit_addon_mpf.costs import setup_exact_problem
model_exact, coeffs_exact = setup_exact_problem(lse)
model_exact.solve()
print(coeffs_exact.value)
[ 0.04761905 -0.57142857 1.52380952]
Bilang tagapagpahiwatig kung ang isang MPF na itinayo gamit ang mga coefficient na ito ay magbibigay ng magandang resulta, maaari nating gamitin ang L1-norm (tingnan din ang Ref. [1]).
print(
"L1 norm of the exact coefficients:",
np.linalg.norm(coeffs_exact.value, ord=1),
) # ord specifies the norm. ord=1 is for L1
L1 norm of the exact coefficients: 2.1428571428556378
I-optimize ang gamit ang isang tinantyang modelo
Maaaring mangyari na ang L1 norm para sa piniling hanay ng mga halaga ng ay masyadong mataas. Kung ganoon ang kaso at hindi kayo makapipili ng ibang hanay ng mga halaga ng , maaari ninyong gamitin ang tinantyang solusyon sa LSE sa halip na eksaktong solusyon.
Upang gawin ito, gamitin lamang ang setup_approximate_model upang itayo ang ibang cvxpy.Problem instance, na naglilimita sa L1-norm sa isang piniling threshold habang pinipigilan ang pagkakaiba ng at .
from qiskit_addon_mpf.costs import setup_sum_of_squares_problem
model_approx, coeffs_approx = setup_sum_of_squares_problem(
lse, max_l1_norm=1.5
)
model_approx.solve()
print(coeffs_approx.value)
print(
"L1 norm of the approximate coefficients:",
np.linalg.norm(coeffs_approx.value, ord=1),
)
[-1.10294118e-03 -2.48897059e-01 1.25000000e+00]
L1 norm of the approximate coefficients: 1.5
Tandaan po na mayroon kayong ganap na kalayaan kung paano lutasin ang optimization problem na ito, na nangangahulugang maaari ninyong baguhin ang optimization solver, ang mga convergence threshold nito, at iba pa. Tingnan ang kaukulang gabay sa How to use the approximate model.
Dynamic MPF coefficients
Sa nakaraang seksyon, nagpakilala tayo ng static MPF na nagpapabuti sa karaniwang Trotter approximation. Gayunpaman, hindi kinakailangan na mino-minimize ng static na bersyon na ito ang error sa approximation. Sa konkretong paraan, ang static MPF na tinatawag na , ay hindi ang pinakamainam na projection ng sa subspace na sinasaklaw ng mga product-formula state na .
Upang matugunan ito, isinasaalang-alang natin ang isang dynamic MPF (ipinakikilala sa Ref. [2] at ipinakita sa eksperimento sa Ref. [3]) na talagang mino-minimize ang approximation error sa Frobenius norm. Pormal na sinasabi, nakatuon tayo sa pag-minimize ng
kaugnay ng ilang mga coefficient na sa bawat oras na . Ang pinakamainam na projector sa Frobenius norm ay , at tinatawag nating ang dynamic MPF. Sa pamamagitan ng paglalagay ng mga kahulugan sa itaas:
kung saan ang ay ang Gram matrix, na tinukoy ng
at
ay kumakatawan sa overlap sa pagitan ng eksaktong estado na at ng bawat product-formula approximation na . Sa mga praktikal na sitwasyon, ang mga overlap na ito ay maaaring masukat lamang nang may katumpakan dahil sa ingay o limitadong access sa .
Dito, ang ay ang paunang estado, at ang ay ang operasyon na inilalapat sa product formula. Sa pamamagitan ng pagpili ng mga coefficient na na nagmi-minimize sa expression na ito (at pangangasiwa ng approximate overlap data kapag hindi ganap na kilala ang ), nakakakuha tayo ng "pinakamahusay" (sa kahulugan ng Frobenius norm) na dynamic approximation ng sa loob ng MPF subspace. Ang mga dami na at ay maaaring kalkulahin nang mahusay gamit ang mga pamamaraan ng tensor network [3]. Nagbibigay ang MPF Qiskit addon ng ilang "backend" para isagawa ang kalkulasyon. Ipinapakita ng halimbawa sa ibaba ang pinaka-flexible na paraan para gawin ito, at ang TeNPy layer-based backend docs ay nagpapaliwanag din nang may detalye. Upang magamit ang pamamaraang ito, magsimula sa circuit na nagpapatupad ng nais na time-evolution at lumikha ng mga modelo na kumakatawan sa mga operasyong ito mula sa mga layer ng kaukulang circuit. Sa huli, lumilikha ng isang Evolver na object na maaaring gamitin para makabuo ng mga time-evolved na dami na at . Nagsisimula tayo sa paglikha ng Evolver na object na katumbas ng approximate time-evolution (ApproxEvolverFactory) na ipinapatupad ng mga circuit. Sa partikular, bigyang-pansin ang variable na order upang matiyak na magkatugma ang mga ito. Pansinin na sa pagbuo ng mga circuit na katumbas ng approximate time-evolution, gumagamit tayo ng placeholder na mga halaga para sa time = 1.0 at sa bilang ng mga Trotter step (reps=1). Ang tamang mga approximating circuit ay ginagawa ng dynamic problem solver sa setup_dynamic_lse.
from qiskit_addon_utils.slicing import slice_by_depth
from qiskit_addon_mpf.backends.tenpy_layers import LayerModel
from qiskit_addon_mpf.backends.tenpy_layers import LayerwiseEvolver
from functools import partial
# Create approximate time-evolution circuits
single_2nd_order_circ = generate_time_evolution_circuit(
hamiltonian, time=1.0, synthesis=SuzukiTrotter(reps=1, order=order)
)
single_2nd_order_circ = pm.run(single_2nd_order_circ) # collect XX and YY
# Find layers in the circuit
layers = slice_by_depth(single_2nd_order_circ, max_slice_depth=1)
# Create tensor network models
models = [
LayerModel.from_quantum_circuit(layer, conserve="Sz") for layer in layers
]
# Create the time-evolution object
approx_factory = partial(
LayerwiseEvolver,
layers=models,
options={
"preserve_norm": False,
"trunc_params": {
"chi_max": 64,
"svd_min": 1e-8,
"trunc_cut": None,
},
"max_delta_t": 2,
},
)
Ang mga opsyon ng LayerwiseEvolver na nagtatakda ng mga detalye ng tensor network simulation ay dapat piliin nang maingat upang maiwasan ang pagtatayo ng isang ill-defined na optimization problem.
Pagkatapos ay itinatayo natin ang exact evolver (halimbawa, ExactEvolverFactory), na nagbabalik ng isang Evolver na object na nagkalkula ng tunay o "sanggunian" na time-evolution. Sa realidad, aapproximate natin ang eksaktong evolution sa pamamagitan ng paggamit ng higher-order Suzuki–Trotter formula o iba pang maaasahang pamamaraan na may maliit na time step. Sa ibaba, ina-approximate natin ang eksaktong time-evolved state gamit ang fourth-order Suzuki-Trotter formula na may maliit na time step na dt=0.1, na nangangahulugang ang bilang ng mga Trotter step na ginagamit sa oras na ay . Tinutukoy din natin ang ilang TeNPy-specific na truncation options para limitahan ang maximum bond dimension ng pinagbabatayang tensor network, pati na rin ang minimum singular values ng mga hiwalay na bond ng tensor network. Ang mga parameter na ito ay maaaring makaapekto sa katumpakan ng expectation value na kinakalkula gamit ang dynamic MPF coefficients, kaya't mahalaga na suriin ang hanay ng mga halaga upang mahanap ang pinakamainam na balanse sa pagitan ng oras ng pagkalkula at katumpakan. Tandaan na ang pagkalkula ng mga MPF coefficient ay hindi nakasalalay sa expectation value ng PF na nakuha mula sa pagpapatupad sa hardware, at samakatuwid ay maaari itong i-tune sa post-processing.
single_4th_order_circ = generate_time_evolution_circuit(
hamiltonian, time=1.0, synthesis=SuzukiTrotter(reps=1, order=4)
)
single_4th_order_circ = pm.run(single_4th_order_circ)
exact_model_layers = [
LayerModel.from_quantum_circuit(layer, conserve="Sz")
for layer in slice_by_depth(single_4th_order_circ, max_slice_depth=1)
]
exact_factory = partial(
LayerwiseEvolver,
layers=exact_model_layers,
dt=0.1,
options={
"preserve_norm": False,
"trunc_params": {
"chi_max": 64,
"svd_min": 1e-8,
"trunc_cut": None,
},
"max_delta_t": 2,
},
)
Susunod, likhain ang paunang estado ng iyong sistema sa format na katugma sa TeNPy (halimbawa, isang MPS_neel_state=). Itinatayo nito ang many-body wavefunction na ie-evolve mo sa oras na bilang isang tensor.
from qiskit_addon_mpf.backends.tenpy_tebd import MPOState
from qiskit_addon_mpf.backends.tenpy_tebd import MPS_neel_state
def identity_factory():
return MPOState.initialize_from_lattice(models[0].lat, conserve=True)
mps_initial_state = MPS_neel_state(models[0].lat)
Para sa bawat time step na itinatayo natin ang dynamic linear system of equations gamit ang pamamaraan na setup_dynamic_lse. Ang kaukulang object ay naglalaman ng impormasyon tungkol sa dynamic MPF problem: ang lse.A ay nagbibigay ng Gram matrix na habang ang lse.b ay nagbibigay ng overlap na . Pagkatapos ay maaari nating solusyunan ang LSE (kapag hindi ito ill-defined) upang mahanap ang mga dynamic coefficient gamit ang setup_frobenius_problem. Mahalaga na mapansin ang pagkakaiba sa mga static coefficient, na nakasalalay lamang sa mga detalye ng product formula na ginamit at independiyente sa mga detalye ng time-evolution (Hamiltonian at paunang estado).
from qiskit_addon_mpf.dynamic import setup_dynamic_lse
from qiskit_addon_mpf.costs import setup_frobenius_problem
mpf_dynamic_coeffs_list = []
for t in trotter_times:
print(f"Computing dynamic coefficients for time={t}")
lse = setup_dynamic_lse(
mpf_trotter_steps,
t,
identity_factory,
exact_factory,
approx_factory,
mps_initial_state,
)
problem, coeffs = setup_frobenius_problem(lse)
try:
problem.solve()
mpf_dynamic_coeffs_list.append(coeffs.value)
except Exception as error:
mpf_dynamic_coeffs_list.append(np.zeros(len(mpf_trotter_steps)))
print(error, "Calculation Failed for time", t)
print("")
Computing dynamic coefficients for time=0.5
Computing dynamic coefficients for time=0.6
Computing dynamic coefficients for time=0.7
Computing dynamic coefficients for time=0.7999999999999999
Computing dynamic coefficients for time=0.8999999999999999
Computing dynamic coefficients for time=0.9999999999999999
Computing dynamic coefficients for time=1.0999999999999999
Computing dynamic coefficients for time=1.1999999999999997
Computing dynamic coefficients for time=1.2999999999999998
Computing dynamic coefficients for time=1.4
Computing dynamic coefficients for time=1.4999999999999998
Sa wakas, i-plot ang mga expectation value na ito sa buong oras ng evolution.
import matplotlib.pyplot as plt
sym = {1: "^", 2: "s", 4: "p"}
# Get expectation values at all times for each Trotter step
for k, step in enumerate(mpf_trotter_steps):
trotter_curve, trotter_curve_error = [], []
for trotter_expvals, trotter_stds in zip(
mpf_expvals_all_times, mpf_stds_all_times
):
trotter_curve.append(trotter_expvals[k])
trotter_curve_error.append(trotter_stds[k])
plt.errorbar(
trotter_times,
trotter_curve,
yerr=trotter_curve_error,
alpha=0.5,
markersize=4,
marker=sym[step],
color="grey",
label=f"{mpf_trotter_steps[k]} Trotter steps",
) # , , )
# Get expectation values at all times for the static MPF with exact coeffs
exact_mpf_curve, exact_mpf_curve_error = [], []
for trotter_expvals, trotter_stds in zip(
mpf_expvals_all_times, mpf_stds_all_times
):
mpf_std = np.sqrt(
sum(
[
(coeff**2) * (std**2)
for coeff, std in zip(coeffs_exact.value, trotter_stds)
]
)
)
exact_mpf_curve_error.append(mpf_std)
exact_mpf_curve.append(trotter_expvals @ coeffs_exact.value)
plt.errorbar(
trotter_times,
exact_mpf_curve,
yerr=exact_mpf_curve_error,
markersize=4,
marker="o",
label="Static MPF - Exact",
color="purple",
)
# Get expectation values at all times for the static MPF with approximate
approx_mpf_curve, approx_mpf_curve_error = [], []
for trotter_expvals, trotter_stds in zip(
mpf_expvals_all_times, mpf_stds_all_times
):
mpf_std = np.sqrt(
sum(
[
(coeff**2) * (std**2)
for coeff, std in zip(coeffs_approx.value, trotter_stds)
]
)
)
approx_mpf_curve_error.append(mpf_std)
approx_mpf_curve.append(trotter_expvals @ coeffs_approx.value)
plt.errorbar(
trotter_times,
approx_mpf_curve,
yerr=approx_mpf_curve_error,
markersize=4,
marker="o",
color="orange",
label="Static MPF - Approximate",
)
# # Get expectation values at all times for the dynamic MPF
dynamic_mpf_curve, dynamic_mpf_curve_error = [], []
for trotter_expvals, trotter_stds, dynamic_coeffs in zip(
mpf_expvals_all_times, mpf_stds_all_times, mpf_dynamic_coeffs_list
):
mpf_std = np.sqrt(
sum(
[
(coeff**2) * (std**2)
for coeff, std in zip(dynamic_coeffs, trotter_stds)
]
)
)
dynamic_mpf_curve_error.append(mpf_std)
dynamic_mpf_curve.append(trotter_expvals @ dynamic_coeffs)
plt.errorbar(
trotter_times,
dynamic_mpf_curve,
yerr=dynamic_mpf_curve_error,
markersize=4,
marker="o",
color="pink",
label="Dynamic MPF",
)
plt.plot(
exact_evolution_times,
exact_expvals,
lw=3,
color="red",
label="Exact time-evolution",
)
plt.title(
f"Expectation values for (ZZ,{(L//2-1, L//2)}) as a function of time"
)
plt.xlabel("Time")
plt.ylabel("Expectation Value")
plt.legend()
plt.grid()

Sa mga kaso tulad ng halimbawa sa itaas, kung saan ang PF ay hindi gumaganap nang maayos sa lahat ng oras, ang kalidad ng mga resulta ng dynamic MPF ay lubos din na naaapektuhan. Sa mga ganitong sitwasyon, kapaki-pakinabang na suriin ang posibilidad ng paggamit ng mga indibidwal na PF na may mas mataas na bilang ng mga Trotter step upang mapabuti ang pangkalahatang kalidad ng mga resulta. Sa mga simulation na ito, nakikita natin ang ugnayan ng iba't ibang uri ng mga error: error mula sa limitadong sampling, at Trotter error mula sa mga product formula. Tinutulungan ng MPF na bawasan ang Trotter error dahil sa mga product formula ngunit nagdudulot ng mas mataas na sampling error kumpara sa mga product formula. Maaari itong maging kapaki-pakinabang, dahil ang mga product formula ay maaaring bawasan ang sampling error sa pamamagitan ng mas maraming sampling, ngunit ang systematic error dahil sa Trotter approximation ay nananatiling hindi nababago.
Isa pang kawili-wiling pag-uugali na maaari nating masundan mula sa plot ay ang expectation value para sa PF para sa ay nagsisimulang kumilos nang pabago-bago (bukod sa hindi maging magandang approximation para sa eksaktong isa) sa mga oras kung saan ang , tulad ng ipinaliwanag sa gabay kung paano pumili ng bilang ng mga Trotter step.
Step 1: Map classical inputs to a quantum problem
Isaalang-alang natin ngayon ang isang solong oras na at kalkulahin ang expectation value ng magnetization gamit ang iba't ibang pamamaraan na gumagamit ng isang QPU. Ang partikular na pagpili ng ay ginawa upang mapakinabangan ang pagkakaiba sa pagitan ng iba't ibang pamamaraan at mapansin ang kaukulang bisa ng bawat isa. Upang matukoy ang window ng oras kung saan ginagarantiyahan ng dynamic MPF na makabuo ng mga observable na may mas mababang error kaysa sa alinman sa mga indibidwal na Trotter formula sa loob ng multi-product, maaari nating ipatupad ang "MPF test" — tingnan ang equation (17) at kaugnay na teksto sa [3].
Set up the Trotter circuits
Sa puntong ito, nahanap na natin ang ating mga expansion coefficient na , at ang natitira na lang ay ang pagbuo ng mga Trotterized quantum circuit. Muli, ang module na qiskit_addon_utils.problem_generators ay nakatutulong na may kapaki-pakinabang na function para dito:
from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
)
from qiskit import QuantumCircuit
total_time = 1.0
mpf_circuits = []
for k in mpf_trotter_steps:
# Initial Neel state preparation
circuit = QuantumCircuit(L)
circuit.x([i for i in range(L) if i % 2 != 0])
trotter_circ = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(order=order, reps=k),
time=total_time,
)
circuit.compose(trotter_circ, inplace=True)
mpf_circuits.append(pm.run(circuit))
mpf_circuits[-1].draw("mpl", fold=-1, scale=0.4)
Step 2: Optimize problem for quantum hardware execution
Bumalik tayo sa pagkalkula ng expectation value para sa isang solong time point. Pipili tayo ng backend para isagawa ang eksperimento sa hardware.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.least_busy(min_num_qubits=127)
print(backend)
qubits = list(range(backend.num_qubits))
Pagkatapos ay tinatanggal natin ang mga outlier qubit mula sa coupling map upang matiyak na hindi isasama ng transpiler sa layout stage ang mga ito. Sa ibaba, ginagamit natin ang iniulat na mga katangian ng backend na nakaimbak sa target na object at tinatanggal ang mga qubit na may measurement error o two-qubit gate na lampas sa isang tiyak na threshold (max_meas_err, max_twoq_err) o may time (na nagtatakda ng pagkawala ng coherence) na mas mababa sa isang tiyak na threshold (min_t2).
import copy
from qiskit.transpiler import Target, CouplingMap
target = backend.target
instruction_2q = "cz"
cmap = target.build_coupling_map(filter_idle_qubits=True)
cmap_list = list(cmap.get_edges())
max_meas_err = 0.012
min_t2 = 40
max_twoq_err = 0.005
# Remove qubits with bad measurement or t2
cust_cmap_list = copy.deepcopy(cmap_list)
for q in range(target.num_qubits):
meas_err = target["measure"][(q,)].error
if target.qubit_properties[q].t2 is not None:
t2 = target.qubit_properties[q].t2 * 1e6
else:
t2 = 0
if meas_err > max_meas_err or t2 < min_t2:
# print(q)
for q_pair in cmap_list:
if q in q_pair:
try:
cust_cmap_list.remove(q_pair)
except ValueError:
continue
# Remove qubits with bad 2q gate or t2
for q in cmap_list:
twoq_gate_err = target[instruction_2q][q].error
if twoq_gate_err > max_twoq_err:
# print(q)
for q_pair in cmap_list:
if q == q_pair:
try:
cust_cmap_list.remove(q_pair)
except ValueError:
continue
cust_cmap = CouplingMap(cust_cmap_list)
cust_target = Target.from_configuration(
basis_gates=backend.configuration().basis_gates
+ ["measure"], # or whatever new set of gates
coupling_map=cust_cmap,
)
sorted_components = sorted(
[list(comp.physical_qubits) for comp in cust_cmap.connected_components()],
reverse=True,
)
print("size of largest component", len(sorted_components[0]))
size of largest component 10
Nais nating itakda ang max_meas_err, min_t2, at max_twoq_err upang mahanap ang sapat na malaking subset ng mga qubit na sumusuporta sa circuit na tatakbo. Sa ating kaso, sapat na ang mahanap ang isang 10-qubit na 1D chain.
cust_cmap.draw()

Pagkatapos ay maaari nating i-map ang circuit at observable sa mga pisikal na qubit ng device.
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
transpiler = generate_preset_pass_manager(
optimization_level=3, target=cust_target
)
transpiled_circuits = [transpiler.run(circ) for circ in mpf_circuits]
qubits_layouts = [
[
idx
for idx, qb in circuit.layout.initial_layout.get_physical_bits().items()
if qb._register.name != "ancilla"
]
for circuit in transpiled_circuits
]
transpiled_circuits = []
for circuit, layout in zip(mpf_circuits, qubits_layouts):
transpiler = generate_preset_pass_manager(
optimization_level=3, backend=backend, initial_layout=layout
)
transpiled_circuit = transpiler.run(circuit)
transpiled_circuits.append(transpiled_circuit)
# transform the observable defined on virtual qubits to
# an observable defined on all physical qubits
isa_observables = [
observable.apply_layout(circ.layout) for circ in transpiled_circuits
]
print(transpiled_circuits[-1].depth(lambda x: x.operation.num_qubits == 2))
print(transpiled_circuits[-1].count_ops())
transpiled_circuits[-1].draw("mpl", idle_wires=False, fold=False)
51
OrderedDict([('sx', 310), ('rz', 232), ('cz', 132), ('x', 19)])

Step 3: Execute using Qiskit primitives
Sa pamamagitan ng Estimator primitive, makukuha natin ang pagtatantya ng expectation value mula sa QPU. Isinasagawa natin ang mga na-optimize na AQC circuit na may karagdagang mga teknik ng error mitigation at suppression.
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(mode=backend)
estimator.options.default_shots = 30000
# Set simple error suppression/mitigation options
estimator.options.dynamical_decoupling.enable = True
estimator.options.twirling.enable_gates = True
estimator.options.twirling.enable_measure = True
estimator.options.twirling.num_randomizations = "auto"
estimator.options.twirling.strategy = "active-accum"
estimator.options.resilience.measure_mitigation = True
estimator.options.experimental.execution_path = "gen3-turbo"
estimator.options.resilience.zne_mitigation = True
estimator.options.resilience.zne.noise_factors = (1, 3, 5)
estimator.options.resilience.zne.extrapolator = ("exponential", "linear")
estimator.options.environment.job_tags = ["mpf small"]
job = estimator.run(
[
(circ, observable)
for circ, observable in zip(transpiled_circuits, isa_observables)
]
)
Hakbang 4: I-post-process at ibalik ang resulta sa nais na klasikal na format
Ang tanging hakbang sa post-processing ay ang pagsasama ng expected value na nakuha mula sa Qiskit Runtime primitives sa iba't ibang Trotter steps gamit ang kani-kanilang MPF coefficients. Para sa isang observable na mayroon tayong:
Una, kinukuha natin ang mga indibidwal na expected value na nakuha para sa bawat isa sa mga Trotter circuit:
result_exp = job.result()
evs_exp = [res.data.evs for res in result_exp]
evs_std = [res.data.stds for res in result_exp]
print(evs_exp)
[array(-0.06361607), array(-0.23820448), array(-0.50271805)]
Susunod, pinagsasama-sama lamang natin ang mga ito kasama ang ating mga MPF coefficient upang makuha ang kabuuang expected value ng MPF. Sa ibaba, ginagawa natin ito para sa bawat isa sa mga iba't ibang paraan kung saan kinomputin natin ang .
exact_mpf_std = np.sqrt(
sum(
[
(coeff**2) * (std**2)
for coeff, std in zip(coeffs_exact.value, evs_std)
]
)
)
print(
"Exact static MPF expectation value: ",
evs_exp @ coeffs_exact.value,
"+-",
exact_mpf_std,
)
approx_mpf_std = np.sqrt(
sum(
[
(coeff**2) * (std**2)
for coeff, std in zip(coeffs_approx.value, evs_std)
]
)
)
print(
"Approximate static MPF expectation value: ",
evs_exp @ coeffs_approx.value,
"+-",
approx_mpf_std,
)
dynamic_mpf_std = np.sqrt(
sum(
[
(coeff**2) * (std**2)
for coeff, std in zip(mpf_dynamic_coeffs_list[7], evs_std)
]
)
)
print(
"Dynamic MPF expectation value: ",
evs_exp @ mpf_dynamic_coeffs_list[7],
"+-",
dynamic_mpf_std,
)
Exact static MPF expectation value: -0.6329590442738475 +- 0.012798249760406036
Approximate static MPF expectation value: -0.5690390035339492 +- 0.010459559917168473
Dynamic MPF expectation value: -0.4655579758795695 +- 0.007639139186720507
Sa wakas, para sa maliit na problemang ito maaari nating makuha ang eksaktong reference value gamit ang scipy.linalg.expm tulad ng sumusunod:
from scipy.linalg import expm
from qiskit.quantum_info import Statevector
exp_H = expm(-1j * total_time * hamiltonian.to_matrix())
initial_state_circuit = QuantumCircuit(L)
initial_state_circuit.x([i for i in range(L) if i % 2 != 0])
initial_state = Statevector(initial_state_circuit).data
time_evolved_state = exp_H @ initial_state
exact_obs = (
time_evolved_state.conj() @ observable.to_matrix() @ time_evolved_state
)
print("Exact expectation value ", exact_obs.real)
Exact expectation value -0.39909900734489434
sym = {1: "^", 2: "s", 4: "p"}
# Get expectation values at all times for each Trotter step
for k, step in enumerate(mpf_trotter_steps):
plt.errorbar(
k,
evs_exp[k],
yerr=evs_std[k],
alpha=0.5,
markersize=4,
marker=sym[step],
color="grey",
label=f"{mpf_trotter_steps[k]} Trotter steps",
) # , , )
plt.errorbar(
3,
evs_exp @ coeffs_exact.value,
yerr=exact_mpf_std,
markersize=4,
marker="o",
color="purple",
label="Static MPF",
)
plt.errorbar(
4,
evs_exp @ coeffs_approx.value,
yerr=approx_mpf_std,
markersize=4,
marker="o",
color="orange",
label="Approximate static MPF",
)
plt.errorbar(
5,
evs_exp @ mpf_dynamic_coeffs_list[7],
yerr=dynamic_mpf_std,
markersize=4,
marker="o",
color="pink",
label="Dynamic MPF",
)
plt.axhline(
y=exact_obs.real,
linestyle="--",
color="red",
label="Exact time-evolution",
)
plt.title(
f"Expectation values for (ZZ,{(L//2-1, L//2)}) at time {total_time} for the different methods "
)
plt.xlabel("Method")
plt.ylabel("Expectation Value")
plt.legend(loc="upper center", bbox_to_anchor=(0.5, -0.2), ncol=2)
plt.grid(alpha=0.1)
plt.tight_layout()
plt.show()
Sa halimbawa sa itaas, ang dynamic MPF na pamamaraan ang pinakamahusay sa mga tuntunin ng expected value, na nagpapabuti kaysa sa makukuha nating resulta sa pamamagitan ng paggamit ng pinakamataas na bilang ng Trotter steps nang mag-isa. Kahit na ang iba't ibang MPF technique ay hindi palaging nagkakamit ng pinahusay na expected value kumpara sa pinakamataas na bilang ng Trotter steps (tulad ng exact at ang approximate na modelo sa plot sa itaas), ang standard deviation ng mga halagang ito ay mahusay na nakukuha ang tumaas na variance na natamo kapag ginagamit ang MPF technique. Itinatampok nito ang kawalan ng katiyakan sa paligid ng nakuhang expected value, na palaging kinabibilangan ng expected value na inaasahan natin mula sa eksaktong time-evolution ng sistema. Sa kabilang banda, ang mga expected value na kinakalkula gamit ang mas mababang bilang ng Trotter steps ay nabigo sa pagkuha ng eksaktong expected value sa loob ng kanilang kawalan ng katiyakan, kaya't tiwala nitong ibinabalik ang maling resulta.
def relative_error(ev, exact_ev):
return abs(ev - exact_ev)
relative_error_k = [relative_error(ev, exact_obs.real) for ev in evs_exp]
relative_error_mpf = relative_error(evs_exp @ mpf_coeffs, exact_obs.real)
relative_error_approx_mpf = relative_error(
evs_exp @ coeffs_approx.value, exact_obs.real
)
relative_error_dynamic_mpf = relative_error(
evs_exp @ mpf_dynamic_coeffs_list[7], exact_obs.real
)
print("relative error for each trotter steps", relative_error_k)
print("relative error with MPF exact coeffs", relative_error_mpf)
print("relative error with MPF approx coeffs", relative_error_approx_mpf)
print("relative error with MPF dynamic coeffs", relative_error_dynamic_mpf)
relative error for each trotter steps [0.33548293650112293, 0.16089452939226306, 0.10361904247828346]
relative error with MPF exact coeffs 0.2338600369291003
relative error with MPF approx coeffs 0.16993999618905486
relative error with MPF dynamic coeffs 0.06645896853467514
Bahagi II: palawakin ito
Palawakin natin ang problema nang higit pa sa kung ano ang posibleng ma-simulate nang eksakto. Sa seksyong ito, magtutuon tayo sa pagpapareplika ng ilang mga resulta na ipinapakita sa Ref. [3].
Hakbang 1: I-map ang mga klasikal na input sa isang quantum na problema
Hamiltonian
Para sa malawak na halimbawa, ginagamit natin ang XXZ model sa isang linya ng 50 sites:
kung saan ang ay isang random coefficient na naaayon sa edge . Ito ang Hamiltonian na isinasaalang-alang sa demonstrasyon na inilalahad sa Ref. [3].
L = 50
# Generate some coupling map to use for this example
coupling_map = CouplingMap.from_line(L, bidirectional=False)
graphviz_draw(coupling_map.graph, method="circo")
import numpy as np
from qiskit.quantum_info import SparsePauliOp, Pauli
# Generate random coefficients for our XXZ Hamiltonian
np.random.seed(0)
even_edges = list(coupling_map.get_edges())[::2]
odd_edges = list(coupling_map.get_edges())[1::2]
Js = np.random.uniform(0.5, 1.5, size=L)
hamiltonian = SparsePauliOp(Pauli("I" * L))
for i, edge in enumerate(even_edges + odd_edges):
hamiltonian += SparsePauliOp.from_sparse_list(
[
("XX", (edge), 2 * Js[i]),
("YY", (edge), 2 * Js[i]),
("ZZ", (edge), 4 * Js[i]),
],
num_qubits=L,
)
print(hamiltonian)
SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYY', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'XXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'YYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],
coeffs=[1. +0.j, 2.09762701+0.j, 2.09762701+0.j, 4.19525402+0.j,
2.43037873+0.j, 2.43037873+0.j, 4.86075747+0.j, 2.20552675+0.j,
2.20552675+0.j, 4.4110535 +0.j, 2.08976637+0.j, 2.08976637+0.j,
4.17953273+0.j, 1.8473096 +0.j, 1.8473096 +0.j, 3.6946192 +0.j,
2.29178823+0.j, 2.29178823+0.j, 4.58357645+0.j, 1.87517442+0.j,
1.87517442+0.j, 3.75034885+0.j, 2.783546 +0.j, 2.783546 +0.j,
5.567092 +0.j, 2.92732552+0.j, 2.92732552+0.j, 5.85465104+0.j,
1.76688304+0.j, 1.76688304+0.j, 3.53376608+0.j, 2.58345008+0.j,
2.58345008+0.j, 5.16690015+0.j, 2.05778984+0.j, 2.05778984+0.j,
4.11557968+0.j, 2.13608912+0.j, 2.13608912+0.j, 4.27217824+0.j,
2.85119328+0.j, 2.85119328+0.j, 5.70238655+0.j, 1.14207212+0.j,
1.14207212+0.j, 2.28414423+0.j, 1.1742586 +0.j, 1.1742586 +0.j,
2.3485172 +0.j, 1.04043679+0.j, 1.04043679+0.j, 2.08087359+0.j,
2.66523969+0.j, 2.66523969+0.j, 5.33047938+0.j, 2.5563135 +0.j,
2.5563135 +0.j, 5.112627 +0.j, 2.7400243 +0.j, 2.7400243 +0.j,
5.48004859+0.j, 2.95723668+0.j, 2.95723668+0.j, 5.91447337+0.j,
2.59831713+0.j, 2.59831713+0.j, 5.19663426+0.j, 1.92295872+0.j,
1.92295872+0.j, 3.84591745+0.j, 2.56105835+0.j, 2.56105835+0.j,
5.12211671+0.j, 1.23654885+0.j, 1.23654885+0.j, 2.4730977 +0.j,
2.27984204+0.j, 2.27984204+0.j, 4.55968409+0.j, 1.28670657+0.j,
1.28670657+0.j, 2.57341315+0.j, 2.88933783+0.j, 2.88933783+0.j,
5.77867567+0.j, 2.04369664+0.j, 2.04369664+0.j, 4.08739329+0.j,
1.82932388+0.j, 1.82932388+0.j, 3.65864776+0.j, 1.52911122+0.j,
1.52911122+0.j, 3.05822245+0.j, 2.54846738+0.j, 2.54846738+0.j,
5.09693476+0.j, 1.91230066+0.j, 1.91230066+0.j, 3.82460133+0.j,
2.1368679 +0.j, 2.1368679 +0.j, 4.2737358 +0.j, 1.0375796 +0.j,
1.0375796 +0.j, 2.0751592 +0.j, 2.23527099+0.j, 2.23527099+0.j,
4.47054199+0.j, 2.22419145+0.j, 2.22419145+0.j, 4.44838289+0.j,
2.23386799+0.j, 2.23386799+0.j, 4.46773599+0.j, 2.88749616+0.j,
2.88749616+0.j, 5.77499231+0.j, 2.3636406 +0.j, 2.3636406 +0.j,
4.7272812 +0.j, 1.7190158 +0.j, 1.7190158 +0.j, 3.4380316 +0.j,
1.87406391+0.j, 1.87406391+0.j, 3.74812782+0.j, 2.39526239+0.j,
2.39526239+0.j, 4.79052478+0.j, 1.12045094+0.j, 1.12045094+0.j,
2.24090189+0.j, 2.33353343+0.j, 2.33353343+0.j, 4.66706686+0.j,
2.34127574+0.j, 2.34127574+0.j, 4.68255148+0.j, 1.42076512+0.j,
1.42076512+0.j, 2.84153024+0.j, 1.2578526 +0.j, 1.2578526 +0.j,
2.51570519+0.j, 1.6308567 +0.j, 1.6308567 +0.j, 3.2617134 +0.j])
Para sa isang observable, pinipili natin ang , tulad ng makikita sa lower panel ng Fig. 5 ng Ref. [3].
observable = SparsePauliOp.from_sparse_list(
[("ZZ", (L // 2 - 1, L // 2), 1.0)], num_qubits=L
)
print(observable)
SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIII'],
coeffs=[1.+0.j])
Pumili ng mga Trotter step
Ang eksperimentong ipinapakita sa Fig. 4 ng Ref. [3] ay gumagamit ng na symmetric Trotter steps ng order na . Nakatutok tayo sa mga resulta para sa oras na , kung saan ang MPF at ang isang PF na may mas mataas na bilang ng Trotter steps (6 sa kasong ito) ay may parehong Trotter error. Gayunpaman, ang MPF expected value ay kinakalkula mula sa mga circuit na naaayon sa mas mababang bilang ng Trotter steps at sa gayon ay mas mababaw. Sa praktika, kahit na ang MPF at ang mas malalim na Trotter steps circuit ay may parehong Trotter error, inaasahan nating ang experimental expected value na kinakalkula mula sa mga MPF circuit ay magiging mas malapit sa teoriya, dahil nangangailangan ito ng pagpapatakbo ng mas mababaw na mga circuit na mas hindi nalantad sa hardware noise kumpara sa circuit na naaayon sa mas mataas na Trotter step PF.
total_time = 3
mpf_trotter_steps = [2, 3, 4]
order = 2
symmetric = True
I-set up ang LSE
Dito tinitignan natin ang mga static MPF coefficient para sa problemang ito.
lse = setup_static_lse(mpf_trotter_steps, order=order, symmetric=symmetric)
mpf_coeffs = lse.solve()
print(
f"The static coefficients associated with the ansatze are: {mpf_coeffs}"
)
print("L1 norm:", np.linalg.norm(mpf_coeffs, ord=1))
The static coefficients associated with the ansatze are: [ 0.26666667 -2.31428571 3.04761905]
L1 norm: 5.628571428571431
model_approx, coeffs_approx = setup_sum_of_squares_problem(
lse, max_l1_norm=2.0
)
model_approx.solve()
print(coeffs_approx.value)
print(
"L1 norm of the approximate coefficients:",
np.linalg.norm(coeffs_approx.value, ord=1),
)
[-0.24255546 -0.25744454 1.5 ]
L1 norm of the approximate coefficients: 2.0
Mga dynamic coefficient
# Create approximate time-evolution circuits
single_2nd_order_circ = generate_time_evolution_circuit(
hamiltonian, time=1.0, synthesis=SuzukiTrotter(reps=1, order=order)
)
single_2nd_order_circ = pm.run(single_2nd_order_circ) # collect XX and YY
# Find layers in the circuit
layers = slice_by_depth(single_2nd_order_circ, max_slice_depth=1)
# Create tensor network models
models = [
LayerModel.from_quantum_circuit(layer, conserve="Sz") for layer in layers
]
# Create the time-evolution object
approx_factory = partial(
LayerwiseEvolver,
layers=models,
options={
"preserve_norm": False,
"trunc_params": {
"chi_max": 64,
"svd_min": 1e-8,
"trunc_cut": None,
},
"max_delta_t": 4,
},
)
# Create exact time-evolution circuits
single_4th_order_circ = generate_time_evolution_circuit(
hamiltonian, time=1.0, synthesis=SuzukiTrotter(reps=1, order=4)
)
single_4th_order_circ = pm.run(single_4th_order_circ)
exact_model_layers = [
LayerModel.from_quantum_circuit(layer, conserve="Sz")
for layer in slice_by_depth(single_4th_order_circ, max_slice_depth=1)
]
# Create the time-evolution object
exact_factory = partial(
LayerwiseEvolver,
layers=exact_model_layers,
dt=0.1,
options={
"preserve_norm": False,
"trunc_params": {
"chi_max": 64,
"svd_min": 1e-8,
"trunc_cut": None,
},
"max_delta_t": 3,
},
)
def identity_factory():
return MPOState.initialize_from_lattice(models[0].lat, conserve=True)
mps_initial_state = MPS_neel_state(models[0].lat)
lse = setup_dynamic_lse(
mpf_trotter_steps,
total_time,
identity_factory,
exact_factory,
approx_factory,
mps_initial_state,
)
problem, coeffs = setup_frobenius_problem(lse)
try:
problem.solve()
mpf_dynamic_coeffs = coeffs.value
except Exception as error:
print(error, "Calculation Failed for time", total_time)
print("")
Itayo ang bawat Trotter circuit sa aming MPF decomposition
from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
)
from qiskit import QuantumCircuit
mpf_circuits = []
for k in mpf_trotter_steps:
# Initial state preparation |1010..>
circuit = QuantumCircuit(L)
circuit.x([i for i in range(L) if i % 2])
trotter_circ = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=k, order=order),
time=total_time,
)
circuit.compose(trotter_circ, qubits=range(L), inplace=True)
mpf_circuits.append(circuit)
Itayo ang Trotter circuit na may katulad na Trotter error sa MPF
k = 6
# Initial state preparation |1010..>
comp_circuit = QuantumCircuit(L)
comp_circuit.x([i for i in range(L) if i % 2])
trotter_circ = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=k, order=order),
time=total_time,
)
comp_circuit.compose(trotter_circ, qubits=range(L), inplace=True)
mpf_circuits.append(comp_circuit)
Hakbang 2: I-optimize ang problema para sa pagpapatakbo sa quantum hardware
import copy
from qiskit.transpiler import Target, CouplingMap
target = backend.target
instruction_2q = "cz"
cmap = target.build_coupling_map(filter_idle_qubits=True)
cmap_list = list(cmap.get_edges())
max_meas_err = 0.055
min_t2 = 30
max_twoq_err = 0.01
# Remove qubits with bad measurement or t2
cust_cmap_list = copy.deepcopy(cmap_list)
for q in range(target.num_qubits):
meas_err = target["measure"][(q,)].error
if target.qubit_properties[q].t2 is not None:
t2 = target.qubit_properties[q].t2 * 1e6
else:
t2 = 0
if meas_err > max_meas_err or t2 < min_t2:
# print(q)
for q_pair in cmap_list:
if q in q_pair:
try:
cust_cmap_list.remove(q_pair)
except ValueError:
continue
# Remove qubits with bad 2q gate or t2
for q in cmap_list:
twoq_gate_err = target[instruction_2q][q].error
if twoq_gate_err > max_twoq_err:
# print(q)
for q_pair in cmap_list:
if q == q_pair:
try:
cust_cmap_list.remove(q_pair)
except ValueError:
continue
cust_cmap = CouplingMap(cust_cmap_list)
cust_target = Target.from_configuration(
basis_gates=backend.configuration().basis_gates
+ ["measure"], # or whatever new set of gates
coupling_map=cust_cmap,
)
sorted_components = sorted(
[list(comp.physical_qubits) for comp in cust_cmap.connected_components()],
reverse=True,
)
print("size of largest component", len(sorted_components[0]))
size of largest component 73
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
transpiler = generate_preset_pass_manager(
optimization_level=3, target=cust_target
)
transpiled_circuits = [transpiler.run(circ) for circ in mpf_circuits]
qubits_layouts = [
[
idx
for idx, qb in circuit.layout.initial_layout.get_physical_bits().items()
if qb._register.name != "ancilla"
]
for circuit in transpiled_circuits
]
transpiled_circuits = []
for circuit, layout in zip(mpf_circuits, qubits_layouts):
transpiler = generate_preset_pass_manager(
optimization_level=3, backend=backend, initial_layout=layout
)
transpiled_circuit = transpiler.run(circuit)
transpiled_circuits.append(transpiled_circuit)
# transform the observable defined on virtual qubits to
# an observable defined on all physical qubits
isa_observables = [
observable.apply_layout(circ.layout) for circ in transpiled_circuits
]
Hakbang 3: Isagawa gamit ang mga Qiskit primitive
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(mode=backend)
estimator.options.default_shots = 30000
# Set simple error suppression/mitigation options
estimator.options.dynamical_decoupling.enable = True
estimator.options.twirling.enable_gates = True
estimator.options.twirling.enable_measure = True
estimator.options.twirling.num_randomizations = "auto"
estimator.options.twirling.strategy = "active-accum"
estimator.options.resilience.measure_mitigation = True
estimator.options.experimental.execution_path = "gen3-turbo"
estimator.options.resilience.zne_mitigation = True
estimator.options.resilience.zne.noise_factors = (1, 1.2, 1.4)
estimator.options.resilience.zne.extrapolator = "linear"
estimator.options.environment.job_tags = ["mpf large"]
job_50 = estimator.run(
[
(circ, observable)
for circ, observable in zip(transpiled_circuits, isa_observables)
]
)
Hakbang 4: Post-process at ibalik ang resulta sa nais na klasikal na format
result = job_50.result()
evs = [res.data.evs for res in result]
std = [res.data.stds for res in result]
print(evs)
print(std)
[array(-0.08034071), array(-0.00605026), array(-0.15345759), array(-0.18127293)]
[array(0.04482517), array(0.03438413), array(0.21540776), array(0.21520829)]
exact_mpf_std = np.sqrt(
sum([(coeff**2) * (std**2) for coeff, std in zip(mpf_coeffs, std[:3])])
)
print(
"Exact static MPF expectation value: ",
evs[:3] @ mpf_coeffs,
"+-",
exact_mpf_std,
)
approx_mpf_std = np.sqrt(
sum(
[
(coeff**2) * (std**2)
for coeff, std in zip(coeffs_approx.value, std[:3])
]
)
)
print(
"Approximate static MPF expectation value: ",
evs[:3] @ coeffs_approx.value,
"+-",
approx_mpf_std,
)
dynamic_mpf_std = np.sqrt(
sum(
[
(coeff**2) * (std**2)
for coeff, std in zip(mpf_dynamic_coeffs, std[:3])
]
)
)
print(
"Dynamic MPF expectation value: ",
evs[:3] @ mpf_dynamic_coeffs,
"+-",
dynamic_mpf_std,
)
Exact static MPF expectation value: -0.47510243192011536 +- 0.6613940032465087
Approximate static MPF expectation value: -0.20914170384216998 +- 0.32341567460419135
Dynamic MPF expectation value: -0.07994951978722761 +- 0.07423091963310202
sym = {2: "^", 3: "s", 4: "p"}
# Get expectation values at all times for each Trotter step
for k, step in enumerate(mpf_trotter_steps):
plt.errorbar(
k,
evs[k],
yerr=std[k],
alpha=0.5,
markersize=4,
marker=sym[step],
color="grey",
label=f"{mpf_trotter_steps[k]} Trotter steps",
)
plt.errorbar(
3,
evs[-1],
yerr=std[-1],
alpha=0.5,
markersize=8,
marker="x",
color="blue",
label="6 Trotter steps",
)
plt.errorbar(
4,
evs[:3] @ mpf_coeffs,
yerr=exact_mpf_std,
markersize=4,
marker="o",
color="purple",
label="Static MPF",
)
plt.errorbar(
5,
evs[:3] @ coeffs_approx.value,
yerr=approx_mpf_std,
markersize=4,
marker="o",
color="orange",
label="Approximate static MPF",
)
plt.errorbar(
6,
evs[:3] @ mpf_dynamic_coeffs,
yerr=dynamic_mpf_std,
markersize=4,
marker="o",
color="pink",
label="Dynamic MPF",
)
exact_obs = -0.24384471447172074 # Calculated via Tensor Network calculation
plt.axhline(
y=exact_obs, linestyle="--", color="red", label="Exact time-evolution"
)
plt.title(
f"Expectation values for (ZZ,{(L//2-1, L//2)}) at time {total_time} for the different methods "
)
plt.xlabel("Method")
plt.ylabel("Expectation Value")
plt.legend(loc="upper center", bbox_to_anchor=(0.5, -0.2), ncol=2)
plt.grid(alpha=0.1)
plt.tight_layout()
plt.show()
Kapag nagpapatakbo ng mga circuit sa hardware, maaaring makatagpo tayo ng mga karagdagang hamon sa pagkuha ng tumpak na mga expectation value dahil sa presensya ng hardware noise. Hindi ito isinasaalang-alang sa MPF formalism at maaaring makapagpahina sa solusyon ng MPF. Halimbawa, ito ang maaaring dahilan kung bakit nabigo ang mga dynamic coefficient na magbigay ng mas tumpak na pagtatantya ng expectation value kumpara sa approximate static coefficient sa plot. Ibig sabihin, ang approximate evolver, na simumuyla ng approximate circuit, ay hindi tumpak na sumasalamin sa mga resulta na nakuha sa pamamagitan ng pagpapatakbo ng mga approximate circuit sa presensya ng hardware noise. Sa mga kadahilanang ito, inirerekomenda na pagsamahin ang iba't ibang teknik ng error mitigation upang makakuha ng mga resulta na kasing-lapit ng posible sa mga ideal na halaga para sa bawat isa sa mga product formula. Ipapakita nito ang pare-parehong mga benepisyo mula sa diskarteng MPF.
Sa kabuuan, ang mga approximate static coefficient ay nagbibigay pa rin ng mas tumpak na solusyon kaysa sa product formula na may mas mataas na bilang ng Trotter step na may parehong dami ng Trotter error sa noiseless na kapaligiran.
Mahalaga rin na tandaan na sa halimbawa na nagpapareplika ng eksperimento sa Ref. [3], ang time point na ay lampas sa limitasyon kung saan inaasahang gumagana nang maayos ang PF na may , na siyang ayon sa tinalakay sa gabay na ito.