Introducere în primitive
Versiuni de pachete
Codul de pe această pagină a fost dezvoltat folosind cerințele de mai jos. Îți recomandăm să folosești aceste versiuni sau unele mai noi.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Versiunea beta a unui nou model de execuție este acum disponibilă. Modelul de execuție dirijată oferă mai multă flexibilitate la personalizarea fluxului de lucru pentru atenuarea erorilor. Consultați ghidul Modelul de execuție dirijată pentru mai multe informații.
De ce a introdus Qiskit primitive?
Similar cu primele zile ale calculatoarelor clasice, când dezvoltatorii trebuiau să manipuleze direct registrele CPU, interfața timpurie cu QPU-urile returna pur și simplu datele brute de la electronica de control.
Aceasta nu era o problemă majoră atunci când QPU-urile se aflau în laboratoare și permiteau accesul direct doar cercetătorilor.
Recunoscând că majoritatea dezvoltatorilor nu ar trebui și nu ar trebui să fie familiari cu distilarea unor astfel de date brute în 0 și 1, Qiskit a introdus backend.run, o primă abstractizare pentru accesarea QPU-urilor în cloud. Aceasta le-a permis dezvoltatorilor
să opereze într-un format de date familiar și să se concentreze pe imaginea de ansamblu.
Pe măsură ce accesul la QPU-uri a devenit mai răspândit, iar mai mulți algoritmi cuantici au fost dezvoltați,
a apărut din nou nevoia unei abstractizări de nivel mai înalt. Ca răspuns, Qiskit a introdus
interfața de primitive, optimizată pentru două sarcini de bază în dezvoltarea algoritmilor cuantici:
estimarea valorii de așteptare (Estimator) și eșantionarea circuitelor (Sampler). Obiectivul este din nou
să îi ajute pe dezvoltatori să se concentreze mai mult pe inovație și mai puțin pe conversia datelor. Interfața de primitive înlocuiește interfața backend.run, deoarece Sampler oferă același acces direct la hardware care era oferit de backend.run.
Ce este o primitivă?
Sistemele de calcul sunt construite pe mai multe niveluri de abstractizare. Abstractizările îți permit să te concentrezi pe un anumit nivel de detaliu relevant pentru sarcina în curs. Cu cât ești mai aproape de hardware, cu atât ai nevoie de un nivel mai scăzut de abstractizare (de exemplu, ar putea fi necesar să muți sau să manipulezi date la nivelul instrucțiunilor CPU). Cu cât sarcina pe care vrei să o efectuezi este mai complexă, cu atât abstractizările vor fi de nivel mai înalt (de exemplu, ai putea folosi o bibliotecă de programare pentru a efectua calcule algebrice).
În acest context, o primitivă este cea mai mică instrucțiune de procesare, cel mai simplu bloc de construcție din care cineva poate crea ceva util pentru un anumit nivel de abstractizare.
Progresele recente în domeniul calculului cuantic au crescut nevoia de a lucra la niveluri mai înalte de abstractizare. Pe măsură ce domeniul se îndreaptă spre unități de procesare cuantică (QPU) mai mari și fluxuri de lucru mai complexe, accentul se mută de la interacțiunea cu semnalele individuale ale qubiților la vizualizarea dispozitivelor cuantice ca sisteme care efectuează sarcini necesare.
Cele mai frecvente două sarcini pentru calculatoarele cuantice sunt eșantionarea stărilor cuantice și calcularea valorilor de așteptare. Aceste sarcini au motivat designul primitivelor Qiskit: Estimator și Sampler.
- Estimator calculează valorile de așteptare ale observabilelor față de stările pregătite de Circuit-uri cuantice.
- Sampler eșantionează registrul de ieșire din execuția Circuit-ului cuantic.
Pe scurt, modelul de calcul introdus de primitivele Qiskit mută programarea cuantică cu un pas mai aproape de unde se află astăzi programarea clasică, unde accentul este mai puțin pe detaliile hardware și mai mult pe rezultatele pe care încerci să le obții.
Definiția și implementările primitivelor
Există două tipuri de primitive Qiskit: clasele de bază și implementările lor. Primitivele Qiskit sunt definite prin clase de bază primitive open-source care se află în Qiskit SDK (în modulul qiskit.primitives). Furnizorii (cum ar fi Qiskit Runtime) pot folosi aceste clase de bază pentru a-și deriva propriile implementări de Sampler și Estimator. Majoritatea utilizatorilor vor interacționa cu implementările furnizorilor, nu cu primitivele de bază.
Clase de bază
BaseEstimatorV2 și BaseSamplerV2 - Clase de bază abstracte care definesc o interfață comună pentru implementarea primitivelor. Toate celelalte clase din modulul qiskit.primitives moștenesc din aceste clase de bază. Dezvoltatorii ar trebui să le folosească dacă sunt interesați să creeze propriul model de execuție bazat pe primitive pentru un anumit furnizor. Aceste clase ar putea fi, de asemenea, utile pentru cei care doresc să efectueze procesări foarte personalizate și consideră că implementările existente de primitive sunt prea simple pentru nevoile lor. Utilizatorii generali nu vor folosi direct clasele de bază.
Implementări
Acestea sunt implementări ale claselor de bază primitive:
-
Primitivele Qiskit Runtime (
EstimatorV2șiSamplerV2) oferă o implementare mai sofisticată (de exemplu, incluzând atenuarea erorilor) ca serviciu bazat pe cloud. Această implementare a primitivelor de bază este folosită pentru a accesa hardware-ul IBM Quantum®. Sunt accesate prin IBM Qiskit Runtime. -
StatevectorEstimatorșiStatevectorSampler- Implementări de referință ale primitivelor care folosesc simulatorul integrat în Qiskit. Sunt construite cu modulul Qiskitquantum_info, producând rezultate bazate pe simulări ideale de tip statevector. Sunt accesate prin Qiskit. -
BackendEstimatorV2șiBackendSamplerV2- Poți folosi aceste clase pentru a „împacheta" orice resursă de calcul cuantic într-o primitivă. Aceasta îți permite să scrii cod în stil de primitivă pentru furnizorii care nu au încă o interfață bazată pe primitive. Aceste clase pot fi folosite la fel ca Sampler și Estimator obișnuite, cu excepția că trebuie inițializate cu un argument suplimentarbackendpentru a selecta pe ce calculator cuantic să ruleze. Sunt accesate folosind Qiskit.
Beneficiile primitivelor Qiskit
Cu primitive, utilizatorii Qiskit pot scrie cod cuantic pentru un QPU specific fără a trebui să gestioneze explicit
fiecare detaliu. De asemenea, datorită nivelului suplimentar de abstractizare, este posibil să poți accesa mai ușor
capabilitățile hardware avansate ale unui anumit furnizor. De exemplu, cu primitivele Qiskit Runtime,
poți profita de cele mai recente progrese în atenuarea și suprimarea erorilor prin comutarea unor opțiuni precum resilience_level al primitivei, în loc să construiești propria implementare a acestor tehnici.
Pentru furnizorii de hardware, implementarea nativă a primitivelor înseamnă că poți oferi utilizatorilor tăi un mod mai „gata de utilizare" de a accesa funcțiile hardware, cum ar fi tehnicile avansate de post-procesare. Astfel, este mai ușor pentru utilizatorii tăi să beneficieze de cele mai bune capabilități ale hardware-ului tău.
Detalii despre primitive
Așa cum s-a descris anterior, toate primitivele sunt create din clasele de bază; prin urmare, au aceeași structură și utilizare generală. De exemplu, formatul intrării pentru toate primitivele Estimator este același. Cu toate acestea, există diferențe în implementări care le fac unice.
Deoarece majoritatea utilizatorilor accesează primitivele Qiskit Runtime, exemplele din restul acestei secțiuni se bazează pe primitivele Qiskit Runtime.
Estimator
Primitiva Estimator calculează valorile de așteptare pentru unul sau mai multe observabile față de stările pregătite de Circuit-uri cuantice. Circuit-urile pot fi parametrizate, atâta timp cât valorile parametrilor sunt, de asemenea, furnizate ca intrare primitivei.
Intrarea este un array de PUB-uri. Fiecare PUB are formatul:
(<circuit unic>, <unul sau mai multe observabile>, <valori opționale ale parametrilor>, <precizie opțională>),
unde valorile parametrilor opționale pot fi o listă sau un singur parametru. Diferite implementări ale Estimator suportă diverse opțiuni de configurare. Dacă intrarea conține măsurători, acestea sunt ignorate.
Ieșirea este un PubResult care conține valorile de așteptare calculate per pereche și erorile lor standard, în formă de PubResult. Fiecare PubResult conține atât date, cât și metadate.
Estimator combină elemente din observabile și valori ale parametrilor urmând regulile de broadcasting NumPy, descrise în subiectul Intrări și ieșiri pentru primitive.
Exemplu:
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
# This cell is hidden from users, it creates the circuits and observables to run
from qiskit_ibm_runtime import EstimatorV2, SamplerV2, QiskitRuntimeService
from qiskit.circuit.random import random_circuit
from qiskit.circuit import Parameter
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
import numpy as np
service = QiskitRuntimeService()
backend = service.least_busy()
phi = Parameter("phi")
circuit1 = random_circuit(10, 5, seed=12345)
circuit1.rzz(phi, 1, 2)
observable1 = SparsePauliOp.from_sparse_list(
[("ZXYZ", [1, 2, 3, 4], 1)], num_qubits=10
)
param_values1 = np.random.uniform(size=5).T
circuit2 = random_circuit(10, 5, seed=12345)
circuit2.rzz(phi, 1, 2)
observable2 = SparsePauliOp.from_sparse_list(
[("XZYX", [1, 2, 3, 4], 1)], num_qubits=10
)
param_values2 = np.random.uniform(size=5).T
shots1 = 164
shots2 = 1024
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
circuit1 = pm.run(circuit1)
circuit2 = pm.run(circuit2)
observable1 = observable1.apply_layout(circuit1.layout)
observable2 = observable2.apply_layout(circuit2.layout)
estimator = EstimatorV2(mode=backend)
estimator_job = estimator.run(
[
(circuit1, observable1, param_values1),
(circuit2, observable2, param_values2),
]
)
Sampler
Sarcina de bază a Sampler-ului este eșantionarea registrului de ieșire din execuția unuia sau mai multor Circuit-uri cuantice. Circuit-urile de intrare pot fi parametrizate, atâta timp cât valorile parametrilor sunt, de asemenea, furnizate ca intrare primitivei.
Intrarea este unul sau mai multe PUB-uri, în formatul:
(<circuit unic>, <una sau mai multe valori opționale ale parametrilor>, <număr opțional de shot-uri>),
unde pot exista mai multe elemente de tip valori ale parametrilor, iar fiecare element poate fi fie un array, fie un singur parametru, în funcție de Circuit-ul ales. În plus, intrarea trebuie să conțină măsurători.
Ieșirea este numărături sau măsurători per shot, ca obiecte PubResult, fără ponderi. Clasa de rezultate are, totuși, metode pentru a returna eșantioane ponderate, cum ar fi numărăturile. Consultați Intrări și ieșiri pentru primitive pentru detalii complete.
Exemplu:
# This cell is hidden from users, add measurement instructions to circuits
circuit1.measure_active()
circuit2.measure_active()
sampler = SamplerV2(mode=backend)
sampler_job = sampler.run(
[
(circuit1, param_values1, shots1),
(circuit2, param_values2, shots2),
]
)
Pași următori
- Citește Începe cu primitivele pentru a implementa primitive în activitatea ta.
- Consultă exemple detaliate de primitive.
- Exersează cu primitivele parcurgând lecția despre funcții de cost în IBM Quantum Learning.
- Consultă referința API EstimatorV2 și referința API SamplerV2.
- Citește Migrează la primitivele V2.