สังเคราะห์ Evolution gate ในปริภูมิเฟอร์มิออน
แนวคิดในคู่มือนี้ใช้ได้เฉพาะใน Python API ในตอนนี้ ฟังก์ชันการทำงานที่เทียบเท่ากันจะมีให้ใน C API ในรุ่นถัดไป
Evolution gate แทนวิวัฒนาการตามเวลา ของทั้งตัวดำเนินการ การสังเคราะห์จากเฟอร์มิออนเป็นเฟอร์มิออนจะเขียน gate นั้นใหม่เป็น FermionicCircuit ของ fermionic gate ที่เล็กลง ทั้งสองฝั่งของการเขียนใหม่ยังอยู่ในปริภูมิเฟอร์มิออน ซึ่งเป็นสิ่งที่ทำให้ต่างจากการสังเคราะห์จากเฟอร์มิออนเป็น qubit ที่ตามมา: groups ของตัวดำเนินการ (ดู จัดกลุ่มเทอมของตัวดำเนินการ: ใช้โครงสร้างของตัวดำเนินการ) ยังคงอยู่ ในขณะที่การแมปจากเฟอร์มิออนเป็น qubit คืนค่าเป็น SparseObservable ซึ่งไม่มีแนวคิดเรื่องการจัดกลุ่ม
มีตัวเลือกสองอย่างสำหรับเลือกวิธี Evolution.synthesis กำหนดวิธีให้ gate ตัวเดียว และ transpiler pass F2FSynthesis กำหนดให้ทั้ง circuit ทั้งสองรับ F2FSynthesisPlugin ซึ่งเป็นอินเทอร์เฟซที่การเขียนใหม่ลักษณะนี้ทุกแบบ implement วิธีที่แพ็กเกจนี้มีให้สำหรับ evolution ในตอนนี้เป็นสูตรผลคูณ (product formula) ซึ่งเป็นสิ่งที่ส่วนที่เหลือของคู่มือนี้ใช้: FermionicLieTrotter สำหรับสูตรอันดับหนึ่ง (ค่าเริ่มต้น) และ FermionicSuzukiTrotter สำหรับอันดับคู่ที่สูงกว่า สิ่งอื่นใดที่ implement อินเทอร์เฟซนี้เลือกใช้ได้ในแบบเดียวกัน และหัวข้อเกี่ยวกับตัวเลือกทั้งสองใช้ได้กับมันโดยไม่เปลี่ยนแปลง
ขั้นตอนจากเฟอร์มิออนเป็นเฟอร์มิออนนี้เป็นทางเลือก Evolution gate ส่งตรงไปยังขั้นตอนจากเฟอร์มิออนเป็น qubit ได้เลย ซึ่งจะแมปและสังเคราะห์ทั้ง gate ไม่ว่าจะมีกี่เทอม การแบ่งก่อนเป็นการเลือกที่ทำเพราะ gate ที่ได้ถูกลงทีละตัว หรือเพราะการแบ่งเผยโครงสร้างที่ขั้นตอนหลังใช้ประโยชน์ได้
ทั้งสองขั้นตอนประกอบกันได้ ดังนั้น evolution อาจถูกประมาณที่ระดับใดระดับหนึ่ง ทั้งสองระดับ หรือไม่ประมาณเลยก็ได้ สูตรผลคูณเป็นการประมาณ เว้นแต่ตัวประกอบของมันสลับที่กันได้ ส่วนวิธีการสังเคราะห์ไม่จำเป็นต้องประมาณเลย
การข้ามขั้นตอนนี้ไม่จำเป็นต้องหมายความว่าสูญเสียการจัดกลุ่มไปทั้งหมด การห่อ mapper ด้วย group_wise() จะแมปตัวดำเนินการทีละกลุ่มแล้วรวมผลลัพธ์ ทำให้เทอม Pauli ที่แมปแล้วมาเป็นกลุ่มแทนที่จะสลับปนกัน สูตรผลคูณฝั่ง qubit จะสังเคราะห์ตามลำดับที่ได้รับ ดังนั้นเทอมที่สลับที่กันได้และอยู่ติดกันจึงจัดตารางพร้อมกันได้
บนแฮมิลโทเนียนด้านล่าง วิธีนี้ได้ประโยชน์ด้านความลึกของ two-qubit ครบถ้วนเท่ากับการแบ่ง: 18 แทนที่จะเป็น 30 โดยจำนวน gate ไม่เปลี่ยน ความต่างอยู่ที่ ตำแหน่ง ที่โครงสร้างถูกแสดงออก การแบ่งในปริภูมิเฟอร์มิออนทำให้แต่ละกลุ่มเป็น gate แยกกัน ซึ่งทุกขั้นตอนหลังมองเห็นและดำเนินการได้ ส่วน group_wise เหลือ gate เดียวและจัดลำดับเทอมภายในมันใหม่เท่านั้น ซึ่งพอสำหรับการจัดตาราง แต่ไม่เหลืออะไรให้ fermionic pass ทำงานด้วย ใช้วิธีนี้เมื่อ evolution ต้องเป็น gate เดียว และใช้สูตรผลคูณเฟอร์มิออนในกรณีอื่น
สร้างแฮมิลโทเนียนที่จัดกลุ่ม
สูตรผลคูณทั้งสองแบ่งตัวดำเนินการเป็นตัวประกอบ และสำหรับตัวดำเนินการที่จัดกลุ่ม ตัวประกอบเหล่านั้นคือกลุ่มของมัน การจัดกลุ่มจึงเป็นตัวกำหนดทั้งต้นทุนและความแม่นยำของผลลัพธ์ ลองใช้โซ่ Fermi-Hubbard หกไซต์ที่จัดกลุ่มตามการสลับที่ของเทอม: เทอม hopping บนพันธะคู่ เทอม hopping บนพันธะคี่ และอันตรกิริยาแนวทแยง
>>> from qiskit_fermions.operators import FermionOperator, cre, ann
>>>
>>> def fermi_hubbard_chain(num_sites, tunneling, interaction):
... """A 1D Fermi-Hubbard chain grouped into even bonds, odd bonds, and the interaction."""
... terms, groups = [], []
... for offset in (0, 1):
... for j in range(offset, num_sites - 1, 2):
... terms += [
... ([cre(j), ann(j + 1)], -tunneling),
... ([cre(j + 1), ann(j)], -tunneling),
... ]
... groups += [offset, offset]
... for j in range(num_sites - 1):
... terms.append(([cre(j), ann(j), cre(j + 1), ann(j + 1)], interaction))
... groups.append(2)
... operator = FermionOperator.from_terms(terms)
... operator.groups = groups
... return operator
>>>
>>> num_sites = 6
>>> hamiltonian = fermi_hubbard_chain(num_sites, tunneling=1.0, interaction=2.0)
>>> hamiltonian.num_groups()
3
สิบห้าเทอมใน 3 กลุ่ม แต่ละกลุ่ม hopping จับคู่ทุกเทอมกับคู่สังยุคของมัน ซึ่งสำคัญ: ตัวประกอบต้องเป็นเฮอร์มิเชียนเพื่อให้เอกซ์โพเนนเชียลของมันเป็นยูนิทารี และเรื่องนี้ไม่ได้ตามมาจากการที่ผลรวมเป็นเฮอร์มิเชียน groups_are_hermitian() ตรวจสอบข้อกำหนดนี้แทนที่จะปล่อยให้ตรวจด้วยตา:
>>> from qiskit_fermions.operators.terms.grouping import groups_are_hermitian
>>>
>>> groups_are_hermitian(hamiltonian)
[True, True, True]
การแยก ออกจากคู่ของมัน จะทำให้ข้อกำหนดนี้เสีย และการปล่อยตัวดำเนินการไม่จัดกลุ่มก็มีผลเหมือนกัน เพราะทั้งสองสูตรจะแบ่งมัน ทีละเทอม และ เดี่ยว ๆ ไม่เป็นเฮอร์มิเชียน:
>>> ungrouped = fermi_hubbard_chain(num_sites, tunneling=1.0, interaction=2.0)
>>> ungrouped.groups = range(len(list(ungrouped.iter_terms()))) # one group per term
>>> all(groups_are_hermitian(ungrouped))
False
ตัวประกอบเช่นนี้เป็นตัวดำเนินการเฟอร์มิออนที่ถูกต้อง และแพ็กเกจนี้จะสร้าง gate ให้ จึงไม่มีอะไรแจ้งเตือนจนกว่าตัวดำเนินการที่แมปแล้วจะถึง PauliEvolutionGate ซึ่งต้องการสัมประสิทธิ์จริงและจะ raise ValueError: Operator contains complex coefficients, which are not supported การตรวจสอบการจัดกลุ่มล่วงหน้าเปลี่ยนความล้มเหลวที่มาช้านั้นให้เป็นคำตอบที่ได้ก่อนสร้าง circuit ใด ๆ
กำหนดวิธีบน gate หนึ่งตัว
ส่งวิธีการสังเคราะห์ให้ gate แล้ว decompose แต่ละ gate ที่มันสร้างออกมาจะกลับมาเป็น Evolution gate ของตัวเอง:
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.circuit.library.synthesis import (
... FermionicLieTrotter,
... FermionicSuzukiTrotter,
... )
>>>
>>> total_time = 1.0
>>>
>>> def factors(synthesis):
... circuit = FermionicCircuit(num_sites)
... circuit.append(
... Evolution(num_sites, hamiltonian, time=total_time, synthesis=synthesis),
... circuit.modes,
... )
... return circuit.decompose().count_ops()["Evolution"]
>>>
>>> factors(FermionicLieTrotter())
3
>>> factors(FermionicSuzukiTrotter(order=2))
5
>>> factors(FermionicSuzukiTrotter(order=2, reps=4))
17
>>> factors(FermionicSuzukiTrotter(order=2, reps=4, merge_adjacent=False))
20
อันดับหนึ่งสร้างหนึ่งตัวประกอบต่อกลุ่ม อันดับสองสร้างพาลินโดรมสมมาตร ดังนั้นสองกลุ่มนอกสุดปรากฏสองครั้ง ครั้งละครึ่งเวลา รวมเป็นห้า การทำซ้ำสี่ครั้งจะได้ยี่สิบ แต่แต่ละรอบจบด้วยกลุ่มเดียวกับที่รอบถัดไปเริ่ม gate ที่อยู่ติดกันเหล่านั้นวิวัฒนาการภายใต้ตัวดำเนินการเดียวกัน จึงถูกรวมเป็น gate เดียวด้วยเวลารวม ซึ่งประหยัดหนึ่ง gate ต่อรอยต่อ ส่ง merge_adjacent=False เพื่อคงลำดับตามตำรา ทุกอันดับแบ่งตัวดำเนินการแบบเดียวกัน สิ่งที่เปลี่ยนคือลำดับของตัวประกอบและเวลาวิวัฒนาการของมัน ไม่ใช่การแบ่งส่วน
ตัวประกอบถูกทำเครื่องหมายเป็น atomic ดังนั้นการ decompose ซ้ำจะปล่อยไว้ที่เดิมแทนที่จะแบ่งต่อ การ decompose มีจุดตรึง ซึ่งทำให้เรียก decompose() ซ้ำได้อย่างปลอดภัย
กำหนดวิธีสำหรับทั้งไปป์ไลน์
การกำหนด synthesis ต่อ gate หมายถึงต้องส่งต่อตัวเลือกผ่านทุกสิ่งที่สร้าง gate รวมถึง UCC และ UCJ ซึ่งสร้าง gate ของมันภายใน pass F2FSynthesis ใช้วิธีเดียวกับทุก Evolution ใน circuit แทน ดังนั้นเลือกครั้งเดียวสำหรับทั้งไปป์ไลน์ ตั้งค่าตามชื่อ gate เช่นเดียวกับ F2QSynthesis และ gate ที่ไม่ได้ระบุชื่อจะถูกปล่อยไว้ตามเดิม:
>>> from qiskit_fermions.transpiler import FermionicPassManager
>>> from qiskit_fermions.transpiler.passes import F2FSynthesis
>>>
>>> circuit = FermionicCircuit(num_sites)
>>> circuit.append(Evolution(num_sites, hamiltonian, time=total_time), circuit.modes)
>>>
>>> expanded = FermionicPassManager(
... F2FSynthesis({"Evolution": ("SuzukiTrotter", (), {"order": 2, "reps": 4})})
... ).run(circuit)
>>> expanded.count_ops()["Evolution"]
17
นี่คือจำนวนเดียวกับที่ decompose() ให้สำหรับวิธีนั้นข้างต้น pass MergeEvolutions ใช้การรวมแบบเดียวกันกับ gate ข้างเคียงที่ไม่ได้มาจากการสังเคราะห์เดียวกัน เช่นรอยต่อระหว่าง circuit ที่ต่อกัน pass ทำสูตรเองทั้งหมด จึงไม่ต้องมีขั้นตอนขยายแยกต่างหาก และรันซ้ำสองครั้งก็ไม่เปลี่ยนอะไร เพราะตัวประกอบที่มันสร้างเป็น atomic จึงไม่มีนิยามของตัวเอง
ส่ง apply=False เพื่อ เลือก วิธีเท่านั้น แล้วปล่อยการขยายให้สิ่งอื่นทำ เช่น Decompose ของ Qiskit (การระบุชื่อ gate เป็น Decompose("Evolution") จำกัดเฉพาะ evolution และปล่อยให้ fermionic gate อื่นใช้ synthesis plugin ของตัวเอง)
วิธีนี้มีประโยชน์เมื่อต้องการเลือกวิธีสำหรับทั้ง circuit ไว้ก่อน แล้วเลื่อนการขยายไปยังจุดที่ต้องการ เช่นเพื่อตรวจสอบ circuit ก่อน:
>>> selected = FermionicPassManager(
... F2FSynthesis({"Evolution": ("SuzukiTrotter", (), {"order": 2})}, apply=False)
... ).run(circuit)
>>> selected.count_ops()["Evolution"] # selected, not yet expanded
1
>>> selected.decompose().count_ops()["Evolution"] # expanded on demand
5
แต่ต้องระวังว่า gate ที่ไม่ได้ขยายทำอะไร: มันไปถึงขั้นตอนจากเฟอร์มิออนเป็น qubit ทั้งตัว ซึ่งถูกแมปโดยไม่ดู synthesis นี่ทำให้พลาดง่ายเมื่อเปรียบเทียบวิธี เพราะทุกวิธีให้ผลลัพธ์เหมือนกัน และการเปรียบเทียบจึงไม่ได้วัดอะไรเลยโดยไม่มีสัญญาณเตือน บนแฮมิลโทเนียนข้างต้น การปล่อย gate อันดับสองไม่ขยายทำให้ circuit ที่ใหญ่กว่ามากด้านล่างยุบเหลือต้นทุนของ evolution ที่แมปแล้วหนึ่งตัว ไม่ว่าจะเลือกวิธีใด
วัดผลตอบแทน
อันดับที่สูงกว่าต้องแลกกับความลึก ดังนั้นคำถามไม่ใช่ว่าแม่นยำกว่าหรือไม่ แต่คือแม่นยำกว่า ต่อ gate หรือไม่ ต้องใช้ตัวเลขสองตัวต่อวิธี: ความคลาดเคลื่อนของสถานะที่ได้ และต้นทุน two-qubit ของ circuit ที่สร้างมัน
ความคลาดเคลื่อนวัดด้วย ffsim ซึ่งจำลอง FermionicCircuit โดยตรง (ดู แพ็กเกจนี้เกี่ยวข้องกับ ffsim อย่างไร) ไม่มีการแมปจากเฟอร์มิออนเป็น qubit เข้ามาเกี่ยวข้อง การเปรียบเทียบจึงแยกสูตรผลคูณเฟอร์มิออนออกจากสิ่งที่การแมปหรือการสังเคราะห์ฝั่ง qubit อาจมีส่วน มันยังทำงานในเซกเตอร์จำนวนอนุภาคคงที่ ซึ่งทั้งเล็กกว่าปริภูมิเต็ม และเป็นปริภูมิที่ evolution อยู่จริง
>>> import ffsim
>>> import numpy as np
>>> from scipy.sparse.linalg import expm_multiply
>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>>
>>> norb, nelec = num_sites, (3, 0) # three spinless fermions on six modes
>>> initial = ffsim.hartree_fock_state(norb, nelec)
>>>
>>> hamiltonian_operator = ffsim.linear_operator(hamiltonian, norb=norb, nelec=nelec)
>>> exact = expm_multiply(
... -1j * total_time * hamiltonian_operator,
... initial,
... traceA=-1j * total_time * ffsim.trace(hamiltonian, norb=norb, nelec=nelec),
... )
>>>
>>> def cost_and_error(synthesis):
... circuit = FermionicCircuit(num_sites)
... circuit.append(
... Evolution(num_sites, hamiltonian, time=total_time, synthesis=synthesis),
... circuit.modes,
... )
... # the method is set on the gate, so decompose() is what expands it here; a pipeline
... # would reach for F2FSynthesis instead (see the note above)
... circuit = circuit.decompose()
... evolved = ffsim.apply_unitary(initial, circuit, norb=norb, nelec=nelec)
... error = 1 - abs(np.vdot(evolved, exact)) ** 2
... qubit_circuit = generate_preset_jw_pass_manager().run(circuit).decompose(reps=6)
... two_qubit = lambda instruction: len(instruction.qubits) == 2
... return error, qubit_circuit.count_ops()["cx"], qubit_circuit.depth(two_qubit)
>>>
>>> methods = [
... ("order 1, reps 1 ", FermionicLieTrotter()),
... ("order 2, reps 1 ", FermionicSuzukiTrotter(order=2)),
... ("order 1, reps 10", FermionicLieTrotter(reps=10)),
... ("order 2, reps 4 ", FermionicSuzukiTrotter(order=2, reps=4)),
... ]
>>> costs = {label: cost_and_error(synthesis) for label, synthesis in methods}
>>> labels, counts, depths = [], [], []
>>> for label, (error, gates, depth) in costs.items():
... labels.append(label.strip().replace(", ", "\n"))
... counts.append(gates)
... depths.append(depth)
... print(f"{label} error {error:.6f}")
order 1, reps 1 error 0.515997
order 2, reps 1 error 0.180958
order 1, reps 10 error 0.004026
order 2, reps 4 error 0.000421
ต้นทุน two-qubit ถูกเว้นจากตารางนั้นโดยตั้งใจ มันขึ้นกับการสังเคราะห์ฝั่ง qubit ที่ Qiskit เลือก ซึ่งดีขึ้นในแต่ละรุ่น ตัวเลขที่พิมพ์ที่นี่จึงเป็นเพียงภาพรวม ณ เวลาหนึ่ง ไม่ใช่คุณสมบัติของสูตรผลคูณ ภาพด้านล่างพล็อตตัวเลขเหล่านั้นแทน และสิ่งที่การเปรียบเทียบตั้งอยู่บนนั้นถูกยืนยันเป็นความสัมพันธ์:
อ่านสองวิธีสุดท้ายด้วยกัน เพราะเป็นการเปรียบเทียบที่สำคัญ อันดับสองกับสี่รอบแม่นยำกว่าอันดับหนึ่งกับสิบรอบราวสิบเท่า และทำได้ด้วย entangling gate น้อยกว่า ไม่ใช่มากกว่า ตามที่ภาพแสดง การใช้งบประมาณ gate กับอันดับที่สูงกว่าชนะการใช้กับขั้นอันดับหนึ่งที่มากขึ้นในกรณีนี้
ผลลัพธ์นั้นไม่เป็นสากล การเพิ่ม reps และการเพิ่ม order ลดความคลาดเคลื่อนในอัตราต่างกันสำหรับต้นทุนประเภทเดียวกัน และอย่างไหนชนะขึ้นอยู่กับตัวดำเนินการและเวลาที่ใช้วิวัฒนาการ สองแถวข้างต้นคือวิธีค้นหาคำตอบสำหรับปัญหาหนึ่ง ๆ
สูตรเฟอร์มิออนประกอบกับสูตรที่เลือกสำหรับขั้นตอนจากเฟอร์มิออนเป็น qubit (ดู MapperFnEvolutionSynthesis.product_formula) เมื่อทั้งสองเป็นการประมาณ ความแม่นยำของผลลัพธ์ถูกกำหนดโดยตัวที่อ่อนกว่า ดังนั้นการเพิ่มอันดับที่นี่ในขณะที่สูตรฝั่ง qubit ยังเป็นอันดับหนึ่งจึงได้ประโยชน์น้อย
จำกัด pass ให้ใช้กับ gate ที่ได้ประโยชน์
อันดับที่สูงกว่าช่วยได้เฉพาะเมื่อตัวประกอบไม่สลับที่กัน หากทั้งหมดสลับที่กันได้ สูตรอันดับหนึ่งก็แม่นยำอยู่แล้ว และตัวประกอบเพิ่มเป็นภาระเปล่า ๆ ตัวดำเนินการแนวทแยงล้วนทำให้เห็นชัด เพราะตัวดำเนินการจำนวนสลับที่กันเอง:
>>> from qiskit_fermions.transpiler.presets import generate_preset_jw_pass_manager
>>>
>>> diagonal = FermionOperator.from_terms(
... [([cre(j), ann(j), cre(j + 1), ann(j + 1)], 1.0 + 0.1 * j) for j in range(num_sites - 1)]
... )
>>> diagonal.groups = list(range(num_sites - 1))
>>>
>>> def diagonal_cost(synthesis):
... circuit = FermionicCircuit(num_sites)
... circuit.append(
... Evolution(num_sites, diagonal, time=total_time, synthesis=synthesis), circuit.modes
... )
... transpiled = generate_preset_jw_pass_manager().run(circuit.decompose())
... return transpiled.decompose(reps=6).count_ops()["cx"]
>>>
>>> diagonal_cost(FermionicLieTrotter())
10
>>> diagonal_cost(FermionicSuzukiTrotter(order=2))
18
ทั้งสอง circuit แม่นยำ ดังนั้นตัวที่สองใช้ entangling gate มากกว่า 80% โดยเปล่าประโยชน์ ตัวดำเนินการ Coulomb แนวทแยงของ UCJ มีรูปแบบนี้ ซึ่งเป็นเหตุผลที่ F2FSynthesis.filter มีอยู่: มันรับ predicate บน DAGOpNode และปล่อย gate ที่ถูกปฏิเสธไว้ตามเดิม ดังนั้น pass เดียวจึงเพิ่มอันดับให้ gate ที่ได้ประโยชน์และปล่อยที่เหลือไว้ที่อันดับหนึ่ง
circuit ที่มีทั้งสองชนิดของ evolution แสดงให้เห็นว่าประหยัดได้เท่าไร predicate ด้านล่างรับ gate เฉพาะเมื่อตัวดำเนินการของมันย้ายอนุภาคระหว่างโหมด ซึ่งเป็นกรณีที่กลุ่มไม่สลับที่กันพอดี และอันดับที่สูงกว่ามีอะไรให้ได้
>>> def is_diagonal(operator):
... """Whether every term only counts particles, rather than moving them between modes."""
... return all(
... sorted(mode for created, mode in actions if created)
... == sorted(mode for created, mode in actions if not created)
... for actions, _ in operator.iter_terms()
... )
>>>
>>> def mixed_circuit():
... circuit = FermionicCircuit(num_sites)
... circuit.append(Evolution(num_sites, hamiltonian, time=total_time), circuit.modes)
... circuit.append(Evolution(num_sites, diagonal, time=total_time), circuit.modes)
... return circuit
>>>
>>> def two_qubit_cost(circuit):
... transpiled = generate_preset_jw_pass_manager().run(circuit).decompose(reps=6)
... two_qubit = lambda instruction: len(instruction.qubits) == 2
... return transpiled.count_ops()["cx"], transpiled.depth(two_qubit)
>>>
>>> order_2 = FermionicSuzukiTrotter(order=2)
>>>
>>> everywhere = two_qubit_cost(
... FermionicPassManager(F2FSynthesis({"Evolution": order_2})).run(mixed_circuit())
... )
>>> restricted = two_qubit_cost(
... FermionicPassManager(
... F2FSynthesis(
... {"Evolution": order_2}, filter=lambda node: not is_diagonal(node.op.operator)
... )
... ).run(mixed_circuit())
... )
>>> everywhere[0] - restricted[0] # the gates the filter saved
8
>>> restricted[0] < everywhere[0] and restricted[1] < everywhere[1]
True
gate ที่ filter ประหยัดได้ก็คือตัวที่อันดับสองใช้ไปกับ evolution แนวทแยงพอดี ซึ่งการเปรียบเทียบแนวทแยงข้างต้นคิดราคาไว้ที่แปด (18 เทียบกับ 10) พวกมันไม่ได้อะไรเลยที่นั่น เพราะ evolution นั้นแม่นยำอยู่แล้วที่อันดับหนึ่ง การตัดทิ้งจึงไม่เสียความแม่นยำ
เปรียบเทียบ circuit อันดับสองทั้งสองกันเอง ไม่ใช่กับตัวที่ไม่ขยาย การปล่อยทั้งสอง gate ไม่ขยายจะส่งแต่ละตัวไปยังขั้นตอนจากเฟอร์มิออนเป็น qubit ทั้งตัว ซึ่งเป็นความผิดพลาดที่หมายเหตุ apply=False ข้างต้นอธิบาย: อาจได้จำนวน entangling gate เท่ากับ circuit ที่ filter ในขณะที่เป็นคนละ circuit และความลึกต่างกัน การอ่านประโยชน์ของ filter จากตัวเลขนั้นจึงไม่ได้วัดอะไรเลย
ไม่มีตัวเลือกใดตรวจสอบว่าตัวประกอบเป็นเฮอร์มิเชียน และตัวดำเนินการที่จัดกลุ่มไม่ถูกต้องอาจดู ดีกว่า ที่อันดับคู่เมื่อเทียบกับอันดับหนึ่ง ทั้งที่ยังผิด เพราะการทำให้สมมาตรหักล้างความคลาดเคลื่อนบางส่วน จัดคู่สังยุคไว้ในกลุ่มเดียวกัน ดังที่ fermi_hubbard_chain ข้างต้นทำ
ขั้นตอนถัดไป
-
อ่าน จัดกลุ่มเทอมของตัวดำเนินการ: ใช้โครงสร้างของตัวดำเนินการ เพื่อดูว่ากลุ่มที่สูตรผลคูณเหล่านี้ใช้แบ่งถูกกำหนดอย่างไร
-
อ่าน Transpile fermionic circuits เพื่อดูขั้นตอนที่
FermionicCircuitผ่าน -
ดู จำลองพลวัต Fermi-Hubbard 1 มิติด้วย flow set สำหรับกรณีตัวอย่างที่สูตรเฟอร์มิออนให้จำนวนขั้นซึ่งการสังเคราะห์ฝั่ง qubit แบบกำหนดเองให้ไม่ได้
-
ดู
synthesisสำหรับวิธีการสังเคราะห์เอง และFermionicQDriftสำหรับทางเลือกแบบสุ่ม