แพ็กเกจนี้เกี่ยวข้องกับ ffsim อย่างไร
แนวคิดในคู่มือนี้ใช้ได้เฉพาะใน Python API
ffsim และแพ็กเกจนี้แบ่งงานกันโดยไม่ทับซ้อน ตามเส้นแบ่งเส้นเดียว:
| ffsim รับผิดชอบ | qiskit-fermions รับผิดชอบ |
|---|---|
ตัวดำเนินการ ansatz ระดับสูง (UCJOpSpinBalanced, UCCSDOpRestrictedReal และตัวอื่นในตระกูลเดียวกัน) ที่สร้างจากแอมพลิจูด coupled-cluster หรือเวกเตอร์พารามิเตอร์ | circuit เฟอร์มิออน (FermionicCircuit) ที่ตัวดำเนินการเหล่านั้นกลายเป็น และการ transpile เป็น circuit ของ qubit ภายใต้การเข้ารหัสจากเฟอร์มิออนเป็น qubit แบบใดก็ได้ |
| การจำลองที่เร็วในปริภูมิกะทัดรัดที่มีจำนวนอนุภาคคงที่ | เฟรมเวิร์ก mapper และโครงสร้างข้อมูลของตัวดำเนินการที่ใช้สร้าง circuit |
ผลในทางปฏิบัติเป็นไปทั้งสองทาง คณิตศาสตร์ของ ansatz อยู่ใน ffsim ดังนั้น UCJ และ UCC จึงรับตัวดำเนินการ ffsim เป็นอินพุตโดยตรง ในทางกลับกัน gate Qiskit ของ ffsim เองเฉพาะเจาะจงกับการแปลง Jordan-Wigner ดังนั้นการลดระดับตัวดำเนินการ ansatz ของมันผ่านการเข้ารหัส อื่น คือสิ่งที่การนำมาใช้ที่นี่ให้คุณ
การจำลองคือจุดที่ทั้งสองมาพบกัน และคู่มือนี้อธิบายว่าอย่างไร ffsim เป็น simulation backend ของแพ็กเกจนี้ โดยเข้าถึงผ่านโปรโตคอลของมันเอง ไม่ใช่ wrapper: คู่มือ SKQD เรียก ffsim.apply_unitary(), ffsim.linear_operator() และ ffsim.sample_state_vector() โดยตรงบนอ็อบเจกต์ FermionicCircuitและอ็อบเจกต์ FermionOperatorโดยไม่มีขั้นตอนแปลง
เสียบเข้ากับอินเทอร์เฟซการจำลองของ ffsim
ffsim เป็นตัวจำลองประสิทธิภาพสูงสำหรับ circuit ควอนตัมเฟอร์มิออน ที่ใช้ประโยชน์จากการอนุรักษ์จำนวนอนุภาคและสปิน-Z เพื่อแทนเวกเตอร์สถานะให้กะทัดรัดกว่า statevector ของ qubit ทั่วไปที่มี มิติ มันกำหนดโปรโตคอลที่อ็อบเจกต์ใดก็ implement ได้เพื่อเข้าร่วมในกลไกการจำลองของมัน (ดู qiskit_fermions.protocols สำหรับโปรโตคอลของแพ็กเกจนี้เอง ซึ่งออกแบบแบบเดียวกัน):
-
ffsim.SupportsApplyUnitaryด้วยเมธอด_apply_unitary_(vec, norb, nelec, copy)ซึ่งใช้อ็อบเจกต์เป็นยูนิทารีกับเวกเตอร์สถานะที่มีจำนวนอนุภาคคงที่ -
ffsim.SupportsLinearOperatorด้วยเมธอด_linear_operator_(norb, nelec)ซึ่งคืนมุมมองscipy.sparse.linalg.LinearOperatorของอ็อบเจกต์บนเซกเตอร์เดียวกัน -
ffsim.SupportsTraceด้วยเมธอด_trace_(norb, nelec)ซึ่งคืนเทรซของอ็อบเจกต์บนเซกเตอร์นั้น
แพ็กเกจนี้ implement อินเทอร์เฟซนั้น: ทุก fermionic gate ใน qiskit_fermions.circuit.library มี _apply_unitary_ และ FermionOperator มี _linear_operator_ และ _trace_ นี่คือสิ่งที่ทำให้ตัวดำเนินการและ circuit ของแพ็กเกจนี้ เข้ากันได้ กับ ffsim เครื่องมือของมันจึงทำงานกับสิ่งเหล่านี้ได้โดยตรงโดยไม่มีขั้นตอนแปลง ffsim.apply_unitary() จำลอง FermionicCircuit ตั้งแต่ต้นจนจบได้ ffsim.linear_operator() diagonalize FermionOperator ได้ และยูทิลิตีการสุ่มตัวอย่างเช่น ffsim.sample_state_vector() (ใช้ใน คู่มือ SKQD เพื่อเปลี่ยน statevector ที่จำลองเป็นจำนวนนับจากการวัด) ทำงานได้โดยไม่ต้องแก้ไข
สิ่งที่ _linear_operator_ คืนคือ LinearOperator ของ SciPy ธรรมดา ดังนั้น scipy.sparse.linalg.eigsh() และฟังก์ชันอื่นในกลุ่มเดียวกันก็ใช้กับมันได้เช่นกัน
>>> import ffsim
>>> import numpy as np
>>>
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, ann, cre
>>>
>>> norb, nelec = 2, (1, 1)
>>> hamiltonian = FermionOperator.from_terms([
... ([cre(0), ann(1)], 0.5),
... ([cre(1), ann(0)], 0.5),
... ])
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(Evolution(2 * norb, hamiltonian, time=1.0), circuit.modes)
>>>
>>> reference = ffsim.hartree_fock_state(norb, nelec)
>>> state = ffsim.apply_unitary(reference, circuit, norb=norb, nelec=nelec) # native ffsim call
การเชื่อมผ่านโปรโตคอลของ ffsim คือสิ่งที่ให้ประโยชน์นี้: ระบบนิเวศยูทิลิตีการจำลองและการสุ่มตัวอย่างที่พัฒนาอย่างต่อเนื่องของมันใช้กับ circuit และตัวดำเนินการของแพ็กเกจนี้ได้โดยไม่เปลี่ยนแปลง และผู้ใช้ที่ทำงานกับ ffsim อยู่แล้วสามารถผสม gate และตัวดำเนินการของแพ็กเกจนี้เข้าไปได้โดยไม่ต้องเรียนรู้ API การจำลองอื่น
ffsim เป็น dependency ที่เป็นทางเลือก
ffsim ถูกประกาศเป็น extra ที่เป็นทางเลือก (pip install "qiskit-fermions[ffsim]" หรือผ่าน [all] โดยอ้อม) และมีการป้องกันขณะรันไทม์ด้วย HAS_FFSIM (ตามที่แสดงข้างต้น) การติดตั้งมันเปิดใช้การจำลอง: ffsim.SupportsLinearOperator และ ffsim.SupportsTrace ถูก implement โดยแปลง FermionOperator ของแพ็กเกจนี้เป็น ffsim.FermionOperator ดังนั้นหากไม่มี ffsim จะ raise MissingOptionalLibraryError ทุกอย่างที่ไม่ได้จำลอง (การสร้างตัวดำเนินการ การแมปมัน และการ transpile circuit ที่ได้) ไม่ต้องใช้มันเลย
การจำลองเฟอร์มิออนอยู่ในเซกเตอร์จำนวนอนุภาคคงที่
ทั้ง _apply_unitary_ และ _linear_operator_ รับอาร์กิวเมนต์ nelec และแทนเวกเตอร์สถานะบน ฐาน determinant ที่มีจำนวนอนุภาคคงที่ สำหรับเซกเตอร์ (norb, nelec) นั้น ซึ่งสะท้อนการตั้งค่าปริภูมิ FCI ของ ffsim (และต่อเนื่องไปถึง PySCF) แทนที่จะเป็นปริภูมิ มิติเต็มที่ตัวจำลอง qubit ทั่วไปใช้ นี่เป็นปริภูมิที่เล็กกว่ามาก (ขนาดของมันเป็นผลคูณของสัมประสิทธิ์ทวินามแทนที่จะเป็นเลขยกกำลังของสอง) แต่มาพร้อมข้อจำกัดที่เข้มงวด มีเพียงตัวดำเนินการและ gate ที่รักษาจำนวนอนุภาค (และในกรณีมีสปิน รักษาจำนวนอนุภาคของแต่ละชนิดสปินแยกกัน) เท่านั้นที่แทนในนั้นได้ ตัวดำเนินการที่การกระทำของมันจะย้ายแอมพลิจูดไปยังจำนวนอนุภาคอื่นไม่มีที่ให้ใส่
ffsim แก้เรื่องนี้ด้วยการปฏิเสธตัวดำเนินการเช่นนั้นตรง ๆ: การแปลงมันเป็น linear operator จะ raise ValueError ที่ระบุว่ากฎการอนุรักษ์ข้อใดล้มเหลว นั่นเป็นค่าเริ่มต้นที่ถูกต้อง เพราะการใช้ กับแฮมิลโทเนียน ที่มีเทอมไม่อนุรักษ์จำนวนอนุภาคจะเปลี่ยนสิ่งที่ควรเป็นยูนิทารีให้เป็นการแมปที่ไม่ใช่ยูนิทารีและไร้ความหมายทางฟิสิกส์
-
Evolutionส่งต่อการปฏิเสธนั้นขึ้นมาจากตัวดำเนินการที่มันใช้วิวัฒนาการ -
OrbitalRotationจะตรวจสอบว่าเมทริกซ์การหมุน (ที่ฝังไว้) เป็นบล็อกทแยงมุมข้ามการแบ่งอัลฟา/เบตาในกรณีที่มีสปิน และจะเกิดValueErrorถ้ามีการผสมระหว่างเซกเตอร์สปิน
>>> from qiskit_fermions.circuit.library import Evolution
>>>
>>> non_conserving = FermionOperator.from_terms([([cre(0), cre(1)], 1.0)]) # creates 2 particles
>>> gate = Evolution(2 * norb, non_conserving, time=1.0)
>>>
>>> try:
... gate._apply_unitary_(reference, norb, nelec, copy=True)
... except ValueError as exc:
... print("rejected:", exc)
rejected: The given FermionOperator could not be converted to a LinearOperator because it does not conserve particle number and the z component of spin. Conserves particle number: False Conserves spin z: False
ดังนั้นการจำลองแบบที่ไม่รักษาจำนวนอนุภาคจึงทำไม่ได้ในปริภูมิเฟอร์มิออน เพราะโครงสร้างของการแทนค่าเซกเตอร์คงที่ และนี่คือราคาที่ต้องจ่ายเพื่อให้ได้ปริภูมิ FCI ที่กะทัดรัด ซึ่งทำให้การจำลองเฟอร์มิออนทำได้จริงตั้งแต่แรก ถ้าอัลกอริทึมของคุณต้องการตัวดำเนินการที่ละเมิดจำนวนอนุภาค (เช่น ช่องข้อผิดพลาดแบบ qubit-native หรือตัวดำเนินการที่สร้างสำหรับแฮมิลโทเนียนที่แมปแล้วซึ่งไม่อนุรักษ์จำนวนอนุภาคทีละเทอม) ให้ทรานสไพล์เป็นคิวบิตก่อน แล้วจำลอง QuantumCircuit ที่ได้ด้วยตัวจำลองระดับคิวบิตแทน เส้นทางการทรานสไพล์แบบใดก็ใช้ได้ คู่มือ fermionic circuit และ คู่มือ transpilation อธิบายรายละเอียดเพิ่มเติม แต่ generate_preset_jw_pass_manager() เป็นตัวเลือกเริ่มต้นที่สมเหตุสมผล
แบบแผนบล็อกสปินสำหรับระบบที่มีสปิน
nelec มีชนิดเป็น int | tuple[int, int] และชนิดของมัน ไม่ใช่แฟล็กแยกต่างหาก ที่เป็นตัวเลือกว่าจะใช้โครงร่างโหมดแบบใดที่รองรับ
-
int เลือกการตีความแบบ ไม่มีสปิน โหมด
norbถูกมองเป็นออร์บิทัลไม่มีสปินโดยตรง และnelecคือจำนวนอนุภาคทั้งหมด -
คู่
(n_alpha, n_beta)เลือกการตีความแบบ มีสปิน ของโหมด2 * norbภายใต้ แบบแผนบล็อกสปิน ที่กำหนดไว้ โหมด0 .. norbคือออร์บิทัลอัลฟา (สปินขึ้น) และโหมดnorb .. 2 * norbคือออร์บิทัลเบตา (สปินลง) แต่ละชนิดสปินถูกอนุรักษ์ อย่างเป็นอิสระ เทอมที่มีเฉพาะอัลฟาสามารถย้ายอิเล็กตรอนระหว่างโหมดอัลฟาได้ แต่ไม่มีวันย้ายเข้าโหมดเบตา และในทางกลับกัน
การกระจายนี้เกิดขึ้นที่จุดเข้าใช้งานโปรโตคอล ffsim ทุกจุดในแพ็กเกจนี้ (ตัวสร้าง Gate, การทำงานของ _apply_unitary_placed_ และการคอมไพล์เซกเตอร์ของเคอร์เนล Rust แบบเนทีฟ) และเป็นแบบแผนที่ใช้ตลอดทั้งคู่มือ LUCJ และ SKQD (เช่น InitializeModes.from_hartree_fock() ใส่การครอบครองอัลฟาลงในโหมด 0 .. n_alpha และการครอบครองเบตาลงในโหมด norb .. norb + n_beta) ควรเปรียบเทียบกับโมดูล qiskit_fermions.operators และ FermionicCircuit โดยทั่วไป ซึ่งใช้ดัชนีโหมด ทั่วไป ที่ไม่มีความหมายเรื่องสปินโดยเนื้อแท้ (ดูคู่มือ fermionic circuit) ความหมายของบล็อกสปินจะถูกกำหนดก็ต่อเมื่อส่ง nelec แบบมีสปินให้การเรียกจำลองเท่านั้น ไม่ได้ฝังอยู่ในการแทนค่าตัวดำเนินการหรือ Circuit เอง
>>> from qiskit_fermions.circuit.library import InitializeModes
>>>
>>> norb, nelec = 3, (2, 1)
>>> init = InitializeModes.from_hartree_fock(norb, nelec)
>>> print([bool(occ) for occ in init.occupation]) # alpha modes 0,1; beta mode 3 (= norb + 0)
[True, True, False, True, False, False]
ขั้นตอนถัดไป
-
ลองอ่านคู่มือ SKQD เพื่อดูการใช้
ffsim.apply_unitary()และffsim.sample_state_vector()ร่วมกันเพื่อสุ่มตัวอย่าง Circuit ที่สร้างจาก Gate ของแพ็กเกจนี้ และเพื่อประเมินค่าคาดหมายของแฮมิลโทเนียนผ่านffsim.linear_operator()(ซึ่งใช้เมธอดโปรโตคอล_linear_operator_ที่อธิบายไว้ที่นี่เช่นกัน) -
ลองอ่านคู่มือ LUCJ สำหรับอีกครึ่งหนึ่งของเรื่อง คือการนำตัวดำเนินการ ansatz ของ ffsim ผ่านไปป์ไลน์การทรานสไพล์ของแพ็กเกจนี้ และลงบนแผนผังการเชื่อมต่อของอุปกรณ์
-
อ่านคู่มือ fermionic circuit เพื่อดูการทำดัชนีโหมดแบบทั่วไปที่ไม่ขึ้นกับสปิน ซึ่งใช้นอกการเรียกจำลอง
-
อ่านคู่มือ transpilation เพื่อดูวิธีออกจากปริภูมิเฟอร์มิออน
และจำลองบนคิวบิต ซึ่งจำเป็นสำหรับตัวดำเนินการที่ไม่อนุรักษ์จำนวนอนุภาค
-
เรียกดู
qiskit_fermions.protocolsเพื่อดูแคตตาล็อกโปรโตคอลทั้งหมดที่แพ็กเกจนี้กำหนด รวมถึงโปรโตคอลการแปลง (SupportsFermionOperator,SupportsMajoranaOperator) ที่ไม่เกี่ยวข้องกับ ffsim -
อ่านคู่มือของ ffsim เอง สำหรับเวิร์กโฟลว์ที่ ffsim รับผิดชอบ โดยเฉพาะการสร้าง UCJ ansatz และการปรับให้เหมาะสมแบบแปรผัน เวกเตอร์พารามิเตอร์ที่คู่มือเหล่านั้นใช้ขับเคลื่อนคือสิ่งที่
UCJและUCCรับ ผ่านตัวดำเนินการที่ทั้งสองสร้างขึ้น