Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Découvrez comment envoyer un circuit quantique Qiskit avec le Kit de développement Azure Quantum (QDK). Vous pouvez envoyer des circuits Qiskit à Azure Quantum à l’aide du Kit de développement Azure Quantum (QDK) et jupyter Notebook dans Visual Studio Code (VS Code). Vous pouvez également tester vos circuits à l’aide du simulateur partiellement alloué local. Le QDK prend en charge les versions 1 et 2 de Qiskit.
Pour plus d’informations, consultez la page Circuits quantiques.
Prérequis
Pour les détails relatifs à l’installation, veuillez consulter la section Configuration de l’extension QDK.
Un espace de travail Azure Quantum dans votre abonnement Azure. Pour créer un espace de travail, consultez Créer un espace de travail Azure Quantum.
Un Python environnement avec Python et Pip installé.
VS Code avec le Kit de développement Azure Quantum et Pythonles extensions Jupyter installées.
La bibliothèque
qdkPython avec les extrasazureqiskitet le paquetipykernel.python -m pip install --upgrade "qdk[azure,qiskit]" ipykernel
Créer un notebook Jupyter Notebook
- Dans VS Code, ouvrez le menu Affichage et choisissez Palette de commandes.
- Entrez et sélectionnez Créer : Nouveau bloc-notes Jupyter.
- VS Code détecte et affiche la version de Python et l’environnement virtuel Python sélectionnés pour le notebook. Si vous avez plusieurs Python environnements, vous devrez peut-être sélectionner un noyau à l’aide du sélecteur de noyau en haut à droite. Si aucun environnement n’a été détecté, consultez Jupyter Notebooks dans VS Code pour obtenir des informations de configuration.
Charger les importations requises
Dans la première cellule de votre notebook, exécutez le code suivant pour charger les importations requises :
from qdk.azure import Workspace
from qdk.azure.qiskit import AzureQuantumProvider
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
Se connecter au service Azure Quantum
Pour connecter au service Azure Quantum, vous avez besoin de l’ID de la ressource et de l’emplacement de votre espace de travail Azure Quantum.
- Connectez-vous à votre compte Azure. https://portal.azure.com
- Sélectionnez votre espace de travail Azure Quantum, puis accédez à Vue d’ensemble.
- Copiez les paramètres d’ID de ressource et d’emplacement .
Ajoutez une nouvelle cellule dans votre bloc-notes et utilisez les informations de votre compte pour créer Workspace et AzureQuantumProvider objets pour vous connecter à votre espace de travail Azure Quantum.
workspace = Workspace(
resource_id = "", # Add the resourceID of your workspace
location = "" # Add the location of your workspace (for example "westus")
)
provider = AzureQuantumProvider(workspace)
Liste de tous les serveurs principaux
Vous pouvez maintenant imprimer tous les serveurs principaux d’informatique quantique disponibles dans votre espace de travail :
print("This workspace's targets:")
for backend in provider.backends():
print("- " + backend.name)
This workspace's targets:
- ionq.simulator
- ionq.qpu.aria-1
- ionq.qpu.forte-1
- ionq.qpu.forte-enterprise-1
- quantinuum.sim.h2-1sc
- quantinuum.sim.h2-2sc
- quantinuum.sim.h2-1e
- quantinuum.sim.h2-2e
- quantinuum.qpu.h2-1
- quantinuum.qpu.h2-2
- rigetti.sim.qvm
- rigetti.qpu.ankaa-3
- rigetti.qpu.cepheus-1-36q
Exécuter un circuit simple
Dans une nouvelle cellule, créez un circuit Qiskit simple.
# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(3, 3)
circuit.name = "Qiskit Sample - 3-qubit GHZ circuit"
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure([0,1,2], [0, 1, 2])
# Print out the circuit
circuit.draw()
┌───┐ ┌─┐
q_0: ┤ H ├──■───────┤M├──────
└───┘┌─┴─┐ └╥┘┌─┐
q_1: ─────┤ X ├──■───╫─┤M├───
└───┘┌─┴─┐ ║ └╥┘┌─┐
q_2: ──────────┤ X ├─╫──╫─┤M├
└───┘ ║ ║ └╥┘
c: 3/════════════════╩══╩══╩═
0 1 2
Sélectionnez une target option pour exécuter votre programme
Exécuter sur le simulateur IonQ
Avant d’exécuter votre circuit sur du matériel réel, testez votre circuit dans le simulateur. Permet get_backend de créer un Backend objet pour se connecter au serveur principal du simulateur IonQ :
simulator_backend = provider.get_backend("ionq.simulator")
Les back-ends IonQ prennent en charge les portes d’un ensemble de portes défini, qui sont compilées pour s’exécuter de façon optimale sur le matériel. Si votre circuit contient des portes qui ne figurent pas dans cette liste, vous devez transpiler dans la fonction prise en charge gateset à l’aide de la transpile fonction fournie par Qiskit :
from qiskit import transpile
circuit = transpile(circuit, simulator_backend)
La fonction transpile retourne un nouvel objet de circuit où les portes sont décomposées en portes prises en charge sur le back-end spécifié.
Vous pouvez maintenant exécuter le programme par le biais du service Azure Quantum et obtenir le résultat. La cellule suivante envoie un travail qui exécute le circuit avec 100 captures :
job = simulator_backend.run(circuit, shots=8)
job_id = job.id()
print("Job id", job_id)
Job id 00000000-0000-0000-0000-000000000000
Pour attendre la fin du travail et retourner les résultats, exécutez :
result = job.result()
print(result)
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=8, success=True, meas_level=2, data=ExperimentResultData(counts={'000': 4, '111': 4}, memory=['000', '000', '000', '000', '111', '111', '111', '111'], probabilities={'000': 0.5, '111': 0.5}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits=3, metadata={}), status=JobStatus.DONE, name='Qiskit Sample - 3-qubit GHZ circuit')], date=None, status=None, header=None, error_data=None)
Étant donné que le résultat est un type d’objet spécifique au package Qiskit, utilisez result.get_counts et plot_histogram visualisez les résultats. Pour représenter toutes les étiquettes de chaîne de bits possibles, ajoutez les étiquettes à counts.
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
{'000': 4, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 4}
Vous pouvez également utiliser la fonction get_memory pour afficher des données de prise de vue individuelles à partir de la tâche :
result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']
Remarque
Sur IonQ targets, si vous soumettez un travail avec un nombre impair de tirs, le nombre de tirs est arrondi au nombre pair le plus proche. Par exemple, si vous spécifiez 9 captures, les résultats affichent les données pour 8 captures.
Estimer le coût du travail
Estimer le coût d’exécution d’un travail avant d’exécuter un travail sur le QPU.
Pour obtenir les informations de tarification les plus actuelles, consultez tarification IonQ, ou recherchez votre espace de travail et affichez les options de tarification sous l’onglet Fournisseur de votre espace de travail via : aka.ms/aq/myworkspaces.
Exécuter sur la QPU IonQ
Pour vous connecter à du matériel réel (une unité de processeur quantique (QPU)), indiquez simplement le nom de target"ionq.qpu.aria-1" la get_backend méthode :
qpu_backend = provider.get_backend("ionq.qpu.aria-1")
Envoyez le circuit à exécuter sur Azure Quantum, obtenez les résultats, puis exécutez-le plot_histogram pour tracer les résultats.
Remarque
Le temps nécessaire à l’exécution d’un circuit sur le processeur quantique peut varier en fonction des durées de file d’attente actuelles.
# Submit the circuit to run on Azure Quantum
job = qpu_backend.run(circuit, shots=100)
job_id = job.id()
print("Job id", job_id)
# Get the job results (this method waits for the Job to complete):
result = job.result()
print(result)
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
Job id 00000000-0000-0000-0000-000000000000
Job Status: job has successfully run
Result(backend_name='ionq.qpu.aria-1', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(counts={'0': 505, '1': 6, '2': 1, '3': 1, '4': 1, '5': 10, '6': 11, '7': 488}, probabilities={'0': 0.4932, '1': 0.0059, '2': 0.001, '3': 0.001, '4': 0.001, '5': 0.0098, '6': 0.0117, '7': 0.4766}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits='3', qiskit='True'))])
{'000': 505, '001': 6, '010': 1, '011': 1, '100': 1, '101': 10, '110': 11, '111': 488}
Important
Vous ne pouvez pas envoyer plusieurs circuits sur un seul travail. Pour contourner ce problème, vous pouvez appeler la backend.run méthode pour envoyer chaque circuit de manière asynchrone, puis extraire les résultats de chaque travail. Par exemple :
jobs = []
for circuit in circuits:
jobs.append(backend.run(circuit, shots=N))
results = []
for job in jobs:
results.append(job.result())
Prérequis
Pour les détails relatifs à l’installation, veuillez consulter la section Configuration de l’extension QDK.
Un Python environnement avec Python et Pip installé.
VS Code avec le Kit de développement Azure Quantum et Python les extensions installées.
Le package
qdkPython avec les extrasqiskitetjupyter.python pip install "qdk[qiskit,jupyter]"
Exécuter un circuit de base
Dans VS Code, ouvrez un Python nouveau fichier pour créer et exécuter un circuit de base avec le simulateur épars intégré à partir du module qsharp.
# load the required imports
from qdk import qsharp
from qsharp.interop.qiskit import QSharpBackend
from qiskit.circuit.random import random_circuit
# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)
# run the circuit using the built-in sparse simulator
backend = QSharpBackend()
job = backend.run(circuit)
counts = job.result().get_counts()
print(counts)
Pour exécuter le programme, sélectionnez l’icône Exécuter en haut à droite, puis sélectionnez Exécuter Python le fichier. La sortie s’affiche dans une nouvelle fenêtre de terminal.
┌─────────────────────────┐┌─┐
q_0: ─■───────────┤0 ├┤M├───
│P(0.79983) │ (XX-YY)(1.9337,1.7385) │└╥┘┌─┐
q_1: ─■───────────┤1 ├─╫─┤M├
└─────────────────────────┘ ║ └╥┘
c: 2/═════════════════════════════════════════╩══╩═
0 1
{'11': 680, '00': 344}
Générer un QIR pour le circuit
À partir de ce même circuit, vous pouvez générer un QIR utilisé pour s’exécuter sur du matériel quantique.
Remarque
Pour générer le QIR, tous les registres doivent être mesurés. S’il existe des registres inutilisés, une erreur est générée. En outre, vous obtenez une erreur lorsque vous tentez de générer QIR avec un Unrestrictedtarget profil. Le profil Unrestricted est valide uniquement pour la simulation. Vous devez utiliser TargetProfile.Base, TargetProfile.Adaptive_RIou TargetProfile.Adaptive_RIF. Vous pouvez remplacer target_profile dans l'appel backend.qir(...) pour basculer entre les profils.
Importer
QSharpErroretTargetProfilefrom qdk.qsharp import QSharpError, TargetProfilePour générer QIR, modifiez la sortie :
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
Votre code doit maintenant ressembler à ceci :
# load the required imports
from qdk import qsharp
from qsharp import QSharpError, TargetProfile
from qsharp.interop.qiskit import QSharpBackend
from qiskit.circuit.random import random_circuit
# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)
# generate QIR for the circuit
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
La sortie de votre code doit ressembler à ceci :
┌────────────┐ ┌─┐
q_0: ┤ Rx(2.7195) ├─■───────────┤M├───
└──┬─────┬───┘ │U1(5.5924) └╥┘┌─┐
q_1: ───┤ Tdg ├─────■────────────╫─┤M├
└─────┘ ║ └╥┘
c: 2/════════════════════════════╩══╩═
0 1
%Result = type opaque
%Qubit = type opaque
define void @ENTRYPOINT__main() #0 {
block_0:
call void @__quantum__qis__rx__body(double 2.7194945105768586, %Qubit* inttoptr (i64 0 to %Qubit*))
call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 0 to %Qubit*))
call void @__quantum__qis__t__adj(%Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__rz__body(double -2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
call void @__quantum__rt__array_record_output(i64 2, i8* null)
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
ret void
}
declare void @__quantum__qis__rx__body(double, %Qubit*)
declare void @__quantum__qis__rz__body(double, %Qubit*)
declare void @__quantum__qis__t__adj(%Qubit*)
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
declare void @__quantum__rt__array_record_output(i64, i8*)
declare void @__quantum__rt__result_record_output(%Result*, i8*)
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
attributes #1 = { "irreversible" }
; module flags
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}
!4 = !{i32 1, !"classical_ints", i1 true}
!5 = !{i32 1, !"qubit_resetting", i1 true}
!6 = !{i32 1, !"classical_floats", i1 false}
!7 = !{i32 1, !"backwards_branching", i1 false}
!8 = !{i32 1, !"classical_fixed_points", i1 false}
!9 = !{i32 1, !"user_functions", i1 false}
!10 = !{i32 1, !"multiple_target_branching", i1 false}
Tous les programmes ne peuvent pas s’exécuter sur tout le matériel. Ici, si vous essayez de target le profil Base, alors vous obtenez des erreurs détaillées sur les parties du programme qui ne sont pas prises en charge.
try:
backend.qir(qc, target_profile=TargetProfile.Base)
except QSharpError as e:
print(e)