Langkau ke kandungan utama
Projek ini dalam fasa beta. Jumpa pepijat? Buat isu GitHub. Ada soalan atau idea? Tanya dalam Discussions — kami suka dengar maklum balas anda!
Bagaimana kualiti terjemahan pada halaman ini?

Petakan perwakilan operator

Pemeta ialah rutin yang mengubah operator daripada satu perwakilan kepada yang lain sambil mengekalkan kesetaraan matematik. Gunakannya untuk bekerja secara fleksibel merentasi algebra operator yang berbeza dan untuk menyediakan operator bagi pelaksanaan litar kuantum.

Laksanakan pemeta tersuai​

Modul pemeta memudahkan pelaksanaan pemetaan tersuai. Pemeta berfungsi dengan mengubah tindakan asas (penciptaan, pemusnahan, Majorana, dan sebagainya) yang membentuk operator, kemudian menggabungkan tindakan yang telah diubah ini mengikut peraturan perwakilan sasaran.

Sebagai contoh konkrit, pertimbangkan transformasi Jordan-Wigner yang memetakan MajoranaOperator kepada operator qubit menggunakan map_majorana_action_generators():

>>> from qiskit.quantum_info import SparseObservable
>>> from qiskit_fermions.mappers import map_majorana_action_generators
>>> from qiskit_fermions.operators import MajoranaOperator
>>>
>>> # Create a Majorana operator
>>> maj_op = MajoranaOperator.from_dict({(0, 1): 1.0, (2,): 0.5})
>>>
>>> # Define how each Majorana action maps to Pauli strings
>>> num_qubits = 2
>>> def map_action(mode: int) -> SparseObservable:
... idx = mode // 2
... qubits = list(range(idx + 1))
... pauli = "Y" if mode % 2 else "X"
... return SparseObservable.from_sparse_list(
... [("Z" * idx + pauli, qubits, 1.0)],
... num_qubits=num_qubits,
... )
>>>
>>> # Apply the mapping to transform the operator
>>> custom_observable = map_majorana_action_generators(
... maj_op,
... map_action,
... identity=lambda: SparseObservable.identity(num_qubits),
... compose=SparseObservable.compose,
... )
>>> print(custom_observable.simplify())
<SparseObservable with 2 terms on 2 qubits: (0+1j)(Z_0) + (0.5+0j)(X_1 Z_0)>

Langkah utama untuk melaksanakan mana-mana pemeta tersuai ialah:

  1. Takrifkan transformasi tindakan: Nyatakan bagaimana setiap tindakan (diindeks mengikut mod) dipetakan kepada perwakilan sasaran. Dalam contoh di atas, tindakan Majorana dipetakan kepada rentetan Pauli mengikut peraturan Jordan-Wigner.

  2. Gunakan salah satu fungsi pemetaan yang disediakan: Modul mappers menyediakan fungsi utiliti untuk mengendalikan lelaran ke atas sebutan operator dan penerapan peta tindakan tersuai seterusnya bagi perwakilan operator yang disediakan oleh modul operators. Sebagai contoh, map_majorana_action_generators() berfungsi dengan operator Majorana.

  3. Dapatkan hasilnya: Fungsi pemetaan mengembalikan operator dalam perwakilan sasaran dengan transformasi yang diterapkan secara konsisten pada semua sebutan.

Reka bentuk ini memudahkan pembuatan prototaip pemetaan tersuai tanpa pengetahuan mendalam tentang struktur dalaman operator. Transformasi diterapkan secara automatik pada setiap sebutan dalam operator sambil mengekalkan kesetaraan matematik.

Petunjuk

Anda juga boleh melelar sebutan operator secara manual dan bukannya menggunakan salah satu fungsi pelelar yang disediakan. Lihat bahagian tentang lelaran sebutan dalam panduan operator untuk butiran.

Pelaksanaan pustaka​

Modul qiskit_fermions.mappers.library menyediakan pelaksanaan pemetaan lazim yang cekap dan diuji secara menyeluruh. Pelaksanaan ini mengikut corak asas yang sama seperti pemeta tersuai tetapi dioptimumkan untuk kegunaan pengeluaran dan tersedia dalam API Python dan C.

Contoh di bawah menerapkan pemeta pustaka pada MajoranaOperator yang sama daripada bahagian pemeta tersuai, menunjukkan hasil yang setara:

>>> from qiskit_fermions.mappers.library import majorana_to_fermion, jordan_wigner
>>>
>>> # Convert MajoranaOperator to FermionOperator using library mapper
>>> ferm_op = majorana_to_fermion(maj_op)
>>>
>>> # Apply Jordan-Wigner mapper to get qubit operator
>>> sparse_observable = jordan_wigner(ferm_op, num_qubits=2)
>>> difference = sparse_observable - custom_observable
>>> print(difference.simplify() == SparseObservable.zero(num_qubits))
True
Nota

Dua langkah di atas ditulis secara terperinci untuk menunjukkan dua pemeta pustaka yang digubah bersama. Dalam amalan, anda akan memetakan MajoranaOperator dalam satu langkah sahaja, dengan majorana_jordan_wigner() (qf_maj_op_jordan_wigner() dalam API C), dan begitu juga untuk jenis operator lain – edge_vertex_jordan_wigner() dan transfer_vertex_jordan_wigner() (qf_edge_op_jordan_wigner(), qf_transfer_op_jordan_wigner()). Melalui FermionOperator juga mengembangkan hasil perantaraan: setiap penjana algebra ini dipetakan kepada satu rentetan Pauli, manakala setiap tindakan fermion dipetakan kepada hasil tambah dua sebutan, jadi sebutan yang dibina daripada beberapa penjana berkembang hanya untuk digabungkan semula kemudian. Penjimatan itu bertambah dengan panjang sebutan; bagi sebutan penjana tunggal dalam Hamiltonian lompatan, kedua-dua laluan berkos lebih kurang sama.

Dalam API Python, sebahagian pemeta pustaka ini juga boleh dicapai melalui pemeta kemudahan yang tidak bergantung pada jenis. fermion_operator() dan majorana_operator() berada di hadapan majorana_to_fermion() dan fermion_to_majorana() (antara lain), menyerahkan kepada pelaksanaan pustaka yang sesuai secara dalaman berdasarkan jenis objek yang diberikan, tanpa memerlukan anda memilih fungsi yang betul sendiri. Perkara yang sama terpakai pada jordan_wigner() dan ternary_tree() (diperkenalkan di bawah), yang masing-masing menghantar kepada pelaksanaan langsung yang sepadan dengan operator yang diberikan. Lihat qiskit_fermions.protocols untuk cara penghantaran ini dilaksanakan secara dalaman.

Pilih pengekodan dengan pokok ternari​

Jordan-Wigner bukan satu-satunya pengekodan fermion-ke-qubit, dan ia bukan yang paling murah. Rentetan ZZ nya bertambah panjang dengan indeks mod, jadi operator Majorana pada mod terakhir daripada nn mod dipetakan kepada rentetan Pauli berpemberat nn. Pengekodan yang menyebarkan maklumat pariti merentasi pokok dan bukannya rantai mencapai prestasi asimptot yang lebih baik.

Pokok ternari pada nn nod merangkumi seluruh keluarga ini. Setiap nod ialah qubit yang membawa tiga pautan ke bawah berlabel X, Y dan Z; sesuatu pautan sama ada menurun ke nod anak (sebuah tepi) atau berakhir (sebuah daun). Laluan setiap daun kembali ke akar mengeja rentetan Pauli: melintasi pautan berlabel PP yang menurun daripada nod uu menyumbang PP pada qubit uu. Setiap pokok sedemikian menghasilkan pengekodan yang sah, dan yang biasa dikenali hanyalah bentuk tertentu – rantai di sepanjang Z ialah Jordan-Wigner, manakala pokok yang setiap nodnya mempunyai tiga anak, setakat yang dibenarkan oleh bilangan nod, ialah seimbang.

>>> from qiskit_fermions.mappers import TernaryTree, TernaryTreeEncoding
>>>
>>> # Jordan-Wigner is a chain descending along Z, with X and Y as legs at every node.
>>> TernaryTree.chain(13, "Z").max_weight
13
>>> # The balanced tree spreads the same information over depth log_3(2n+1).
>>> TernaryTree.breadth_first(13, 3).max_weight
3

Pemberat maksimum itu adalah optimum. Jiang et al. membuktikan bahawa operator Majorana bagi mana-mana pemetaan fermion-ke-qubit untuk nn mod mempunyai pemberat Pauli purata sekurang-kurangnya log⁡3(2n)\log_3(2n), jadi tiada pemetaan yang dapat membawa yang terbesar daripadanya di bawah ⌈log⁡3(2n+1)⌉\lceil \log_3(2n+1) \rceil. Kedua-dua pokok menggunakan tepat nn qubit, jadi penjimatan terletak pada pemberat Pauli, bukan bilangan qubit.

Untuk memetakan operator, susun pokok menjadi pengekodan dan serahkannya kepada pemeta bersama-sama bilangan qubit untuk hasilnya. Penyusunan memasangkan daun pokok menjadi operator Majorana dan membina rentetan Pauli mereka sekali sahaja, jadi pengekodan yang sama harus digunakan semula merentasi banyak operator. Bilangan qubit kekal bersama panggilan pemetaan dan bukannya pengekodan, jadi satu pengekodan boleh melayani daftar berlainan lebar; bilangan yang melebihi bilangan nod pokok diisi dengan identiti.

>>> from qiskit_fermions.mappers.library import fermion_ternary_tree
>>> from qiskit_fermions.operators import FermionOperator
>>>
>>> hamiltonian = FermionOperator.from_dict(
... {((True, 0), (False, 3)): 1.0, ((True, 3), (False, 0)): 1.0}
... )
>>> encoding = TernaryTreeEncoding(TernaryTree.breadth_first(4, 3))
>>> fermion_ternary_tree(hamiltonian, encoding, 4).simplify()
<SparseObservable with 2 terms on 4 qubits: (0.5+0j)(Y_3 Z_1 Y_0) + (0.5+0j)(X_3 Z_2 X_0)>

Pemetaan melalui rantai di sepanjang Z menghasilkan semula fermion_jordan_wigner() (qf_ferm_op_jordan_wigner() dalam API C) dengan tepat, dan dalam pengertian inilah ia menggeneralisasikannya:

>>> from qiskit_fermions.mappers.library import fermion_jordan_wigner
>>> chain = TernaryTreeEncoding(TernaryTree.chain(4, "Z"))
>>> direct = fermion_jordan_wigner(hamiltonian, 4)
>>> (fermion_ternary_tree(hamiltonian, chain, 4) - direct).simplify().num_terms
0

Setiap perwakilan operator mempunyai pemeta pokok ternari, mencerminkan set Jordan-Wigner; lihat qiskit_fermions.mappers.library untuk senarai penuh, dan Mapper Library dalam API C. Dalam API Python, ia juga boleh dicapai melalui ternary_tree(), pembalut tidak bergantung jenis yang memilih pemeta yang betul untuk operator yang diberikan, sama seperti jordan_wigner():

>>> from qiskit_fermions.mappers.library import ternary_tree
>>> ternary_tree(hamiltonian, encoding, 4).simplify()
<SparseObservable with 2 terms on 4 qubits: (0.5+0j)(Y_3 Z_1 Y_0) + (0.5+0j)(X_3 Z_2 X_0)>
Nota

Sebahagian identiti yang benar di bawah Jordan-Wigner ialah sifat rantai dan bukannya pokok ternari. Operator nombor ialah nj=(1−Zj)/2n_j = (1 - Z_j)/2 hanya pada rantai; pada pokok lain, ZjZ_j menjadi rentetan ZZ ke atas set qubit. Begitu juga operator bucu VjV_j ialah Pauli berpemberat 1 ZjZ_j hanya pada rantai, di mana rantai ZZ bagi dua rentetan Majorana saling membatalkan.

Oleh sebab setiap operator nombor masih dipetakan kepada satu rentetan ZZ, keadaan Fock masih merupakan keadaan asas pengiraan di bawah mana-mana pokok ternari, tetapi bit qq tidak lagi menunjukkan penghunian qq. Penghunian jj sebaliknya ialah pariti bit yang diukur pada sokongan imej njn_j. Baca sokongan tersebut daripada pemeta dan bukannya menerbitkannya daripada pokok, supaya penyahkodan kekal betul untuk sebarang bentuk atau pilih atur mod:

>>> for mode in range(4):
... number = FermionOperator.from_dict({((True, mode), (False, mode)): 1.0})
... print(mode, ternary_tree(number, encoding, 4).simplify())
0 <SparseObservable with 2 terms on 4 qubits: (0.5+0j)() + (-0.5+0j)(Z_2 Z_1 Z_0)>
1 <SparseObservable with 2 terms on 4 qubits: (0.5+0j)() + (-0.5+0j)(Z_1)>
2 <SparseObservable with 2 terms on 4 qubits: (0.5+0j)() + (-0.5+0j)(Z_2)>
3 <SparseObservable with 2 terms on 4 qubits: (0.5+0j)() + (-0.5+0j)(Z_3)>

Pada pokok seimbang ini, mod 0 dihuni apabila qubit 0, 1 dan 2 memegang bilangan ganjil satu, jadi penyediaannya bermakna membalikkan qubit 0 sahaja, manakala penyahkodan rentetan bit yang diukur mengambil pariti ke atas ketiga-tiganya. Satu ralat balikan bit pada qubit 1 kemudian merosakkan penghunian kedua-dua mod 0 dan mod 1, yang penting bagi sebarang aliran kerja yang membaca penghunian daripada sampel bising.

Apabila Evolution diturunkan melalui pemeta sedemikian, bungkus pemeta dalam group_wise() (lihat Synthesize an Evolution gate in fermionic space). Sebutan lompatan dipetakan kepada dua rentetan Pauli yang berkomut, yang masing-masing tidak mengekalkan bilangan zarah dengan sendirinya; hanya hasil darabnya dalam evolusi yang berbuat demikian. Di bawah Jordan-Wigner kedua-dua rentetan bertindak pada qubit yang sama, jadi susunan sebutan yang dipermudahkan memastikannya bersebelahan. Di bawah pokok lain sokongan mereka berbeza (seperti dalam Y_3 Z_1 Y_0 dan X_3 Z_2 X_0 sebelum ini), susunan mentah dan susunan yang dipermudahkan kedua-duanya menyelang-nyelikannya dengan imej sebutan lain, dan formula hasil darab di sisi qubit kemudian membocorkan bilangan zarah.

Bina pokok sembarangan​

Pembina rantai dan pembina bulatan-pertama-lebar merangkumi keluarga seragam, tetapi antara muka am mengambil satu pasangan (parent, label) bagi setiap nod, dengan None untuk akar (API C mengambil indeks akar sebagai gantinya). Ini penting kerana pokok yang berbaloi dicari biasanya bukan rantai mahupun seragam – algoritma Bonsai, sebagai contoh, menumbuhkan pokok rentang bagi graf gandingan peranti, jadi percabangannya mengikut ketersambungan itu.

>>> # Node 0 branches three ways, node 1 twice, and node 4 carries a single child.
>>> tree = TernaryTree([None, (0, "X"), (0, "Y"), (0, "Z"), (1, "X"), (1, "Z"), (4, "Y")])
>>> tree.num_nodes, tree.num_legs, tree.max_weight
(7, 15, 4)
>>> tree.children(0)
{'X': 1, 'Y': 2, 'Z': 3}

Perhatikan bilangan daun: ia sentiasa 2n+12n+1, walau apa jua bentuknya. Nod dengan lebih sedikit anak tidak menjana lebih sedikit rentetan Pauli – pautannya yang tidak digunakan ialah daun, dan daun mengeja rentetan sama seperti keturunan sesuatu tepi. Daripada 2n+12n+1 rentetan itu, 2n2n dipasangkan menjadi operator Majorana bagi nn mod, dan tepat satu tertinggal.

Jumlah pariti​

Daun yang tertinggal itu ialah jumlah pariti fermion ∏j(1−2nj)\prod_j (1 - 2 n_j). Ia ialah sifat pengekodan dan bukannya pemetaan mana-mana operator, jadi ia ialah kaedah pada pengekodan itu sendiri:

>>> TernaryTreeEncoding(TernaryTree.chain(4, "Z")).total_parity(4)
<SparseObservable with 1 term on 4 qubits: (1+0j)(Z_3 Z_2 Z_1 Z_0)>
>>> TernaryTreeEncoding(TernaryTree.breadth_first(4, 3)).total_parity(4)
<SparseObservable with 1 term on 4 qubits: (1+0j)(Z_3 Z_0)>

Seperti yang ditunjukkan oleh kes seimbang, ini bukan secara amnya rentetan semua-ZZ: ia ialah daun yang dicapai melalui laluan semua-ZZ, yang bertindak sebagai identiti pada setiap nod yang tidak berada pada laluan itu.

Penting

Jumlah pariti di sini ialah cerapan untuk diukur, bukan kekangan untuk dikenakan. Kedua-dua nilai eigennya adalah fizikal, jadi jangan unjurkan keadaan ke sektor +1+1: pengekodan pokok ternari menggunakan satu qubit bagi setiap mod dan adalah keseluruhan (onto) ruang berdimensi 2n2^n, tanpa meninggalkan subruang tidak fizikal untuk dibuang melalui unjuran.

Contoh terperinci: pokok Bravyi-Kitaev​

Spesifikasi lebih kerap dikira daripada ditaip, kerana pokok untuk pengekodan sebenar jarang cukup kecil untuk ditulis dengan tangan. Bravyi-Kitaev ialah contoh yang baik: ia tergolong dalam keluarga ini, tetapi pokoknya tidak seragam, jadi tiada pembina kemudahan yang merangkuminya.

Pokoknya dibina melalui pembahagian rekursif ke atas nod, satu bagi setiap mod. Dalam julat nod [l,r][l, r], biarkan hh ialah kuasa dua terbesar yang muat; nod yang diletakkan untuk julat itu ialah l+h−1l + h - 1, yang terakhir dalam blok tersebut. Pautan X nya menurun ke pokok yang dibina daripada blok sebelumnya dan pautan Z nya ke pokok yang dibina daripada baki selepasnya, meninggalkan pautan Y nya sebagai daun:

>>> def bravyi_kitaev_tree(num_modes: int) -> TernaryTree:
... """Builds the ternary tree of the Bravyi-Kitaev encoding on ``num_modes`` modes."""
... spec: list[tuple[int, str] | None] = [None] * num_modes
... def build(left: int, right: int) -> int | None:
... if left > right:
... return None # an empty range: the parent's link stays a leg
... block = 1
... while 2 * block <= right - left + 1:
... block *= 2
... node = left + block - 1
... for child, label in (
... (build(left, node - 1), "X"), # the block before this node
... (build(node + 1, right), "Z"), # the remainder after it
... ):
... if child is not None:
... spec[child] = (node, label)
... return node
... build(0, num_modes - 1)
... return TernaryTree(spec)

Pada empat mod seluruh julat ialah satu blok, jadi nod yang diletakkan dahulu ialah 3, dengan [0,2][0, 2] sebelumnya dan tiada apa-apa selepasnya; sub-julat itu memberikan nod 1 di atas nod tunggal 0 dan 2. Menyusun pokok mengesahkan bahawa pengekodan itu ialah Bravyi-Kitaev dan bukan sekadar pokok dengan kelas bentuk yang sama – imej Majorana pertamanya ialah X0X1X3X_0 X_1 X_3:

>>> tree = bravyi_kitaev_tree(4)
>>> tree.children(1)
{'X': 0, 'Z': 2}
>>> encoding = TernaryTreeEncoding(tree)
>>> encoding.majorana_image(0)
[(0, 'X'), (1, 'X'), (3, 'X')]

Jumlah paritinya menjadikan perkara dalam bahagian sebelumnya konkrit: daun yang tertinggal ialah yang dicapai melalui laluan semua-ZZ, dan di sini laluan itu berhenti pada akar, jadi cerapan itu ialah Z3Z_3 satu-qubit dan bukannya rentetan ke atas keempat-empat qubit:

>>> encoding.total_parity(4)
<SparseObservable with 1 term on 4 qubits: (1+0j)(Z_3)>

Penskalaan ke atas tidak memerlukan apa-apa selain hujah yang lebih besar. Oleh sebab tiada nod yang pernah menggunakan pautan Y nya untuk tepi, setiap satu bercabang paling banyak dua arah, jadi pemberat Pauli bertambah secara logaritma dan bukannya secara linear:

>>> [bravyi_kitaev_tree(n).max_weight for n in (4, 8, 16, 32, 64)]
[3, 4, 5, 6, 7]