Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Informazioni su come inviare un circuito quantistico Qiskit usando il azure-quantumPython pacchetto. È possibile inviare circuiti Qiskit ad Azure Quantum usando Azure Quantum Development Kit (QDK) e Jupyter Notebook in Visual Studio Code (VS Code). È anche possibile testare i circuiti usando il simulatore di tipo sparse locale.
Per altre informazioni, vedere Circuiti quantistici.
Prerequisiti
Per informazioni dettagliate sull'installazione, vedere Configurare l'estensione QDK.
Un'area di lavoro di Azure Quantum nella sottoscrizione di Azure. Per creare un'area di lavoro, vedere Creare un'area di lavoro di Azure Quantum.
Ambiente Python con Python e Pip installato.
VS Code con estensioni Azure Quantum Development Kit, Pythone Jupyter installate.
La libreria
qdkPython, il pacchettoazure-quantumPython con l'extraqiskite il pacchettoipykernel.Nota
Se il kernel Python Jupyter
ipykernelnon viene rilevato, Visual Studio Code richiederà l'installazione.python -m pip install --upgrade azure-quantum[qiskit] qdk ipykernelImportante
Assicurarsi di avere la versione più recente di Qiskit. Per ulteriori informazioni, vedere l'argomento Aggiornare il pacchetto azure-quantumPython.
Creare un nuovo notebook di Jupyter
- In VS Code aprire il menu Visualizza e scegliere Riquadro comandi.
- Inserire e selezionare Crea: Nuovo Jupyter Notebook.
- Vs Code rileva e visualizza la versione di Python e l'ambiente virtuale Python selezionato per il notebook. Se si dispone di più Python ambienti, potrebbe essere necessario selezionare un kernel utilizzando il selettore di kernel in alto a destra. Se non è stato rilevato alcun ambiente, vedere Jupyter Notebooks in VS Code per informazioni sull'installazione.
Caricare le importazioni necessarie
Nella prima cella del notebook eseguire il codice seguente per caricare le importazioni necessarie:
import azure.quantum
from azure.quantum import Workspace
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from azure.quantum.qiskit import AzureQuantumProvider
Connettersi al servizio Azure Quantum
Per connettersi al servizio Azure Quantum, è necessario avere l'ID risorsa e la posizione dell'area di lavoro di Azure Quantum.
Accedi al tuo account Azure, https://portal.azure.com,
Selezionare l'area di lavoro di Azure Quantum e passare a Panoramica.
Copiare i parametri nei campi.
Aggiungere una nuova cella nel notebook e usare le informazioni sull'account per creare gli oggetti Workspace e AzureQuantumProvider per connettersi all'area di lavoro di 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)
Elenca tutti i back-end
È ora possibile stampare tutti i back-end di calcolo quantistico disponibili nell'area di lavoro:
print("This workspace's targets:")
for backend in provider.backends():
print("- " + backend.name())
This workspace's targets:
- ionq.qpu
- ionq.qpu.aria-1
- ionq.simulator
- microsoft.estimator
- quantinuum.hqs-lt-s1
- quantinuum.hqs-lt-s1-apival
- quantinuum.hqs-lt-s2
- quantinuum.hqs-lt-s2-apival
- quantinuum.hqs-lt-s1-sim
- quantinuum.hqs-lt-s2-sim
- quantinuum.qpu.h2-1
- quantinuum.sim.h2-1sc
- quantinuum.sim.h2-1e
- rigetti.sim.qvm
- rigetti.qpu.ankaa-3
Eseguire un circuito semplice
Creare prima di tutto un circuito Qiskit semplice da eseguire.
# 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
Selezionare un target per eseguire il programma
Eseguire nel simulatore IonQ
Prima di eseguire su hardware reale, testare il circuito nel simulatore. Usare get_backend per creare un Backend oggetto per connettersi al back-end del simulatore IonQ:
simulator_backend = provider.get_backend("ionq.simulator")
I backend IonQ supportano i gate di un gateset definito, che vengono compilati per funzionare in modo ottimale sull'hardware. Se il circuito contiene cancelli che non sono inclusi in questo elenco, è necessario eseguire il transpile nell'oggetto supportato gateset usando la transpile funzione fornita da Qiskit:
from qiskit import transpile
circuit = transpile(circuit, simulator_backend)
La funzione transpile restituisce un nuovo oggetto di circuito in cui i cancelli vengono scomposti in cancelli supportati nel backend specificato.
È ora possibile eseguire il programma tramite il servizio Azure Quantum e ottenere il risultato. La cella seguente invia un processo che esegue il circuito con 100 scatti:
job = simulator_backend.run(circuit, shots=8)
job_id = job.id()
print("Job id", job_id)
Job id 00000000-0000-0000-0000-000000000000
Per attendere il completamento del processo e restituire i risultati, eseguire:
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)
Poiché il risultato è un oggetto nativo del pacchetto Qiskit, è possibile usare result.get_countse plot_histogram di Qiskit per visualizzare i risultati. Per assicurarsi che tutte le etichette di stringa di bit possibili siano rappresentate, aggiungerle a 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}
È anche possibile usare la funzione get_memory() per visualizzare i dati dello scatto individuale dal processo di lavoro.
result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']
Nota
In IonQ targets, se invii un lavoro con un numero dispari di colpi, il numero di colpi viene arrotondato per difetto al numero pari più vicino. Ad esempio, se si specificano 9 scatti, i risultati visualizzano i dati per 8 scatti.
Stimare il costo del lavoro
Prima di eseguire un processo nella QPU, è necessario stimare la quantità di costi dei processi da eseguire.
Per i dettagli più aggiornati sui prezzi, vedere Prezzi di IonQ oppure trovare l'area di lavoro e visualizzare le opzioni relative ai prezzi nella scheda Provider dell'area di lavoro tramite: aka.ms/aq/myworkspaces.
Esecuzione nella QPU di IonQ
Per connettersi all'hardware reale (un'unità di elaborazione quantistica, QPU), specificare semplicemente il nome dell'oggetto target nel metodo "ionq.qpu.aria-1".
qpu_backend = provider.get_backend("ionq.qpu.aria-1")
Inviare il circuito per l'esecuzione in Azure Quantum, ottenere i risultati ed eseguire plot_histogram per tracciare i risultati.
Nota
Il tempo necessario per eseguire un circuito nella QPU può variare a seconda dei tempi di coda correnti.
# 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}
Importante
L'invio di più circuiti in un singolo processo non è attualmente supportato. Come soluzione alternativa è possibile chiamare il backend.run metodo per inviare ogni circuito in modo asincrono, quindi recuperare i risultati di ogni processo. Ad esempio:
jobs = []
for circuit in circuits:
jobs.append(backend.run(circuit, shots=N))
results = []
for job in jobs:
results.append(job.result())
Prerequisiti
Per informazioni dettagliate sull'installazione, vedere Configurare l'estensione QDK.
Ambiente Python con Python e Pip installato.
VS Code con Azure Quantum Development Kit ed Python estensioni installate.
Pacchetto
qdkPython con iqiskitcomponenti aggiuntivi facoltativijupyter.python pip install "qdk[qiskit,jupyter]"Importante
Assicurarsi di avere la versione più recente di Qiskit. Per ulteriori informazioni, vedere l'argomento Aggiornare il pacchetto azure-quantumPython.
Eseguire un circuito di base
In VS Code aprire un nuovo Python file per definire ed eseguire un circuito di base con il simulatore sparse predefinito del qsharp pacchetto.
# 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)
Per eseguire il programma, selezionare l'icona Esegui in alto a destra e selezionare Esegui Python file. L'output viene visualizzato in una nuova finestra del terminale.
┌─────────────────────────┐┌─┐
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}
Generare QIR per il circuito
Da questo stesso circuito, è possibile generare qiR usato per l'esecuzione su hardware quantistico.
Nota
Per generare qir, tutti i registri devono essere misurati. Se sono presenti registri inutilizzati, viene generato un errore. Inoltre, viene visualizzato un errore quando si tenta di generare QIR con un Unrestrictedtarget profilo. Il profilo Unrestricted è valido solo per la simulazione. È necessario usare TargetProfile.Base, TargetProfile.Adaptive_RIo TargetProfile.Adaptive_RIF. È possibile eseguire l'override del parametro target_profile nella chiamata backend.qir(...) per commutare i profili.
Importare
QSharpErroreTargetProfilefrom qdk.qsharp import QSharpError, TargetProfilePer fare ciò, per generare il QIR, modifica l'output:
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
Il codice dovrebbe ora essere simile al seguente:
# 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))
L'output del codice dovrebbe essere simile al seguente:
┌────────────┐ ┌─┐
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}
Non tutti i programmi possono essere eseguiti su tutti gli hardware. In questo caso, se si prova a target il profilo Base, si ottengono errori dettagliati su quali parti del programma non sono supportate.
try:
backend.qir(qc, target_profile=TargetProfile.Base)
except QSharpError as e:
print(e)