จัดกลุ่มเทอมของตัวดำเนินการ: ใช้โครงสร้างของตัวดำเนินการ
การจัดกลุ่มเป็นหนึ่งในการดำเนินการภายใต้ 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>
นี่คือแลตทิซขนาดสองคูณสามอย่างง่ายของโหมดมาจอรานาที่เชื่อมด้วยขอบมีทิศทาง แต่ละขอบแทนเทอมในตัวดำเนินการที่กระทำกับสองโหมดที่เชื่อมกัน เป้าหมายคือการจัดกลุ่มเทอมเหล่านี้ตามป้ายกำกับขอบ (แสดงบนกราฟ) เทอมที่เชื่อมด้วยขอบที่มีป้ายเดียวกันจะอยู่ในกลุ่มเดียวกัน โค้ดต่อไปนี้แสดงวิธีทำ
- PYTHON
- C
>>> 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))]
#include <qiskit_fermions.h>
uint64_t num_terms = 7;
uint64_t num_modes = 14;
uint32_t modes[14] = {0, 1, 1, 2, 3, 0, 1, 4, 5, 2, 5, 4, 4, 3};
QkComplex64 coeffs[7] = {{1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0},
{1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}};
uint32_t boundaries[8] = {0, 2, 4, 6, 8, 10, 12, 14};
QfMajoranaOperator *op = qf_maj_op_new(num_terms, num_modes, coeffs, modes, boundaries);
uint32_t groups[7] = {0, 0, 1, 2, 1, 3, 3};
qf_maj_op_set_groups(op, groups, num_terms);
QfMajoranaOperator *group_ops[4];
qf_maj_op_split_out_groups(op, NULL, 0, group_ops);
วิเคราะห์การจัดกลุ่ม
กลุ่มไม่ได้กำหนดความหมายใดๆ ในตัวเอง: groups array บันทึกว่าเทอมใดอยู่ด้วยกัน แต่ไม่เคยบอกว่าทำไม ไม่มีรูทีนใดในไลบรารีนี้ที่รายงานว่าการจัดกลุ่มนั้น “ถูกต้อง” หรือไม่ เพราะไม่มีนิยามความถูกต้องเพียงแบบเดียวให้อ้างอิง อย่างไรก็ตาม ผู้ใช้งานขั้นถัดไปมักสมมติสมบัติบางอย่างของการจัดกลุ่ม และฟังก์ชันในส่วนนี้ช่วยให้คุณตรวจสอบข้อสมมติเช่นนั้นล่วงหน้า แทนที่จะต้องเสียค่าใช้จ่ายทุกครั้งที่เรียกใช้
แบบแผนที่พบบ่อยที่สุดคือแต่ละกลุ่มเป็นเฮอร์มิเชียนแยกกัน นั่นคือสิ่งที่ทำให้สูตรผลคูณสุ่มแบบเฟอร์มิออนเป็นไปได้ตั้งแต่แรก: เดี่ยวๆ ที่ ไม่ใช่เฮอร์มิเชียน ดังนั้นวิวัฒนาการตามเวลาของมันจึงไม่ยูนิทารีและสุ่มตัวอย่างโดยลำพังไม่ได้ การจับคู่กับ จะได้กลุ่มที่ทำได้
- PYTHON
- C
>>> 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]
#include <qiskit_fermions.h>
uint64_t num_terms = 3;
uint64_t num_actions = 6;
bool actions[6] = {true, false, true, false, true, false};
uint32_t modes[6] = {0, 1, 1, 0, 2, 3};
QkComplex64 coeffs[3] = {{1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}};
uint32_t boundaries[4] = {0, 2, 4, 6};
QfFermionOperator *op =
qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
uint32_t groups[3] = {0, 0, 1};
qf_ferm_op_set_groups(op, groups, num_terms);
bool hermitian[2];
qf_ferm_op_groups_are_hermitian(op, 1e-8, hermitian);
double means[2];
qf_ferm_op_group_coeff_means(op, means);
บังคับให้มีดัชนีกลุ่มหนึ่งตัวต่อหนึ่งเทอม
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 เชื่อถือได้เฉพาะกับชนิดตัวดำเนินการที่รูปแบบนอร์มัลเป็นรูปแบบมาตรฐานจริงๆ เท่านั้น ให้ดูชนิดตัวดำเนินการนั้นๆ เพื่อดูว่าข้อใดใช้
A. Gandon et al., Stabilizer-based quantum simulation of fermion dynamics with local qubit encodings, arXiv:2512.11418v2.