ข้ามไปยังเนื้อหาหลัก
โครงการนี้อยู่ในช่วงเบต้า พบข้อผิดพลาด? สร้าง GitHub Issue มีคำถามหรือไอเดีย? ถามใน Discussions — ยินดีรับฟังความคิดเห็น!
คุณภาพการแปลในหน้านี้เป็นอย่างไร?

ทรานสไพล์ LUCJ ansatz

สำคัญ

แนวคิดในคู่มือนี้ใช้ได้เฉพาะใน Python API เท่านั้น

ansatz local unitary cluster Jastrow (LUCJ) เป็นการกำหนดพารามิเตอร์ที่กะทัดรัดและมีประสิทธิภาพต่อฮาร์ดแวร์ของฟังก์ชันคลื่นอิเล็กตรอนที่มีสหสัมพันธ์ เป็นสมาชิกของตระกูล unitary cluster Jastrow (UCJ) ทั่วไป และมีรูปแบบ

∣Ψ⟩=(∏k=1LUk eiJk Uk†)∣Φ0⟩,\lvert \Psi \rangle = \left(\prod_{k=1}^{L} \mathcal{U}_k\, e^{i \mathcal{J}_k}\, \mathcal{U}_k^\dagger\right) \lvert \Phi_0 \rangle,

โดยที่ ∣Φ0⟩\lvert \Phi_0 \rangle คือสถานะอ้างอิง (โดยทั่วไปคือ Hartree-Fock) แต่ละ Uk\mathcal{U}_k คือการหมุนออร์บิทัล และแต่ละ Jk\mathcal{J}_k คือตัวดำเนินการคูลอมบ์แนวทแยง

J=12∑ij,στJijστ niσ njτ,\mathcal{J} = \frac12 \sum_{ij,\sigma\tau} \mathbf{J}^{\sigma\tau}_{ij}\, n_{i\sigma}\, n_{j\tau},

โดย niσn_{i\sigma} คือตัวดำเนินการจำนวนบนออร์บิทัลเชิงพื้นที่ ii ที่มีสปิน σ\sigma

ffsim สร้างตัวดำเนินการ ansatz ส่วนแพ็กเกจนี้เปลี่ยนมันเป็น Circuit และลดระดับ Circuit นั้นลงสู่คิวบิต คู่มือนี้พูดถึงครึ่งหลังของประโยคนั้น เหตุผลที่ต้องเดินทางนี้คือการลดระดับนั่นเอง: Gate ของ Qiskit ที่มากับ ffsim เฉพาะเจาะจงกับการแปลง Jordan-Wigner ในขณะที่ FermionicCircuit ไม่มีข้อสมมติเกี่ยวกับการเข้ารหัสเฟอร์มิออนเป็นคิวบิต ดังนั้น ansatz เดียวกันจึงสังเคราะห์ผ่านการเข้ารหัสใดก็ได้ที่เหมาะกับอุปกรณ์เป้าหมาย

ดังนั้นตัวดำเนินการ ansatz จึงมาถึงที่นี่แบบพร้อมใช้ และทุกอย่างด้านล่างคือสิ่งที่เกิดกับมันหลังจากนั้น: Gate แตกออกเป็นอะไร ลดระดับผ่าน Jordan-Wigner อย่างไร จับคู่กับแผนผังการเชื่อมต่อของอุปกรณ์อย่างไร และการลดระดับที่ไม่ใช่ Jordan-Wigner ยังต้องการอะไรอีก สำหรับการสร้าง กำหนดพารามิเตอร์ หรือจำลอง UCJ ansatz ตั้งแต่แรก ดูคู่มือของ ffsim เอง

ดูเพิ่มเติม

คู่มือความสัมพันธ์กับ ffsim สำหรับวิธีที่สองแพ็กเกจแบ่งงานกัน และคู่มือ transpilation สำหรับขั้นตอนไปป์ไลน์ที่ใช้ด้านล่าง

1. รับตัวดำเนินการ LUCJ จาก ffsim​

ansatz ถูกเริ่มต้นจากแอมพลิจูดของการคำนวณ coupled-cluster singles and doubles (CCSD) รัน restricted Hartree-Fock ตามด้วย CCSD สำหรับโมเลกุลไฮโดรเจนในเบซิส 6-31g โดยใช้ PySCF สำหรับเคมีควอนตัม แล้วส่งแอมพลิจูดให้ from_t_amplitudes() ของ ffsim ซึ่งทำ double factorization ของแอมพลิจูด t2t_2 เพื่อให้ได้เมทริกซ์คูลอมบ์แนวทแยงและการหมุนออร์บิทัลของแต่ละชั้น และหาการหมุนออร์บิทัลสุดท้ายแบบเลือกได้จากแอมพลิจูด t1t_1 จำนวนการทำซ้ำ LL คือสิ่งที่การแยกตัวประกอบนั้นให้ออกมา; n_reps ตัดทอนจำนวนนั้น โดยแลกความแม่นยำกับ Circuit ที่ตื้นกว่า

>>> import ffsim
>>> import pyscf
>>> import pyscf.cc
>>>
>>> # build the molecule and run Hartree-Fock
>>> mol = pyscf.gto.Mole()
>>> mol.build(
... atom=[["H", (0, 0, 0)], ["H", (0, 0, 0.74)]],
... basis="6-31g",
... symmetry="Dooh",
... verbose=0,
... )
<pyscf.gto.mole.Mole object at ...>
>>> scf = pyscf.scf.RHF(mol).run()
>>>
>>> norb = scf.mo_coeff.shape[1]
>>> nelec = (mol.nelec[0], mol.nelec[1])
>>>
>>> # run CCSD for the t-amplitudes, then factorize them into an ansatz operator
>>> ccsd = pyscf.cc.CCSD(scf).run()
>>> t1, t2 = ccsd.t1, ccsd.t2
>>>
>>> ucj_op = ffsim.UCJOpSpinBalanced.from_t_amplitudes(t2, t1=t1, n_reps=2)

นี่คือจุดที่ ansatz ไม่ใช่เรื่องของ ffsim อีกต่อไป ffsim มีตัวเลือกที่แพ็กเกจนี้ไม่เห็นและไม่จำเป็นต้องรู้ เช่น การแยกตัวประกอบแบบ (“บีบอัด”) ที่ปรับให้เหมาะสมแบบแปรผันเบื้องหลัง optimize=True หรือการจัดเรียงเวกเตอร์พารามิเตอร์ที่ตัวปรับให้เหมาะสมแบบแปรผันใช้ขับเคลื่อน ทั้งหมดให้ตัวดำเนินการชนิดเดียวกัน และทุกอย่างด้านล่างใช้ได้โดยไม่ต้องเปลี่ยนกับทุกตัว

2. เปลี่ยนตัวดำเนินการเป็น fermionic circuit​

Gate UCJ ห่อหุ้มตัวดำเนินการและแสดงเป็น Circuit บน โหมดเฟอร์มิออน Gate นี้เป็นยูนิทารีล้วนที่ไม่มีสถานะอ้างอิงในตัว ดังนั้นให้เติม Gate InitializeModes (สร้างด้วย from_hartree_fock()) ไว้ข้างหน้า เพื่อให้สถานะอ้างอิง Hartree-Fock ที่ ansatz กระทำกับ

>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import InitializeModes, UCJ
>>>
>>> ansatz = UCJ(ucj_op)
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(InitializeModes.from_hartree_fock(norb, nelec), circuit.modes)
>>> circuit.append(ansatz, circuit.modes)

การแยก Circuit ออกจะเผยให้เห็นโครงสร้างของมัน และนี่คือการแทนค่าที่ส่วนที่เหลือของคู่มือใช้ Gate InitializeModes เตรียมดีเทอร์มิแนนต์อ้างอิง และแต่ละชั้นของ ansatz ประกอบด้วย OrbitalRotation Uk†\mathcal{U}_k^\dagger จากนั้น eiJke^{i\mathcal{J}_k} (คือ Evolution ของตัวดำเนินการคูลอมบ์แนวทแยง Jk\mathcal{J}_k) แล้วจึง Uk\mathcal{U}_k โดยมี OrbitalRotation สุดท้ายอยู่ท้ายสุด การหมุนออร์บิทัลกระทำแยกตามเซกเตอร์สปิน ดังนั้นแต่ละอันจึงวางบนโหมดอัลฟา 0..norb และโหมดเบตา norb..2*norb อย่างอิสระ

>>> circuit.decompose().draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

The gates that the UCJ ansatz decomposes into.

ทุก Gate ในการแยกส่วนนั้นยังเป็นเฟอร์มิออน: OrbitalRotation และ Evolution ถูกนิยามบนโหมด และยังไม่มีคิวบิตหรือตัวดำเนินการ Pauli ปรากฏ นั่นคือสิ่งที่ทำให้การเข้ารหัสยังเปิดอยู่ และเป็นสถานะที่ ansatz คงอยู่จนกว่าขั้นตอนการสังเคราะห์จะเลือกการเข้ารหัส

หมายเหตุ

แต่ละชั้นจบด้วย Uk\mathcal{U}_k และชั้นถัดไปเริ่มด้วย Uk+1†\mathcal{U}_{k+1}^\dagger ดังนั้น Gate OrbitalRotation ที่อยู่ติดกันสามารถรวมเป็นการหมุนเดียวได้ Pass การทรานสไพล์ที่ทำการรวมนี้อยู่ในแผนพัฒนาในอนาคต

3. เลือกการเข้ารหัสเฟอร์มิออนเป็นคิวบิต​

Circuit ยังเป็นเฟอร์มิออน และนั่นคือจุดที่แพ็กเกจนี้พิสูจน์คุณค่าในเวิร์กโฟลว์ FermionicCircuit ไม่มีข้อสมมติว่าโหมดกลายเป็นคิวบิตอย่างไร ดังนั้นการเข้ารหัสจึงเป็นตัวเลือกใน ขั้นสังเคราะห์ ไม่ใช่สิ่งที่ฝังอยู่ใน ansatz นั่นคือสิ่งที่แพ็กเกจนี้เพิ่มจาก Gate ของ Qiskit ที่มากับ ffsim ซึ่งเฉพาะเจาะจงกับการแปลง Jordan-Wigner

ถ้าใช้ Jordan-Wigner อย่างเดียว คุณไม่จำเป็นต้องอ้อมทางนี้: ffsim มี UCJOpSpinBalancedJW และคลาสพี่น้อง ซึ่งแปลงตัวดำเนินการ UCJ เป็น Circuit คิวบิตได้เอง เหตุผลที่ควรส่ง ansatz ผ่าน fermionic circuit คือทุกอย่าง อื่น ที่การเข้ารหัสให้คุณได้ เช่น การเข้ารหัสแบบเฉพาะที่ ใช้คิวบิตเพิ่มเพื่อจำกัดน้ำหนัก Pauli ของแต่ละเทอม ซึ่งคู่มือ flow-set แบบ 1D และ 2D ใช้เพื่อให้ความลึกสองคิวบิตของแต่ละขั้น Trotter ไม่ขึ้นกับขนาดของระบบ

สำหรับ UCJ ansatz โดยเฉพาะ ขั้นสังเคราะห์ต้องครอบคลุม Gate สองชนิด:

  • วิวัฒนาการคูลอมบ์แนวทแยง Evolution ไม่ขึ้นกับการเข้ารหัสอยู่แล้ว: MapperFnEvolutionSynthesis รับฟังก์ชัน mapper ดังนั้นชั้น eiJke^{i \mathcal{J}_k} จึงลดระดับผ่านการเข้ารหัสใดก็ได้ที่คุณเขียนเป็นฟังก์ชันนั้นได้ คู่มือ flow-set แสดงวิธีเขียน

  • การหมุนออร์บิทัลและการเตรียม Slater-determinant ทั้ง OrbitalRotation และ PrepareSlaterDeterminant ที่ InitializeModes ตัวแรกและการหมุนรวมเข้าด้วยกัน (ดูด้านล่าง) ไม่ถูกแมปเป็นคิวบิตโดยตรง Pass F2FSynthesis จะแยกมันออกก่อน ในปริภูมิเฟอร์มิออน เป็น Gate Evolution บนหนึ่งหรือสองโหมดต่อ Gate (และสำหรับการเตรียม จะมี InitializeModes ของสถานะอ้างอิงด้วย) ดังนั้นการเข้ารหัสใดที่แมป Evolution ได้ก็จัดการมันได้ ภายใต้ Jordan-Wigner ตัวประกอบระหว่างโหมดที่อยู่ติดกันจะกลายเป็นออบเจกต์ XXPlusYYGateobjects ในขั้นคิวบิต

  • การเริ่มต้นสถานะ ปลั๊กอินสำหรับ InitializeModes ไม่ได้กำหนดพารามิเตอร์ด้วยการเข้ารหัส: มันระบุไว้ว่าสมมติการเข้ารหัสบนเบซิสการครอบครองที่แมปโหมดต่อคิวบิตแบบ 1 ต่อ 1 และปล่อย Gate โดยตรงบนเบซิสนั้น การเข้ารหัสอื่นต้องมีปลั๊กอินของตัวเอง และตอนนี้ยังไม่มี

วิธีทรานสไพล์ Circuit UCJ ภายใต้การเข้ารหัสที่ไม่ใช่ Jordan-Wigner ยังเป็นคำถามวิจัยที่เปิดอยู่ และแพ็กเกจนี้ให้กรอบสำหรับพัฒนาไปป์ไลน์ดังกล่าว ส่วนที่เหลือของคู่มือนี้สร้างไปป์ไลน์ทรานสไพล์สำหรับการเข้ารหัส Jordan-Wigner ซึ่งเทียบเท่ากับที่ generate_preset_jw_pass_manager() สร้าง เป็นตัวอย่าง

4. ลดระดับผ่าน Jordan-Wigner​

การลดระดับเกิดใน F2QSynthesis ซึ่งทำงานคล้าย HighLevelSynthesis ของ Qiskit: มันไล่ดูคำสั่งเฟอร์มิออนและส่งแต่ละคำสั่งให้ปลั๊กอินที่ลงทะเบียนสำหรับชื่อ Gate นั้น แอตทริบิวต์ F2QSynthesis.methods เก็บ F2QSynthesisPlugin หนึ่งตัวต่อชื่อ Gate ดังนั้นการสร้างขั้นตอนนี้จึงหมายถึงการเลือกปลั๊กอินสำหรับทุก Gate เฟอร์มิออนที่ Circuit มี:

>>> from qiskit_fermions.mappers.library import jordan_wigner
>>> from qiskit_fermions.transpiler.passes import F2QSynthesis
>>> from qiskit_fermions.transpiler.passes.synthesis import (
... MapperFnEvolutionSynthesis,
... TrivialOccupationInitializeModesSynthesis,
... )
>>>
>>> synthesis = F2QSynthesis()
>>> synthesis.methods["Evolution"] = MapperFnEvolutionSynthesis(jordan_wigner)
>>> synthesis.methods["InitializeModes"] = TrivialOccupationInitializeModesSynthesis()

การกำหนดอินสแตนซ์แบบนี้ยังเป็นวิธีที่ปลั๊กอินที่คุณเขียนเองเข้าสู่ไปป์ไลน์ได้ โดยไม่ต้องลงทะเบียนที่ไหนก่อน

นี่คือจุดที่การเข้ารหัสถูกตัดสิน ตามสองวิธีที่ส่วนที่ 3 อธิบายไว้: แบบชัดเจน โดยส่ง jordan_wigner() ให้ MapperFnEvolutionSynthesis และแบบโดยนัย โดยปลั๊กอินอีกตัวสมมติมันอยู่แล้ว

จากนั้นขั้นตอนนั้นจะเสียบเข้า MultiStagePassManager ซึ่งขั้นตอนต่างๆ ทำงานตามลำดับคงที่:

>>> from qiskit.passmanager import MultiStagePassManager
>>> from qiskit.transpiler import generate_preset_pass_manager
>>> from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig
>>>
>>> from qiskit_fermions.transpiler import (
... FermionicCircuitToDAG,
... FermionicPassManager,
... QuantumDAGToCircuit,
... )
>>> from qiskit_fermions.transpiler.passes import (
... F2FSynthesis,
... HopEvolutionSynthesis,
... MergeOrbitalRotations,
... MergeSlaterDeterminantPreparation,
... TrivialF2QLayout,
... )
>>>
>>> pm = MultiStagePassManager(
... input=FermionicCircuitToDAG(),
... optimization=FermionicPassManager(
... [
... MergeOrbitalRotations(),
... MergeSlaterDeterminantPreparation(),
... F2FSynthesis(
... {"OrbitalRotation": "Givens", "PrepareSlaterDeterminant": "Givens"}
... ),
... ]
... ),
... layout=FermionicPassManager(TrivialF2QLayout()),
... synthesis=synthesis,
... qubit=generate_preset_pass_manager(
... hls_config=HLSConfig(PauliEvolution=[HopEvolutionSynthesis(), "default"])
... ),
... output=QuantumDAGToCircuit(),
... )

ขั้น optimization ทำงาน ก่อน การสังเคราะห์ บน fermionic circuit ซึ่งทำให้มีค่า: มันเขียน Gate ใหม่ขณะที่ยังเป็นเฟอร์มิออนและไม่ขึ้นกับการเข้ารหัส ดังนั้นสิ่งที่ประหยัดได้จะส่งต่อไปถึงการเข้ารหัสใดๆ ที่ตามมา MergeOrbitalRotations ยุบแต่ละช่วงของ Gate OrbitalRotation ที่ต่อเนื่องกันให้เหลือหนึ่งตัว ซึ่งสำคัญสำหรับ UCJ ansatz เพราะทุกชั้นจบด้วย Uk\mathcal{U}_k และชั้นถัดไปเริ่มด้วย Uk+1†\mathcal{U}_{k+1}^\dagger จากนั้น MergeSlaterDeterminantPreparation รวม InitializeModes ตัวแรกกับการหมุนที่ตามมาเป็น PrepareSlaterDeterminant ตัวเดียว ซึ่งการสังเคราะห์ลดระดับผ่านการแยกส่วน Slater แบบลดรูปที่ถูกกว่า แทนที่จะเป็นการหมุนสี่เหลี่ยมเต็มรูป ลำดับสำคัญ: การรวมการหมุนก่อนจะเผยการหมุนเดี่ยวที่อยู่ถัดจากการเริ่มต้นสถานะทันที ซึ่งการรวม Slater จะดูดเข้าไป F2FSynthesis มาท้ายสุด เพราะมันแตกการหมุนที่เหลืออยู่ และถ้าทำเร็วกว่านี้ Pass การรวมทั้งสองจะไม่มีอะไรให้รวม

ขั้นตอนที่เหลือเป็นงานท่อ input และ output แปลงระหว่าง Circuit กับ DAG, layout กำหนดโหมดเฟอร์มิออนให้คิวบิต (TrivialF2QLayout แมปโหมด i ไปคิวบิต i) และ qubit คือ pass manager ของ Qiskit ปกติที่เข้ามารับช่วงเมื่อไม่เหลืออะไรที่เป็นเฟอร์มิออน

การรันต้องมีขั้นเตรียมการหนึ่งอย่าง: Gate UCJ แบบประกอบต้องถูกแยกเป็น Gate พื้นฐานก่อน เพื่อให้ขั้น optimization เห็นการหมุนและวิวัฒนาการแต่ละตัว

>>> transpiled = pm.run(circuit.decompose())
>>> print(dict(sorted(transpiled.count_ops().items())))
{'rz': 14, 'rzz': 12, 'x': 2, 'xx_plus_yy': 28}

เมื่อไม่มีอุปกรณ์เป้าหมาย จะแมปลงบนคิวบิต 2 * norb ตัวโดยสมมติการเชื่อมต่อแบบทุกตัวถึงทุกตัว การหมุนออร์บิทัลสังเคราะห์เป็นออบเจกต์ XXPlusYYGateobjects และวิวัฒนาการคูลอมบ์แนวทแยงเป็นออบเจกต์ RZZGateobjects:

>>> transpiled.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

The Jordan-Wigner transpiled LUCJ circuit.

ไปป์ไลน์นี้ตรงกับที่ generate_preset_jw_pass_manager() ประกอบขึ้นทุกประการ ดังนั้นในทางปฏิบัติให้ใช้ preset และสร้างขั้นตอนด้วยมือเมื่อต้องเปลี่ยนขั้นใดขั้นหนึ่ง:

>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>>
>>> preset = generate_preset_jw_pass_manager()
>>> preset.run(circuit.decompose()).count_ops() == transpiled.count_ops()
True

5. จับคู่กับโทโพโลยีของอุปกรณ์​

อุปกรณ์จริงมีแผนผังการเชื่อมต่อคิวบิตที่จำกัด และ LUCJ ansatz ถูกออกแบบให้ตรงกับมัน อันตรกิริยาสปินเดียวกัน (pairs_aa) สร้างโซ่เชิงเส้นสองสาย และอันตรกิริยาอัลฟา-เบตา (pairs_ab) เชื่อมสองสายเข้าด้วยกัน generate_lucj_pass_manager() ของ ffsim สร้างไปป์ไลน์คิวบิตที่รับรู้อุปกรณ์สำหรับโครงสร้างนี้ และคืนเซตย่อยของ pairs_ab ที่ฮาร์ดแวร์รองรับได้จริง เสียบไปป์ไลน์นั้นเข้าขั้น qubit ของ preset โดยคงการสังเคราะห์เฟอร์มิออนเป็นคิวบิตของแพ็กเกจนี้ไว้:

>>> from ffsim.qiskit import generate_lucj_pass_manager
>>> from qiskit.providers.fake_provider import GenericBackendV2
>>> from qiskit.transpiler import CouplingMap
>>>
>>> # a heavy-hex device coupling map (any BackendV2 works, e.g. a real fake_provider backend)
>>> coupling_map = CouplingMap.from_heavy_hex(5)
>>> backend = GenericBackendV2(
... num_qubits=coupling_map.size(),
... basis_gates=["cp", "xx_plus_yy", "p", "x", "swap"],
... coupling_map=coupling_map,
... )
>>>
>>> # nearest-neighbor same-spin chain; let the pass manager choose the alpha-beta pairs
>>> pairs_aa = [(p, p + 1) for p in range(norb - 1)]
>>>
>>> pm = generate_preset_jw_pass_manager()
>>> hls_config = HLSConfig(PauliEvolution=[HopEvolutionSynthesis(), "default"])
>>> pm.qubit, allowed_pairs_ab = generate_lucj_pass_manager(
... backend,
... norb,
... "heavy-hex",
... (pairs_aa, None),
... optimization_level=3,
... seed_transpiler=0,
... hls_config=hls_config,
... )
>>>
>>> # the alpha-beta interactions the heavy-hex connectivity can implement
>>> print(allowed_pairs_ab)
[(0, 0)]

การประกอบนั้นคือจุดสำคัญ: ขั้น qubit รับรู้อุปกรณ์ ในขณะที่ขั้นสังเคราะห์เฟอร์มิออนเป็นคิวบิตที่อยู่ก่อนหน้ายังเป็นของแพ็กเกจนี้เอง จึงยังเปลี่ยนได้ การแทนที่ขั้น qubit จะทิ้งสิ่งที่ preset ลงทะเบียนไว้ตรงนั้น คือ HopEvolutionSynthesis ที่เปลี่ยนตัวประกอบ Givens ของการหมุนออร์บิทัลเป็นออบเจกต์ XXPlusYYGateobjects ให้ส่งมันต่อผ่าน hls_config ดังข้างต้น ไม่เช่นนั้นต้องไปถึง basis ของอุปกรณ์โดยไม่มีมัน

เมื่อ pm.qubit ถูกตั้งเป็นไปป์ไลน์ที่รับรู้อุปกรณ์แล้ว การรัน pass manager จะวาง Circuit บนคิวบิตของ Backend และกำหนดเส้นทางไปยังแผนผังการเชื่อมต่อ สำหรับ ansatz ที่ไม่จำกัด จากขั้นที่ 1 ซึ่งตัวดำเนินการคูลอมบ์แนวทแยงยังมีเทอมอัลฟา-เบตาที่ฮาร์ดแวร์เข้าถึงโดยตรงไม่ได้ ตัวกำหนดเส้นทางต้องแทรก Gate SWAP จำนวนมากเพื่อเชื่อมมัน:

>>> naive = pm.run(circuit.decompose())
>>> naive.num_qubits # laid out on the full heavy-hex device register
57
>>> naive_swaps = naive.count_ops()["swap"]
>>> naive_swaps # many SWAPs to bridge the unreachable alpha-beta interactions
33

จำกัด ansatz ให้เหลือเฉพาะอันตรกิริยาที่ฮาร์ดแวร์ทำได้

วิธีแก้คือส่ง allowed_pairs_ab กลับเข้าสู่การสร้าง ansatz ผ่านอาร์กิวเมนต์ interaction_pairs ของ from_t_amplitudes() เพื่อให้ตัวดำเนินการคูลอมบ์แนวทแยงมีเฉพาะเทอมอัลฟา-เบตาที่แผนผังการเชื่อมต่อทำได้โดยตรง ansatz จึงตรงกับโทโพโลยีของอุปกรณ์ และตัวกำหนดเส้นทางแทบไม่ต้องแตะมัน:

>>> restricted = UCJ(
... ffsim.UCJOpSpinBalanced.from_t_amplitudes(
... t2, t1=t1, n_reps=2, interaction_pairs=(pairs_aa, allowed_pairs_ab)
... )
... )
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(InitializeModes.from_hartree_fock(norb, nelec), circuit.modes)
>>> circuit.append(restricted, circuit.modes)
>>>
>>> transpiled = pm.run(circuit.decompose())
>>> restricted_swaps = transpiled.count_ops()["swap"]
>>> restricted_swaps # far fewer routing SWAPs than the unrestricted ansatz
4

การวาดเฉพาะคิวบิตที่ใช้งาน (idle_wires=False) แสดง Circuit ที่จำกัดอยู่ที่โซ่สปินสองสายและสะพานอัลฟา-เบตา แสดงด้วย Gate basis ของอุปกรณ์ Layout และการกำหนดเส้นทางกระจายโหมดตรรกะไปทั่วคิวบิตกายภาพของอุปกรณ์ ดังนั้นให้ส่ง wire_order ที่ได้จาก layout สุดท้ายของ Circuit (final_index_layout() แสดงคิวบิตกายภาพที่คิวบิตขาเข้าแต่ละตัวไปอยู่ ตามลำดับคิวบิตขาเข้า) เพื่อวาดสายกลับตามลำดับโหมดเดิม:

>>> wire_order = transpiled.layout.final_index_layout(filter_ancillas=False)
>>> transpiled.draw("mpl", idle_wires=False, fold=-1, wire_order=wire_order)
<Figure size ... with 1 Axes>

The hardware-restricted LUCJ circuit routed onto the heavy-hex device coupling map.

หมายเหตุ

จำนวน Gate และความลึกหลัง layout ที่แน่นอนขึ้นกับ Pass การกำหนดเส้นทาง/optimization และอุปกรณ์ที่เลือก จึงไม่ได้แสดงซ้ำที่นี่ ประเด็นสำคัญคือการออกแบบร่วมกัน: การแสดง ansatz ด้วยโซ่ pairs_aa แบบเพื่อนบ้านใกล้สุดและสะพาน pairs_ab ที่กรองตามฮาร์ดแวร์ ทำให้ Circuit ที่สังเคราะห์ใกล้เคียงโทโพโลยีของอุปกรณ์ ลดภาระการกำหนดเส้นทาง (Gate SWAP ที่แทรกเข้ามา) ดู FermionicSlaterGivensDecomposition สำหรับตัวเลือกการสังเคราะห์ที่เกี่ยวข้อง (minimize_2q_gate_count) ซึ่งแลกจำนวน Gate สองคิวบิตกับความลึกหลังกำหนดเส้นทาง

ขั้นตอนถัดไป​

  • เรียนรู้ว่า Gate แต่ละตัวทำงานอย่างไรในเอกสาร qiskit_fermions.circuit.library และคู่มือ fermionic circuit

  • สำรวจคู่มืออธิบาย operators เพื่อทำความเข้าใจวิธีสร้างตัวดำเนินการเฟอร์มิออนและแฮมิลโทเนียนโดยตรง

  • ดูว่า fermionic circuit ถูกแมปเป็นคิวบิตอย่างไรในคู่มือ transpilation

  • อ่านเอกสาร F2QSynthesis สำหรับอีกวิธีกำหนดค่าขั้นสังเคราะห์: พจนานุกรม config ที่เลือกปลั๊กอินด้วยชื่อสั้นที่ลงทะเบียนไว้ใต้เอนทรีพอยต์ qiskit_fermions.transpiler.synthesis แทนที่จะเลือกด้วยอินสแตนซ์

  • อ่านคู่มือความสัมพันธ์กับ ffsim เพื่อทำความเข้าใจว่าสองแพ็กเกจแบ่งงานกันอย่างไร และโปรโตคอลใดที่ให้ ffsim จำลอง Circuit ของแพ็กเกจนี้ได้