Gumawa ng mga SqDRIFT circuit
Sa sample-based quantum diagonalization (SQD), kailangan mong pumili ng ansatz na pagkukunan ng mga bitstring. Ang variant na SqDRIFT ay gumagamit na lang ng ensemble ng mga time evolution circuit na direktang binuo mula sa target na Hamiltonian. Nagagawa ito sa pag-subsample ng mas maliliit na time evolution operator mula sa Hamiltonian batay sa mga coefficient nito, na kilala bilang paraan ng Trotterization na qDRIFT.
Ipinapakita ng getting started guide na ito kung paano gumawa ng ensemble ng mga ganitong randomized na circuit.
1. Setup ng Hamiltonian
Para sa layunin ng gabay na ito, i-load ang electronic structure Hamiltonian ng N2 mula sa isang FCIDUMP file. May iba pang paraan para buuin ang FermionOperator. Siguraduhing tingnan ang dokumentasyon nito, pati na ang qiskit_fermions.operators.library.
- PYTHON
- C
>>> from qiskit_fermions.operators.library import FCIDump
>>> from qiskit_fermions.operators import FermionOperator
>>>
>>> fcidump = FCIDump.from_file("docs/guides/n2.fcidump")
>>> num_modes = 2 * fcidump.norb
>>> hamil = FermionOperator.from_fcidump(fcidump)
#include <qiskit_fermions.h>
QfFCIDump* fcidump = NULL;
qf_fcidump_from_file("docs/guides/n2.fcidump", &fcidump);
QfFermionOperator* hamil = qf_ferm_op_from_fcidump(fcidump);
uint32_t num_modes = 2 * qf_fcidump_norb(fcidump);
2. I-group ang mga term ng Hamiltonian
Samantalahin ang maraming symmetry na nasa electronic structure Hamiltonian sa pamamagitan ng pag-group ng magkakaugnay na term na may magkaparehong coefficient. Binabago ng aksyon na ito ang distribusyon ng operator coefficient na sinasample ng qDRIFT protocol, pero hindi nito naaapektuhan ang mga convergence guarantee nito. Mahalaga, ang pag-group ng mga term na magkaugnay sa symmetry ay nagreresulta sa kapaki-pakinabang na pagkansela ng mga Pauli term, kaya mas maikli ang kabuuang circuit depth kapag nag-time evolve ng isang state sa ilalim ng aksyon nila.
Ang module na qiskit_fermions.operators.terms.grouping ay nagbibigay ng mga convenience function para sa pag-group ng mga term ng isang operator. Mas detalyado itong ipinapaliwanag sa gabay na ito.
Ipinapalagay ng implementasyon ng group_terms_by_electronic_structure() na normal-ordered ang mga term ng Hamiltonian!
- PYTHON
- C
>>> from qiskit_fermions.operators.terms.grouping import group_terms_by_electronic_structure
>>> from qiskit_fermions.operators.terms.ordering import canonical_order
>>>
>>> canon = canonical_order(hamil.normal_ordered().simplify(atol=1e-16))
>>> exit_code = group_terms_by_electronic_structure(canon, num_modes, two_body_physicist_order=False)
>>> assert exit_code is None
>>> print(canon.groups) # the groups attribute now contains some list of group indices
[0, ...]
QfFermionOperator* normal = qf_ferm_op_normal_ordered(hamil, NULL);
QfFermionOperator* simplified = qf_ferm_op_simplify(normal, 1e-16);
QfFermionOperator* canon = qf_ferm_op_canonical_order(simplified);
QfExitCode exit = qf_ferm_op_group_terms_by_electronic_structure(canon, num_modes, false);
assert(exit == QfExitCode_Success);
qf_ferm_op_free(normal);
qf_ferm_op_free(simplified);
Ang buong electronic structure Hamiltonian ay may ilang term na ang pagsama sa isang time-evolution circuit ay walang epekto sa mga bitstring na makikita at, kaya, nagdudulot lang ng dagdag na sampling overhead. Kaya inirerekomendang i-filter ang mga ganoong term mula sa Hamiltonian sa puntong ito, bago buuin ang Evolution gate sa susunod na hakbang.
Ang mga term na pasok sa deskripsyong ito ay ang mga diagonal sa occupation-number basis, ibig sabihin, ang mga produkto ng number operator (). Kasama rito ang constant energy offset, na ang time evolution ay nagdadala lang ng global phase sa circuit, ang mga indibidwal na number operator na ang time evolution ay katumbas ng single-qubit Z rotation, pati ang mga mas mataas na order na produkto tulad ng . Wala sa mga ito ang makapagbabago ng occupation ng isang mode, kaya ang pag-drop sa mga ito ay walang gastos sa excitation content. Hindi tulad ng per-draw rejection sa step 5, nangyayari ang pag-filter na ito nang isang beses, sa mismong Hamiltonian, kaya ang distribusyon ng coefficient na sinasample ng protocol ay muling binubuo nang pare-pareho mula sa na-filter na operator sa halip na i-renormalize sa gitna ng draw.
Ang function na filter_diagonal_terms() ay nag-aalis ng mga ganoong term mula sa isang operator in place:
- PYTHON
- C
>>> from qiskit_fermions.operators.terms.filtering import filter_diagonal_terms
>>>
>>> filter_diagonal_terms(canon)
qf_ferm_op_filter_diagonal_terms(canon);
Mas mura nang malaki ang pag-filter dito, nang isang beses lang, kaysa sa paulit-ulit na pag-filter. Tumatakbo nang isang beses ang FermionicQDrift kada na-transpile na circuit, kaya ang pag-filter sa Hamiltonian sa simula, sa halip na sa bawat tawag, ay iniiwasan ang pag-uulit ng trabaho para sa bawat circuit na nabubuo mula rito.
Dahil sa parehong dahilan, sulit na i-order ang mga term ng Hamiltonian ayon sa group index dito. Ang mga group index ay tag kada term na walang sinasabi kung nasaan ang mga term na iyon, kaya ang mga term ng isang group ay karaniwang nakakalat sa buong operator: ang grouping na inilapat sa itaas ay nagtatalaga ng mga index ayon sa pagkakasunod ng unang pagkakita, kaya malayo ang ikalawang term ng isang group sa una nito.
Sinasample ng FermionicQDrift ang buong mga group at hinahanap ang bawat nakuhang group gamit ang split_out_groups(). Ang paghahanap ng group sa gitna ng nakakalat na mga term ay nangangahulugang pag-scan sa lahat ng mga ito, kaya pareho ang gastos ng paghahanap kahit isa o apatnapung group ang nakuha. Kinokolekta ng group_order() ang bawat group sa isang tuloy-tuloy na hanay, kaya pagkatapos nito ang paghahanap ay isang binary search sa mga hangganan ng group at ang gastos ay ayon sa nakuhang mga group sa halip na sa hawak na mga term. Nagiging napakamura ng mismong paghahanap; kung gaano karami ang natitipid nito sa isang partikular na transpilation ay depende sa iba pang ginagawa ng pipeline, dahil ang mapping at synthesis na ang nangingibabaw kapag wala na ang scan:
- PYTHON
- C
>>> from qiskit_fermions.operators.terms.ordering import group_order
>>>
>>> canon = group_order(canon)
>>> print(canon.groups[:4])
[0, 0, ...]
QfFermionOperator* grouped = qf_ferm_op_group_order(canon);
Inaayos nito ang pagkakasunod ng mga term nang hindi binabago ang halaga ng operator, at kailangan lang itong gawin nang isang beses gaano man karaming circuit randomization ang kukunin mula rito.
3. Ihanda ang time evolution circuit
Ihanda ang time evolution circuit ng Hamiltonian at ang base circuit na pagkukunan ng mga sample. Ang qiskit_fermions.circuit.library ay naglalaman ng lahat ng kinakailangang component para rito, alinsunod sa mga convention ng Qiskit.
Ang qDRIFT protocol ang synthesis method na FermionicQDrift, at dala ito ng Evolution gate bilang synthesis nito. Ipinapakilala ng method ang ilang parameter na magagamit mo para i-customize ang mga circuit na gagawin:
-
Ang haba ng bawat circuit sa mga excitation group:
num_groups -
Opsyonal, isang seed para sa random number generator:
rng -
Opsyonal, mga precomputed na sampling weight, kung ang transpilation mismo ang maging bottleneck:
weights(tingnan ang (Opsyonal) I-precompute ang mga sampling weight sa ibaba)
Dahil hawak ng gate ang method, ang anumang naglalarawan sa operator ng gate, tulad ng mga weight na iyon, ay nasa tabi mismo ng operator na iyon.
- PYTHON
- C
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.circuit.library.synthesis import FermionicQDrift
>>>
>>> time = 1.0 # you can choose a desired scaling factor here
>>> num_groups = 10
>>> qdrift = FermionicQDrift(num_groups, rng=19)
>>> evo_gate = Evolution(num_modes, canon, time, synthesis=qdrift)
>>>
>>> circ = FermionicCircuit(num_modes)
>>> circ.append(evo_gate, circ.modes)
// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions.
Hindi ini-initialize ng halimbawang ito ang mga fermionic mode gamit ang mga particle, at hindi rin nito sinusukat ang huling state nila.
4. I-transpile ang circuit
Ang module na qiskit_fermions.transpiler ay direktang isinasama sa transpilation pipeline ng Qiskit, kaya ang FermionicCircuit na binuo sa itaas ay maaaring direktang i-transpile sa isang QuantumCircuit.
Gamitin ang fermion-to-qubit mapping na jordan_wigner() para i-convert ang Hamiltonian na nakasaad sa mga fermion para maisaad na lang ito sa mga Pauli string. Magagawa ito nang direkta bilang bahagi ng proseso ng transpilation gamit ang transpilation pass na F2QSynthesis. Gamitin ang generate_preset_jw_pass_manager() para buuin ang FermionicStagedPassManager, na tinitiyak na pare-pareho ang paggamit ng Jordan-Wigner encoding sa lahat ng circuit instruction.
Mahalaga, idagdag ang Decompose pass ng Qiskit sa optimization stage ng transpilation pipeline. Binabaklas nito ang Evolution gate gamit ang synthesis method na dala ng gate, na siyang qDRIFT method na inihanda sa itaas. Tinitiyak nito na hindi gagamitin ng circuit ang time evolution ng buong Hamiltonian, na ang depth ay lalampas sa kakayahan ng kasalukuyang magagamit na quantum computing hardware.
Sa halip, nagsa-subsample ito ng takdang bilang ng groups ng mga term ng Hamiltonian para sa bawat circuit, tuwing ita-transpile ang circuit. Dahil dito, makakagawa ka ng maraming circuit randomization ayon sa kinakailangan ng algorithm na SqDRIFT sa pamamagitan ng paulit-ulit na pagpapatakbo ng transpilation pipeline. Ang bilang ng mga circuit na gagawin ay num_sqdrift_randomizations.
- PYTHON
- C
>>> from qiskit.transpiler.passes import Decompose
>>> from qiskit_fermions.transpiler import FermionicPassManager
>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>>
>>> pm = generate_preset_jw_pass_manager()
>>> pm.optimization = FermionicPassManager([Decompose(["Evolution"])])
>>>
>>> num_sqdrift_randomizations = 10
>>> sqdrift_circuits = [
... pm.run(circ) for _ in range(num_sqdrift_randomizations)
... ]
// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions, which we therefore also cannot transpile
// via this API.
Itinatakda ng mga naunang halimbawa ang rng seed ng synthesis method na FermionicQDrift, para maulit ang pagkakasunod ng mga randomization.
Tumatanggap ang parehong pipeline ng qDRIFT method sa dalawa pang lugar. Ang pass na F2FSynthesis ay kumukuha ng isang method para sa bawat Evolution gate ayon sa pangalan, F2FSynthesis({"Evolution": FermionicQDrift(num_groups)}), na siyang sapat kapag walang gate na may hawak na partikular sa operator nito. Ang ikatlo ay gagamitin sa susunod na hakbang, ang pass na QDriftTrotterization.
5. I-filter ang mga nakuhang excitation ayon sa occupation
Bukod sa mga diagonal term na na-filter sa nakaraang hakbang, ang isang nakuhang excitation ay maaaring kumilos nang buo sa loob ng isang set ng mga mode na ayos na ang occupation (lahat occupied o lahat unoccupied), kung saan hindi ito makapaglilipat ng particle mula sa isang panig patungo sa kabila. Walang sinasabi sa iyo ang ganoong excitation tungkol sa mga na-sample na bitstring, kaya sayang ang slot na ginugol dito. Ang pass na QDriftTrotterization, na bumabalot sa parehong method na FermionicQDrift, ay tumatanggi sa mga ganoong excitation habang kinukuha ang mga ito at kumukuha ng kapalit, kaya ang bawat isa sa num_groups slot ng resultang circuit ay may excitation na nag-uugnay sa dalawang panig.
Hindi libre ang pag-filter na ito, at hiwalay itong pass dahil dito. Ang pinapanatili nito ay ang badyet ng num_groups na sampled slot, hindi ang circuit depth: dahil nakapirmi ang badyet na iyon, pinapalitan ang tinanggihang excitation sa halip na tanggalin, at ang mura ay napapalitan ng coupling excitation na mas magastos i-synthesize. Asahan na mas malalim ang na-filter na circuit kaysa sa hindi na-filter na kinuha mula sa parehong seed.
Ang pag-renormalize ng draw sa mga tinanggap na excitation ay nagbabago sa distribusyon na sinasample ng qDRIFT protocol, at hindi tulad ng grouping sa step 2, sinisira rin nito ang convergence guarantee ng protocol: ang na-sample na produkto ay hindi na nag-a-average sa evolution sa ilalim ng Hamiltonian na ipinasa mo. Ang bawat natirang excitation ay nabibigyan ng bigat na katumbas ng reciprocal ng acceptance probability, ang mga tinanggihan ay walang naiaambag, at hindi inaayos ang kabuuang laki ng coefficient o ang evolution time kada gate para bumawi.
Isang over-approximation din ang acceptance rule. Mode supports lang ang kinukumpara nito, kaya wala itong dalang amplitude information, at lumalaki lang ang mga tracked set: ang excitation na nakakulong sa occupied set ay talagang inert sa isang product state, pero humihina ang parehong katwiran para sa mga susunod na draw, kapag ang mga naunang tinanggap na excitation ay nag-iwan sa state na entangled at minarkahan ang karamihan ng mga mode bilang “uncertain”.
Gamitin ang pag-filter para sa bitstring-sampling workflow na inilalarawan ng gabay na ito, kung saan ang mga circuit ay pinapasok sa SQD post-processing at ang mga na-sample na bitstring lang ang mahalaga. Huwag itong gamitin kung balak mong tantiyahin ang isang expectation value mula sa mga circuit na ito, o umasa sa qDRIFT error bound sa anumang ibang paraan: ang mga resultang iyon ay may bias na hindi itinatama ng pass.
Kailangang malaman ng pag-filter na ito kung aling mga mode ang occupied sa simula. Kaya nangangailangan ito ng InitializeModes gate bago ang mga Evolution gate sa circuit; ang InitializeModes.from_hartree_fock() ay madaling paraan para bumuo nito. Magdagdag ng isa rito para sa N2 Hartree-Fock reference (pitong alpha at pitong beta na electron sa 14 na spatial orbital) at ihambing ang mga na-sample na excitation na may at walang pag-filter:
- PYTHON
- C
>>> from qiskit_fermions.circuit.library import InitializeModes
>>> from qiskit_fermions.transpiler.passes import F2FSynthesis, QDriftTrotterization
>>>
>>> init = InitializeModes.from_hartree_fock(fcidump.norb, (7, 7))
>>>
>>> hf_circ = FermionicCircuit(num_modes)
>>> hf_circ.append(init, hf_circ.modes)
>>> hf_circ.append(Evolution(num_modes, canon, time), hf_circ.modes)
>>>
>>> num_groups = 5
>>> qdrift_unfiltered = F2FSynthesis(
... {"Evolution": FermionicQDrift(num_groups, rng=3480)}
... )
>>> qdrift_trivial = QDriftTrotterization(
... FermionicQDrift(num_groups, rng=3480)
... )
>>>
>>> for instruction in FermionicPassManager(qdrift_unfiltered).run(hf_circ)._inner.data:
... if instruction.operation.name == "Evolution":
... print(sorted(instruction.operation.operator.get_support()))
[2, 4]
[41, 45, 52]
[15, 45, 55]
[41, 52, 53]
[10, 16, 37, 38]
>>>
>>> for instruction in FermionicPassManager(qdrift_trivial).run(hf_circ)._inner.data:
... if instruction.operation.name == "Evolution":
... print(sorted(instruction.operation.operator.get_support()))
[0, 1, 6, 7]
[0, 1, 28, 29]
[4, 13, 55]
[13, 20, 40, 41]
[0, 1, 28, 29]
// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions, which we therefore also cannot transpile
// via this API.
Wala sa mga excitation na nakuha nang walang pag-filter ang humahawak sa occupied set (0-6 at 28-34), kaya wala sa mga ito ang makapaglilipat ng particle sa pagitan ng occupied at unoccupied na mode. Sa pag-filter, lahat ng lima ay tinanggihan at pinalitan ng mga excitation na nag-uugnay nga ng occupied na mode sa unoccupied na mode. Halimbawa, ang unang tinanggap na excitation na [0, 1, 6, 7] ay naglilipat ng particle sa pagitan ng mga occupied na mode na 0, 1, at 6 at ng unoccupied na mode na 7.
Kapag natanggap ang isang excitation, ang bawat mode sa support nito ay nagiging “uncertain” at, kaya, puwedeng gumanap ng alinmang papel para sa mga susunod na sample, kaya patuloy na lumalaki ang mga set ng occupied at unoccupied na mode habang mas maraming excitation ang natatanggap. Ito ang dahilan kung bakit katanggap-tanggap ang ikalawang excitation, [0, 1, 28, 29]. Ang lahat ng apat nitong mode ay kabilang sa mga orihinal na occupied, kaya hindi ito nag-uugnay sa anumang orihinal na unoccupied na mode. Tinanggap lang ito dahil naging uncertain ang mga mode na 0 at 1 (kaya puwede nang maging “unoccupied” na panig ng coupling) nang mahawakan sila ng unang excitation.
Ang paglaking ito ang dahilan kung bakit over-approximation ang rule at hindi isang test: habang mas maraming mode ang nagiging uncertain, mas kaunting draw ang tinatanggihan, at ang pag-filter ang may pinakamalaking epekto sa sampling distribution sa mga pinakaunang draw.
Para masukat kung gaano kalayo ang nailipat ng pag-filter sa distribusyon, basahin ang mga rejection count na itinatala ng pass sa circuit metadata. Isang entry ang iniimbak kada na-filter na Evolution gate, at ang ratio ng tinanggap sa kabuuan ay tumatantiya sa acceptance probability, na siyang salik kung saan na-over-weight ang mga natirang excitation:
- PYTHON
- C
>>> # a freshly seeded pass, so the counts do not depend on earlier draws
>>> qdrift_counted = QDriftTrotterization(
... FermionicQDrift(num_groups, rng=3480)
... )
>>> filtered = FermionicPassManager(qdrift_counted).run(hf_circ)
>>> discarded = filtered.metadata.get("filter_trivial.discarded")
>>> emitted = filtered.metadata.get("filter_trivial.emitted")
>>> print(f"{emitted[0]} kept, {discarded[0]} discarded")
5 kept, 7 discarded
>>> print(f"acceptance probability: {emitted[0] / (emitted[0] + discarded[0]):.2f}")
acceptance probability: 0.42
// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions, which we therefore also cannot transpile
// via this API.
Kailangan ng pag-filter ng occupation information na pagbabatayan. Ang PrepareSlaterDeterminant gate ay nagbibigay nito gaya ng InitializeModes, at minamarkahan ng anumang OrbitalRotation ang bawat mode na kinikilos nito bilang “uncertain”. Kung wala ni isa sa mga ito, o kapag ang lahat ng seeded na mode ay napunta sa isang panig (lahat occupied, o lahat unoccupied), maglalabas ang pass ng UserWarning at iiwang hindi na-filter ang sampling para sa Evolution gate na iyon. Sa Hamiltonian na ang natitirang mga term ay hindi na makapag-uugnay sa dalawang tracked set, ang pass ay magtataas na lang ng RuntimeError pagkatapos ng magkakasunod na pagtanggi na umabot sa QDriftTrotterization.MAX_SAMPLE_RETRIES.
(Opsyonal) I-precompute ang mga sampling weight
Gamitin lang ito kung ang transpilation mismo ang bottleneck. Wala itong binabago sa mga circuit na makukuha mo.
Kinukuha ng FermionicQDrift ang bawat group na may probabilidad na proporsyonal sa laki ng coefficient nito, at kinukuha ang mga laki na iyon mula sa Hamiltonian sa bawat tawag: isang halaga kada term ng Hamiltonian, na binabawasan hanggang isa kada group. Dahil stateless ang method, inuulit nito ang reduction na iyon sa bawat randomization, kahit pareho ang resulta tuwing gagawin. Hinahayaan ka ng argumentong weights na i-compute ito nang isang beses gamit ang group_coeff_means() at ipasa ang resulta, na inilalabas ang gastos sa loop habang walang naka-cache na state na nakadepende sa Hamiltonian ang method.
Ito ang katapat ng term ordering sa step 2. Inilalabas niyon ang group lookup sa loop, ito naman ang weight reduction, at kapansin-pansin ang bawat isa ayon lang sa kawalan ng isa pa, kaya sulit na ilapat ang dalawa nang magkasama. Dahil ang canon ay na-reorder na sa itaas, direkta silang nagkakasundo.
Ang mga weight ay naglalarawan sa mga group ng isang partikular na operator, kaya kabilang sila sa Evolution gate ng operator na iyon: buuin ang method para sa gate na iyon at ipasa ito bilang synthesis ng gate, gaya mismo sa step 3.
- PYTHON
- C
>>> from qiskit_fermions.operators.terms.grouping import group_coeff_means
>>>
>>> weights = group_coeff_means(canon) # `canon` is group-ordered, from step 2
>>> qdrift_weighted = FermionicQDrift(10, rng=19, weights=weights)
>>> weighted_gate = Evolution(num_modes, canon, time, synthesis=qdrift_weighted)
>>>
>>> weighted_circ = FermionicCircuit(num_modes)
>>> weighted_circ.append(weighted_gate, weighted_circ.modes)
>>>
>>> weighted_circuits = [
... pm.run(weighted_circ) for _ in range(num_sqdrift_randomizations)
... ]
>>> len(weighted_circuits)
10
// WARNING: Qiskit's C API does not yet allow us to implement circuits
// with custom gate definitions, which we therefore also cannot transpile
// via this API.
Dahil ito mismo ang mga weight na ico-compute ng pass, pareho ang mga circuit sa dati; ang paulit-ulit na reduction lang ang nawala.
Isang entry ang inaasahan kada group, hindi kada term, tuwing may mga group ang operator, dahil ang grouped na operator ay sinasample kada group. Dapat hindi negatibo ang mga entry: ang weight ay isang magnitude, dahil dinedecompose ng qDRIFT protocol ang na may positibong , at ang sign ng coefficient ay kabilang sa , kung saan direktang binabasa ito ng pass mula sa operator.
Ang mga weight ay absolute magnitude, hindi relatibong kagustuhan. Ang kabuuan nila ang nagtatakda rin ng evolution time, kaya ang pagpaparami ng bawat entry sa ay pareho ang sampling pero nag-e-evolve ng sa halip na . Kaya ang pagpasa ng anumang bukod sa sariling coefficient magnitude ng Hamiltonian ay nagbabago kung aling evolution ang tinatantiya ng ensemble, kaya isa itong performance tool at hindi paraan para i-tune ang sampling.
Dahil ang mga weight ay kabilang sa gate na ang operator ay inilalarawan nila, ang isang circuit ay maaaring may ilang Evolution gate, bawat isa ay may mga weight ng sarili nitong operator. Ang pass na QDriftTrotterization ng step 5 ay sumusunod din dito sa parehong paraan: kumukuha ito ng gate gamit ang FermionicQDrift na dala ng gate, at bumabalik sa ginamit sa pagkakabuo nito para sa mga gate na walang dala. Ang ibang uri ng synthesis method sa isang gate ay hindi pahayag tungkol sa qDRIFT, kaya hindi ito pinapansin ng pass. Ang pagbibigay ng method sa pass ayon sa pangalan ng gate, tulad ng sa F2FSynthesis({"Evolution": ...}), ay nagpapatupad ng isang method sa bawat Evolution gate, kaya ang mga weight na ipinasa roon ay makabuluhan lang para sa circuit na may iisa lang. Sinusuri ang haba ng mga weight laban sa bawat gate na pinaglalapatan nila.
(Opsyonal) I-optimize ang fermionic mode indexing
Maaari kang magdagdag ng karagdagang optimization step sa transpilation pipeline na nagpapaliit sa distansya ng mga fermionic excitation span sa pamamagitan ng pag-relabel ng mga fermionic mode index. Ipinakilala ang optimization na ito sa paper na SqDRIFT at ipinapatupad ng build_excitation_span_minimization_model(). Madali itong maisingit sa transpiler pipeline gamit ang pass na RelabelModes:
- PYTHON
- C
>>> from pyomo.environ import SolverFactory
>>> from qiskit_fermions.transpiler.passes import RelabelModes
>>>
>>> solver = SolverFactory("appsi_highs")
>>> solver.options["time_limit"] = 10
>>>
>>> qdrift = F2FSynthesis({"Evolution": FermionicQDrift(5, rng=19)})
>>> relabel = RelabelModes(solver=solver)
>>>
>>> pm.optimization = FermionicPassManager([qdrift, relabel])
>>>
>>> relabeled_circ = pm.run(circ)
>>> # if the automatic mode relabeling was successful, the circuit's
>>> # metadata will contain the mode `permutation` information
// WARNING: This feature is not available via the C API.
Ang paggamit ng awtomatikong optimization sa loob ng RelabelModes (na gumagamit ng build_excitation_span_minimization_model()) ay nangangailangan ng opsyonal na dependency na pinamamahalaan ng HAS_PYOMO.
Binabago ng relabeling kung aling mode ang dala ng isang qubit, kaya makukuha lang ng subspace diagonalization ang tamang mga bitstring kung isasaalang-alang ito. Nakadepende kung saan ito isinasaalang-alang sa kung saan ka sumusukat.
Idagdag ang mga measurement sa FermionicCircuit gamit ang FermionicCircuit.measure_all() bago mag-transpile, at wala nang ibang gagawin: pinangalanan ng bawat measurement ang mode na binabasa nito, kaya dala ito ng relabeling at ang mga na-sample na bitstring ay naka-index ayon sa orihinal na mode.
Kung ang na-transpile na QuantumCircuit ang susukatin mo, kailangang i-post-process ang mga bitstring gamit ang permutation na naitala sa metadata ng circuit. Tingnan ang dokumentasyon ng RelabelModes para sa recipe.
Mga susunod na hakbang
Ngayong matagumpay ka nang nakagawa ng ensemble ng mga circuit, maaari ka nang mag-sample ng mga bitstring mula sa mga ito. Para magawa iyon, kailangang i-execute ang mga circuit sa hardware. Tingnan ang Qiskit documentation para sa detalyadong tagubilin.
Kapag nakuha na ang mga bitstring sample, maaari itong gamitin kasama ng mga coefficient ng Hamiltonian para magsagawa ng SQD post-processing, gaya ng ipinaliwanag sa SQD addon tutorials.