ทำงานกับ Circuit แบบโบซอน
BosonicCircuit แสดงการคำนวณโดยตรงบนโหมดโบซอน มันไม่มีการตัดทอน ไม่มีการเข้ารหัส และไม่มีจำนวน Qubit: สิ่งเหล่านั้นเข้ามาทีหลังระหว่าง transpilation ซึ่งทำให้ Circuit หนึ่งแปลงลงได้ภายใต้หลายการเข้ารหัสและหลายการตัดทอนโดยไม่ต้องสร้างใหม่
มันเปิดเผย API ที่ลดรูปเมื่อเทียบกับ QuantumCircuit ของ Qiskit โดยตั้งใจ เพื่อไม่ให้ใช้ Gate ของ Qubit กับโหมดโบซอนได้ ซึ่งจะไม่ใช่การดำเนินการที่นิยามได้ชัดเจน คู่มือนี้ครอบคลุมการดำเนินการที่ เปิดเผย ไว้สำหรับประกอบ Circuit ใหญ่จาก Circuit เล็ก
ทำไมจึงใช้ Circuit แบบโบซอน
ลองพิจารณาเวิร์กโฟลว์แบบดั้งเดิมในการนำวิวัฒนาการตามเวลาของแฮมิลโทเนียนแบบโบซอนไปไว้บนสถาปัตยกรรมที่ใช้ Qubit:
-
นิยามแฮมิลโทเนียนแบบโบซอน เช่น
-
เลือกการตัดทอนและการเข้ารหัส แล้วแมปแฮมิลโทเนียนเป็นตัวดำเนินการ Qubit ด้วยสิ่งเหล่านั้น
-
ทำวิวัฒนาการตามเวลาในปริภูมิ Qubit ด้วย Trotterization หรือวิธีอื่น
ขั้นตอนที่สองมาเร็ว และมันตัดสินใจสองอย่างที่ถอนคืนได้ยาก การตัดทอนกำหนดว่าแต่ละโหมดเก็บกี่ระดับ และการเข้ารหัสกำหนดว่านั่นใช้กี่ Qubit ดังนั้นทั้งสองจึงถูกตรึงในตัวดำเนินการ Qubit ก่อนที่จะทำอะไรอย่างอื่นกับ Circuit หากต้องการดูฟิสิกส์เดียวกันภายใต้ค่าตัดอื่นหรือการเข้ารหัสอื่น คุณต้องแมปแฮมิลโทเนียนใหม่และสร้าง Circuit ใหม่ นอกจากนี้ สิ่งที่การแมปทิ้งไปคือโครงสร้างแบบโบซอน: เทอมไหนอยู่ด้วยกัน และเทอมของคู่การกระโดดเป็นตัวผันของกันและกัน
BosonicCircuit ย้ายการตัดสินใจเหล่านั้นไปไว้ท้ายสุด:
-
นิยามแฮมิลโทเนียนแบบโบซอน
-
แสดงวิวัฒนาการตามเวลาโดยตรงบนโหมดโบซอน ด้วย Gate แบบโบซอน
-
เลือกการตัดทอนและการเข้ารหัสเป็นส่วนหนึ่งของ transpilation
Circuit อธิบายว่าจะคำนวณ อะไร และ transpilation ตัดสินว่าจะวางมันบน Qubit อย่างไร จากนั้น Circuit เดียวกันจะถูกแปลงลงที่ทุกค่าตัดและภายใต้ทุกการเข้ารหัส และการจัดกลุ่มของตัวดำเนินการยังอยู่ให้ pass ที่ใช้ประโยชน์ได้ ส่วนถัดไปแสดงวิธีประกอบ Circuit เช่นนี้ Transpile Circuit แบบโบซอน แสดงการแปลงลง
การทำดัชนีโหมดแบบทั่วไป
โมดูล operators และ Circuit ใช้ข้อตกลงเดียวกันสำหรับโหมด โหมดเป็นเพียงดัชนีที่ติดป้ายระดับขั้นความเสรีแบบโบซอน และไม่มีความหมายในตัวเอง ดังนั้นคุณจึงทำวิวัฒนาการตัวดำเนินการใดก็ได้ที่ implement โปรโตคอล OperatorTrait ไม่ว่ามันจะแทนอะไร และ Circuit ไม่จำเป็นต้องรู้ว่าโหมด 2 หมายถึงอะไร เช่นเดียวกันกับขนาดของโหมด: Circuit ไม่มีค่าตัดการครอบครอง ดังนั้นไม่มีอะไรที่นี่บอกว่าโหมดมีกี่ระดับ
ต่อ Gate
Gate ถูกต่อลงบนโหมด รับเฉพาะอินสแตนซ์ของ BosonicGate เท่านั้น:
>>> from qiskit_bosons.circuit import BosonicCircuit
>>> from qiskit_bosons.circuit.library import Evolution, InitializeModes
>>> from qiskit_bosons.operators import BosonOperator, ann, cre
>>>
>>> hopping = BosonOperator.from_dict({(cre(0), ann(1)): -1.0, (cre(1), ann(0)): -1.0})
>>> hopping.groups = [0] * len(hopping) # the pair is Hermitian, its terms alone are not
>>>
>>> prepare = BosonicCircuit(2)
>>> prepare.append(InitializeModes([2, 0]), prepare.modes)
>>> step = BosonicCircuit(2)
>>> step.append(Evolution(2, hopping, time=0.1), step.modes)
อย่างอื่นจะถูกปฏิเสธ และข้อผิดพลาดระบุชนิดที่ผิด:
>>> from qiskit.circuit.library import HGate
>>> try:
... prepare.append(HGate(), [0])
... except ValueError as error:
... print(error)
Unsupported instruction type: <class '...HGate'>
ประกอบ Circuit
compose() วางคำสั่งของ Circuit หนึ่งลงบนอีกอัน คำสั่งเหล่านั้นถูก inline ไม่ได้ห่อเป็น Gate เดียว ผลลัพธ์จึงเป็น Circuit ธรรมดาที่คุณแยกส่วนและ transpile ต่อได้
>>> program = prepare.compose(step)
>>> program.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>
โดยค่าเริ่มต้นจะคืน Circuit ใหม่และไม่แตะตัวถูกดำเนินการทั้งสอง ส่ง inplace=True เพื่อแก้ไขตัวแรกแทน และ front=True เพื่อวางตัวถูกดำเนินการ ก่อน คำสั่งที่มีอยู่:
>>> step.compose(prepare, front=True)._inner.data == program._inner.data
True
Circuit ที่แคบกว่าสามารถวางลงบนเซตย่อยของโหมดที่เลือกได้:
>>> single = BosonicCircuit(1)
>>> single.append(Evolution(1, BosonOperator.from_dict({(cre(0), ann(0)): 1.0}), 0.1), single.modes)
>>> wide = BosonicCircuit(3).compose(single, [2])
>>> wide.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>
รับเฉพาะ BosonicCircuit อื่นเป็นตัวถูกดำเนินการ เพราะ compose ของ Qiskit เองจะ inline Gate ของ Qubit และข้ามการตรวจสอบที่ append บังคับใช้
ทำซ้ำ Circuit
repeat() ทำซ้ำ Circuit ต่อกันตั้งแต่ต้นจนจบ การทำซ้ำถูก แผ่ราบ: ผลลัพธ์เก็บคำสั่ง reps ครั้งต่อเนื่องกัน แทนที่จะเป็น Gate เดียวที่ห่อ Circuit ดังนั้นจำนวนการดำเนินการจึงเพิ่มตาม reps และ decompose ทำงานบนส่วนที่ซ้ำแทนที่จะลบการทำซ้ำหนึ่งครั้ง
>>> len(step.repeat(0)._inner.data) # zero repetitions is the identity
0
>>> step.repeat(5).draw("mpl", fold=-1)
<Figure size ... with 1 Axes>
นี่คือวิธีระดับ Circuit ในการทำ Trotterize: วิวัฒน์ในเวลาสั้น ๆ แล้วทำซ้ำ ดู สังเคราะห์ Gate Evolution ในปริภูมิโบซอน สำหรับทางเลือกในการเลือกสูตรผลคูณบน Gate เอง และเหตุผลที่สองสิ่งนี้เป็นคนละเรื่องที่บังเอิญใช้คำว่า "repetitions" ร่วมกัน
คั่นขั้นตอนด้วย barrier
barrier ทำเครื่องหมายจุดซิงโครไนซ์ที่ pass การปรับให้เหมาะสมจะไม่รวม Gate ข้ามไป barrier() วางหนึ่งอันบนทุกโหมด หรือบนโหมดที่คุณระบุ:
>>> program = BosonicCircuit(2)
>>> program.append(InitializeModes([2, 0]), program.modes)
>>> program.barrier()
>>> program.barrier(program.modes[0], label="zero")
>>> program.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>
repeat(..., insert_barriers=True) ใส่หนึ่งอันระหว่างการทำซ้ำที่ต่อเนื่องกัน และไม่ใส่หลังอันสุดท้าย:
>>> step.repeat(3, insert_barriers=True).draw("mpl", fold=-1)
<Figure size ... with 1 Axes>
barrier และการเข้ารหัส
การเข้ารหัสต้องใช้หลาย Qubit ต่อโหมด ดังนั้นรีจิสเตอร์ของโหมดและรีจิสเตอร์ของ Qubit จึงมีขนาดต่างกัน และ layout เชื่อมโยง ทั้งรีจิสเตอร์ โหมดจึงไม่มี Qubit ของตัวเองให้จำกัด barrier ลงไป ระหว่างการสังเคราะห์โบซอนเป็น Qubit barrier ถูกแมปไปยัง ทุก Qubit ของแต่ละรีจิสเตอร์ที่มันแตะ ซึ่งถูกต้องภายใต้ layout ใด ๆ:
>>> from qiskit_bosons.mappers import LevelSpec
>>> from qiskit_bosons.transpiler.presets import generate_preset_occupation_pass_manager
>>> lowered = generate_preset_occupation_pass_manager(LevelSpec(2, "unary_projected")).run(program)
>>> lowered.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>
อ่านค่าจาก Circuit แบบโบซอน
BosonicCircuit ไม่มี measure หรือ measure_all ความหมายของบิตที่วัดได้ขึ้นอยู่กับการเข้ารหัส ภายใต้การเข้ารหัสแบบยูนารี การครอบครองของโหมดกระจายอยู่บนหลาย Qubit และต้องอ่านจากรูปแบบของบิต ส่วนแบบกะทัดรัดเป็นเลขฐานสอง ดังนั้นการวัดที่ระบุโหมดจะต้องรู้การเข้ารหัส ซึ่ง Circuit แบบโบซอนไม่รู้โดยตั้งใจ ให้วัด QuantumCircuit ที่ transpile แล้วแทน และถอดรหัสบิตสตริงด้วย LevelEncoding.level_to_bits() และออฟเซตของ LevelSpec ที่คุณใช้แปลงลง จำลองพลวัต Bose-Hubbard ด้วยการเลือกการเข้ารหัส ทำสิ่งนี้กับโมเดลที่สมบูรณ์
>>> hasattr(BosonicCircuit, "measure_all")
False
ขั้นตอนถัดไป
-
Transpile Circuit แบบโบซอน อธิบายว่า Circuit แบบโบซอนกลายเป็น Circuit ของ Qubit ได้อย่างไร ทีละขั้นตอน
-
หมุนโหมดโบซอน ครอบคลุม Gate ที่ผสมโหมดและรักษาจำนวนโบซอน
-
สังเคราะห์ Gate Evolution ในปริภูมิโบซอน แสดงวิธี Trotterize วิวัฒนาการในปริภูมิโบซอน
-
หลักการออกแบบของการแทนตัวดำเนินการ อธิบายตัวดำเนินการที่ Gate นำพา