Sari la conținutul principal
Acest proiect este în versiune beta. Ai găsit o eroare? Deschide un issue pe GitHub. Ai o întrebare sau o idee? Întreabă în Discussions — ne-ar plăcea să aflăm părerea ta!
Cum este calitatea traducerii pe această pagină?

Lucrul cu circuite bosonice

Un BosonicCircuit exprimă un calcul direct pe moduri bosonice. Nu poartă nicio trunchiere, nicio codificare și niciun număr de qubiți: acestea intervin mai târziu, în timpul transpilării, ceea ce permite ca un singur circuit să fie coborât sub mai multe codificări și mai multe trunchieri fără a fi reconstruit.

Expune în mod deliberat un API redus în comparație cu QuantumCircuit din Qiskit, astfel încât porțile de qubiți nu pot fi aplicate unui mod bosonic, ceea ce nu ar fi o operație bine definită. Acest ghid tratează operațiile care sunt expuse pentru asamblarea unor circuite mai mari din altele mai mici.

De ce să folosești circuite bosonice​

Ia în considerare fluxul de lucru tradițional pentru a pune evoluția în timp a unui Hamiltonian bosonic pe o arhitectură bazată pe qubiți:

  1. Definește Hamiltonianul bosonic, de exemplu H=−∑ijbi†bjH = -\sum_{ij} b^\dagger_i b_j.

  2. Alege o trunchiere și o codificare și mapează cu ele Hamiltonianul la un operator de qubiți.

  3. Implementează evoluția în timp în spațiul qubiților, prin trotterizare sau altă metodă.

Al doilea pas vine devreme și ia două decizii care sunt costisitoare de retras. Trunchierea fixează câte niveluri păstrează fiecare mod, iar codificarea fixează câți qubiți costă aceasta, deci ambele sunt fixate în operatorul de qubiți înainte de a se fi făcut orice altceva cu circuitul. Pentru a privi aceeași fizică sub o altă limită sau o altă codificare, mapezi din nou Hamiltonianul și construiești din nou circuitul. Ceea ce aruncă maparea, de asemenea, este structura bosonică: ce termeni aparțin împreună și faptul că termenii unei perechi de salt sunt adjuncții unul altuia.

Un BosonicCircuit mută aceste decizii la final:

  1. Definește Hamiltonianul bosonic.

  2. Exprimă evoluția în timp direct pe moduri bosonice, cu porți bosonice.

  3. Alege trunchierea și codificarea ca parte a transpilării.

Circuitul descrie ce calcul se efectuează, iar transpilarea decide cum să fie pus pe qubiți. Același circuit este apoi coborât la fiecare limită și sub fiecare codificare, iar gruparea operatorului este în continuare acolo pentru pașii care o pot folosi. Secțiunile următoare arată cum se asamblează un astfel de circuit; Transpilarea circuitelor bosonice îl arată coborât.

Indexarea generică a modurilor​

Modulul operators și circuitul împart o convenție comună pentru moduri. Un mod este doar un index care etichetează un grad de libertate bosonic și nu are semnificație proprie. Poți așadar evolua orice operator care implementează protocolul OperatorTrait, indiferent ce reprezintă, iar circuitul nu trebuie niciodată să știe ce înseamnă modul 2. Același lucru este valabil pentru dimensiunea unui mod: un circuit nu are limită de ocupare, deci nimic de aici nu spune câte niveluri are un mod.

Adăugarea porților​

Porțile se adaugă pe moduri. Sunt acceptate doar instanțe 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)

Orice altceva este refuzat, iar eroarea denumește tipul vinovat:

>>> from qiskit.circuit.library import HGate
>>> try:
... prepare.append(HGate(), [0])
... except ValueError as error:
... print(error)
Unsupported instruction type: <class '...HGate'>

Compunerea circuitelor​

compose() plasează instrucțiunile unui circuit peste altul. Ele sunt inserate direct, nu împachetate într-o singură poartă, deci rezultatul este un circuit obișnuit pe care îl poți descompune și transpila în continuare.

>>> program = prepare.compose(step)
>>> program.draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A composed BosonicCircuit.

Implicit se returnează un circuit nou, iar ambii operanzi rămân neatinși. Transmite inplace=True pentru a-l modifica în schimb pe primul și front=True pentru a pune operandul înaintea instrucțiunilor existente:

>>> step.compose(prepare, front=True)._inner.data == program._inner.data
True

Un circuit mai îngust poate fi plasat pe un subset ales de moduri:

>>> 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>

A narrow-composed BosonicCircuit.

Doar un alt BosonicCircuit este acceptat ca operand, deoarece compose din Qiskit ar insera direct porți de qubiți și ar ocoli verificarea pe care o impune append.

Repetarea unui circuit​

repeat() repetă un circuit cap la cap. Repetările sunt aplatizate: rezultatul conține instrucțiunile de reps ori în secvență, în loc de o poartă care învelește circuitul. Prin urmare, numărul de operații crește cu reps, iar decompose acționează asupra corpului repetat în loc să elimine o repetare.

>>> len(step.repeat(0)._inner.data) # zero repetitions is the identity
0
>>> step.repeat(5).draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A repeated BosonicCircuit.

Aceasta este modalitatea la nivel de circuit de a trotteriza: evoluezi pentru un timp scurt și repeți. Vezi Sinteza unei porți Evolution în spațiul bosonic pentru alternativa de a alege o formulă de produs pe poarta însăși și pentru motivul pentru care cele două sunt lucruri diferite care împart întâmplător cuvântul „repetări”.

Separarea pașilor cu bariere​

O barieră marchează un punct de sincronizare peste care pașii de optimizare nu fuzionează porți. barrier() plasează una pe toate modurile sau pe modurile pe care le denumești:

>>> 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>

A BosonicCircuit with barriers.

repeat(..., insert_barriers=True) pune una între repetările consecutive și niciuna după ultima:

>>> step.repeat(3, insert_barriers=True).draw("mpl", fold=-1)
<Figure size ... with 1 Axes>

A repeated BosonicCircuit with barriers.

Barierele și codificarea​

O codificare necesită mai mulți qubiți per mod, deci registrul de moduri și registrul de qubiți diferă ca dimensiune, iar un layout pune în relație registre întregi. Un mod nu are așadar qubiți proprii la care să restrângă o barieră. În timpul sintezei boson-către-qubit, o barieră este mapată pe fiecare qubit al fiecărui registru pe care l-a atins, ceea ce este corect sub orice 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>

A QuantumCircuit showing the expansion of barrier to cover the entire qubit register.

Citirea unui circuit bosonic​

Un BosonicCircuit nu are measure sau measure_all. Ce înseamnă un bit măsurat depinde de codificare. Sub o codificare unară, ocuparea unui mod este răspândită pe mai mulți qubiți și trebuie citită dintr-un tipar de biți, iar sub una compactă este un număr binar, deci o măsurare care denumește un mod ar trebui să cunoască codificarea, ceea ce un circuit bosonic în mod deliberat nu face. Măsoară în schimb QuantumCircuit transpilat și decodifică șirurile de biți cu LevelEncoding.level_to_bits() și cu decalajele din LevelSpec cu care ai coborât. Simulează dinamica Bose-Hubbard cu o codificare la alegere face acest lucru pentru un model complet.

>>> hasattr(BosonicCircuit, "measure_all")
False

Pașii următori​