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

จัดกลุ่มเทอมของตัวดำเนินการ: ใช้โครงสร้างของตัวดำเนินการ

การจัดกลุ่มเป็นหนึ่งในการดำเนินการภายใต้ qiskit_fermions.operators.terms ซึ่งรวบรวมรูทีนที่แบ่งเทอมของตัวดำเนินการตามโครงสร้างของมัน

ตามที่อธิบายในคู่มือ operators ตัวดำเนินการสามารถเก็บ groups array ซึ่งเป็นส่วนเสริมของโครงสร้างข้อมูลแบบเบาบางที่เชื่อมแต่ละเทอมกับดัชนีกลุ่ม เทอมที่ใช้ดัชนีกลุ่มเดียวกันจะรวมเป็นกลุ่ม ซึ่งช่วยให้คุณใช้ประโยชน์จากโครงสร้างนี้อย่างเป็นระบบในการประมวลผลขั้นถัดไป

การจัดกลุ่มเทอมที่เกี่ยวข้องกัน (ไม่ว่าจะตามสมบัติทางกายภาพ ความสัมพันธ์เชิงพีชคณิต หรือสมมาตรเฉพาะของปัญหา) จะให้ประโยชน์หลายอย่าง

  • การสังเคราะห์ Circuit ที่ปรับให้เหมาะสม: เทอมที่จัดกลุ่มไว้จะนำข้อมูลเฉพาะของปัญหาไปตลอดทั้งสแต็ก ทำให้ปรับแต่ง Circuit ที่สังเคราะห์ได้ง่ายขึ้น ส่งผลให้ความลึกของ Circuit และจำนวน Gate ลดลง

  • การรักษาโครงสร้างทางกายภาพ: กลุ่มเข้ารหัสโครงสร้างที่มีความหมายจากปัญหาเดิม (เช่น รูปแบบอันตรกิริยาหรือสมมาตร) ซึ่งนำไปใช้ให้การแยกส่วนที่มีความหมายทางกายภาพมากขึ้นได้

  • การเลือก flow set: การจัดกลุ่มสามารถเข้ารหัส flow set และโครงสร้างเชิงทฤษฎีกราฟอื่นๆ ที่เกี่ยวข้องกับการจำลองควอนตัมได้อย่างเป็นธรรมชาติ ดังที่แสดงใน [1]

  • เสถียรภาพของอัลกอริทึมที่ดีขึ้น: ดังที่แสดงในรูทีน SqDRIFT อัลกอริทึมบางตัวได้ประโยชน์จากเสถียรภาพหรือประสิทธิภาพที่ดีขึ้น เพราะรักษาสมบัติทางกายภาพไว้

  • ตัวประกอบของสูตรผลคูณ: สูตรผลคูณเฟอร์มิออนแบ่งตัวดำเนินการเป็นกลุ่มของมัน ดังนั้นการจัดกลุ่มจึงกำหนดทั้งต้นทุนและความคลาดเคลื่อนแบบ Trotter ของการวิวัฒนาการตามเวลา ดู Synthesize an Evolution gate in fermionic space

การใช้งาน​

วิธีที่ง่ายที่สุดในการกำหนดการจัดกลุ่มตัวดำเนินการคือการตั้งค่าแอตทริบิวต์ groups ของตัวดำเนินการเป้าหมาย ด้านล่างคือตัวอย่างการจัดกลุ่มเทอมตาม line flow sets ดังที่แสดงในรูปที่ 1c ของ [1]

คำใบ้

โมดูล qiskit_fermions.operators.terms.grouping มีเมธอดอำนวยความสะดวกสำหรับระบุโครงสร้างในตัวดำเนินการโดยอัตโนมัติและกำหนดดัชนีกลุ่มตามนั้น

>>> import rustworkx as rx
>>> graph = rx.PyDiGraph()
>>> _ = graph.add_nodes_from(range(6))
>>> edges = [(0, 1), (1, 2), (3, 0), (1, 4), (5, 2), (5, 4), (4, 3)]
>>> groups = [0, 0, 1, 2, 1, 3, 3]
>>> edges_with_group_as_payload = [(i, j, g) for (i, j), g in zip(edges, groups)]
>>> _ = graph.add_edges_from(edges_with_group_as_payload)
>>> from rustworkx.visualization import mpl_draw
>>> mpl_draw(
... graph,
... pos={i: (i % 3, i // 3) for i in range(6)},
... edge_labels=str,
... with_labels=True,
... )
<Figure size ... with 1 Axes>

A simple directed graph on which to define a MajoranaOperator.

นี่คือแลตทิซขนาดสองคูณสามอย่างง่ายของโหมดมาจอรานาที่เชื่อมด้วยขอบมีทิศทาง แต่ละขอบแทนเทอมในตัวดำเนินการที่กระทำกับสองโหมดที่เชื่อมกัน เป้าหมายคือการจัดกลุ่มเทอมเหล่านี้ตามป้ายกำกับขอบ (แสดงบนกราฟ) เทอมที่เชื่อมด้วยขอบที่มีป้ายเดียวกันจะอยู่ในกลุ่มเดียวกัน โค้ดต่อไปนี้แสดงวิธีทำ

>>> from qiskit_fermions.operators import MajoranaOperator
>>>
>>> # Construct operator directly using sparse arrays
>>> # 7 terms, each with coefficient 1.0, modes from edge endpoints
>>> op = MajoranaOperator(
... coeffs=[1.0] * 7,
... modes=[node for edge in edges for node in edge],
... boundaries=[0, 2, 4, 6, 8, 10, 12, 14],
... )
>>>
>>> # Assign group indices to terms (groups is part of the sparse data structure)
>>> op.groups = groups
>>>
>>> # Partition operator by groups
>>> grouped_ops = op.split_out_groups()
>>>
>>> # Inspect each group
>>> for i, g in enumerate(grouped_ops):
... print(f"Group {i}: {list(sorted(g.iter_terms()))}")
Group 0: [([0, 1], (1+0j)), ([1, 2], (1+0j))]
Group 1: [([3, 0], (1+0j)), ([5, 2], (1+0j))]
Group 2: [([1, 4], (1+0j))]
Group 3: [([4, 3], (1+0j)), ([5, 4], (1+0j))]

วิเคราะห์การจัดกลุ่ม​

กลุ่มไม่ได้กำหนดความหมายใดๆ ในตัวเอง: groups array บันทึกว่าเทอมใดอยู่ด้วยกัน แต่ไม่เคยบอกว่าทำไม ไม่มีรูทีนใดในไลบรารีนี้ที่รายงานว่าการจัดกลุ่มนั้น “ถูกต้อง” หรือไม่ เพราะไม่มีนิยามความถูกต้องเพียงแบบเดียวให้อ้างอิง อย่างไรก็ตาม ผู้ใช้งานขั้นถัดไปมักสมมติสมบัติบางอย่างของการจัดกลุ่ม และฟังก์ชันในส่วนนี้ช่วยให้คุณตรวจสอบข้อสมมติเช่นนั้นล่วงหน้า แทนที่จะต้องเสียค่าใช้จ่ายทุกครั้งที่เรียกใช้

แบบแผนที่พบบ่อยที่สุดคือแต่ละกลุ่มเป็นเฮอร์มิเชียนแยกกัน นั่นคือสิ่งที่ทำให้สูตรผลคูณสุ่มแบบเฟอร์มิออนเป็นไปได้ตั้งแต่แรก: ap†aqa^\dagger_p a_q เดี่ยวๆ ที่ p≠qp \neq q ไม่ใช่เฮอร์มิเชียน ดังนั้นวิวัฒนาการตามเวลาของมันจึงไม่ยูนิทารีและสุ่มตัวอย่างโดยลำพังไม่ได้ การจับคู่กับ aq†apa^\dagger_q a_p จะได้กลุ่มที่ทำได้

>>> from qiskit_fermions.operators import FermionOperator
>>> from qiskit_fermions.operators.terms.grouping import (
... group_coeff_means,
... groups_are_hermitian,
... groups_have_uniform_coeffs,
... )
>>>
>>> # a conjugate pair, plus one unpaired term. The operator is built from the sparse
>>> # arrays rather than from a dictionary, because only the former fixes the term order
>>> # that the group indices below are paired with.
>>> pair_and_single = FermionOperator(
... [1.0, 1.0, 1.0],
... [True, False, True, False, True, False],
... [0, 1, 1, 0, 2, 3],
... [0, 2, 4, 6],
... )
>>> pair_and_single.groups = [0, 0, 1]
>>>
>>> groups_are_hermitian(pair_and_single) # group 1 is unpaired
[True, False]
>>> group_coeff_means(pair_and_single)
[1.0, 1.0]

บังคับให้มีดัชนีกลุ่มหนึ่งตัวต่อหนึ่งเทอม​

groups array เก็บดัชนีหนึ่งตัวต่อหนึ่งเทอม และการกำหนดอาร์เรย์ที่มีความยาวต่างกันจะเกิดข้อผิดพลาด ไม่มีส่วนใดขั้นถัดไปตรวจสอบเงื่อนไขนี้ซ้ำ จึงบังคับใช้ตรงจุดที่ดัชนีเข้าสู่ตัวดำเนินการ: อาร์เรย์ที่สั้นเกินไปจะทำให้เทอมท้ายๆ หายไปโดยไม่แจ้งเตือน และอาร์เรย์ที่ยาวเกินไปจะสร้างกลุ่มที่ไม่มีเทอมใดอยู่

>>> pair_and_single.groups = [0, 0] # one index short, on a three-term operator
Traceback (most recent call last):
ValueError: expected one group index per term, but got 2 for 3 terms

การล้างดัชนีกลุ่มโดยกำหนดเป็น None ทำได้เสมอ

การตรวจสอบสองอย่างเป็นอิสระต่อกัน​

groups_have_uniform_coeffs() รายงานว่าสัมประสิทธิ์ของกลุ่มตรงกันหรือไม่ ซึ่งเป็นข้อสมมติที่ group_coeff_means() ใช้เมื่อหาค่าเฉลี่ยของขนาด มันไม่ใช่รูปแบบที่อ่อนกว่าของการตรวจสอบความเป็นเฮอร์มิเชียน: การตรวจสอบทั้งสองไม่ได้นัยถึงกันและกัน ไม่ว่าทิศทางใด

>>> from qiskit_fermions.operators.terms.grouping import (
... groups_are_hermitian,
... groups_have_uniform_coeffs,
... )
>>> # uniform coefficients, but not Hermitian: the terms are not each other's adjoint
>>> uniform = FermionOperator(
... [1.0, 1.0],
... [True, False, True, False],
... [0, 1, 2, 3],
... [0, 2, 4],
... )
>>> uniform.groups = [0, 0]
>>> groups_have_uniform_coeffs(uniform), groups_are_hermitian(uniform)
([True], [False])
>>> # Hermitian, but with mixed magnitudes: two conjugate pairs at different scales
>>> mixed = FermionOperator(
... [1.0, 1.0, 5.0, 5.0],
... [True, False, True, False, True, False, True, False],
... [0, 1, 1, 0, 2, 3, 3, 2],
... [0, 2, 4, 6, 8],
... )
>>> mixed.groups = [0, 0, 0, 0]
>>> groups_are_hermitian(mixed), groups_have_uniform_coeffs(mixed)
([True], [False])

โดยค่าเริ่มต้นจะเปรียบเทียบขนาด เพราะนั่นคือสิ่งที่ group_coeff_means() หาค่าเฉลี่ย คู่เฮอร์มิเชียนคอนจูเกตที่มีสัมประสิทธิ์เชิงซ้อนจะมีขนาดเท่ากันแต่สัมประสิทธิ์ไม่เท่ากัน จึงผ่านเฉพาะรูปแบบเริ่มต้นเท่านั้น

>>> conjugate = FermionOperator(
... [1.0j, -1.0j],
... [True, False, True, False],
... [0, 1, 1, 0],
... [0, 2, 4],
... )
>>> conjugate.groups = [0, 0]
>>> groups_have_uniform_coeffs(conjugate)
[True]
>>> groups_have_uniform_coeffs(conjugate, abs=False)
[False]
หมายเหตุ

groups_are_hermitian() รับช่วงการรับประกันด้านเดียวของ is_hermitian() มา: ค่า True เชื่อถือได้เสมอ ส่วนค่า False เชื่อถือได้เฉพาะกับชนิดตัวดำเนินการที่รูปแบบนอร์มัลเป็นรูปแบบมาตรฐานจริงๆ เท่านั้น ให้ดูชนิดตัวดำเนินการนั้นๆ เพื่อดูว่าข้อใดใช้

[1] (1,2)

A. Gandon et al., Stabilizer-based quantum simulation of fermion dynamics with local qubit encodings, arXiv:2512.11418v2.