Dela via


Skicka en krets med Qiskit till Azure Quantum

Lär dig hur du skickar en Qiskit-kvantkrets med hjälp av azure-quantumPython paketet. Du kan skicka Qiskit-kretsar till Azure Quantum med hjälp av en Azure Quantum-notebook-fil azure-quantumPython , som har ett inbyggt paket eller från din lokala dator. Du kan också testa dina kretsar med hjälp av den lokala sparse-simulatorn.

Mer information finns i Kvantkretsar.

Förutsättningar

Installationsinformation finns i Konfigurera QDK-tillägget.

Skapa en ny Jupyter Notebook

  1. I VS Code väljer du Visa > kommandopalett och väljer Skapa: Ny Jupyter Notebook.
  2. Längst upp till höger identifierar och visar VS Code den version av Python och den virtuella Python miljö som har valts för notebook-filen. Om du har flera Python miljöer kan du behöva välja en kernel med hjälp av kernelväljaren längst upp till höger. Om ingen miljö har identifierats kan du läsa mer i Jupyter Notebooks i VS Code .

Läs in nödvändiga importer

I den första cellen i anteckningsboken kör du följande kod för att läsa in de importer som krävs:

import azure.quantum
from azure.quantum import Workspace 
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from azure.quantum.qiskit import AzureQuantumProvider

Ansluta till Azure Quantum-tjänsten

Om du vill ansluta till Azure Quantum-tjänsten behöver du resurs-ID:t och platsen för din Azure Quantum-arbetsyta.

  1. Logga in på ditt Azure-konto, https://portal.azure.com,

  2. Välj din Azure Quantum-arbetsyta och gå till Översikt.

  3. Kopiera parametrarna i fälten.

    Skärmbild av Visual Studio Code som visar hur du expanderar översiktsfönstret för din Kvantarbetsyta.

Lägg till en ny cell i anteckningsboken och använd kontoinformationen för att skapa Workspace och AzureQuantumProvider objekt för att ansluta till din Azure Quantum-arbetsyta.

workspace = Workspace(  
    resource_id = "", # Add the resourceID of your workspace
    location = "" # Add the location of your workspace (for example "westus")
    )

provider = AzureQuantumProvider(workspace)

Visa en lista över alla serverdelar

Nu kan du skriva ut alla serverdelar för kvantberäkning som är tillgängliga på din arbetsyta:

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.h1-1
- quantinuum.sim.h1-1sc
- quantinuum.sim.h1-1e
- rigetti.sim.qvm
- rigetti.qpu.ankaa-9q-3
- rigetti.qpu.ankaa-3

Köra en enkel krets

Skapa först en enkel Qiskit-krets som ska köras.

# 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 

Välj en target för att köra programmet

Kör på IonQ-simulatorn

Innan vi kör på riktig maskinvara ska vi testa kretsen i simulatorn. Använd get_backend för att skapa ett Backend objekt för att ansluta till IonQ Simulator-serverdelen:

simulator_backend = provider.get_backend("ionq.simulator")

IonQ-serverdelar stöder portar från en definierad gateset som kompileras för att köras optimalt på maskinvaran. Om kretsen innehåller portar som inte finns i den här listan måste du gå vidare till den som stöds gateset med hjälp av funktionen transpile som tillhandahålls av Qiskit:

from qiskit import transpile
circuit = transpile(circuit, simulator_backend)

Transpile-funktionen returnerar ett nytt kretsobjekt där portar delas upp i portar som stöds på den angivna serverdelen.

Nu kan du köra programmet via Azure Quantum-tjänsten och få resultatet. Följande cell skickar ett jobb som kör kretsen med 100 skott:

job = simulator_backend.run(circuit, shots=8)
job_id = job.id()
print("Job id", job_id)
Job id 00000000-0000-0000-0000-000000000000

Om du vill vänta tills jobbet har slutförts och returnera resultatet kör du:

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)

Eftersom resultatet är ett objekt som är inbyggt i Qiskit-paketet kan du använda Qiskits result.get_counts och plot_histogram visualisera resultatet. För att se till att alla möjliga bitsträngsetiketter representeras lägger du till dem i 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}

Qiskit-kretsresultat på IonQ-simulator

Du kan också använda get_memory() funktionen för att visa enskilda skottdata från jobbet

result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']

Kommentar

Om du skickar ett jobb med ett udda antal skott i IonQ targetsavrundas resultatet ned till nästa jämna tal. Om du till exempel anger 9 skott visar resultatet data för 8 skott.

Beräkna jobbkostnad

Innan du kör ett jobb på QPU:n bör du uppskatta hur mycket det kostar att köra.

Den senaste prisinformationen finns i IonQ-priser eller hitta din arbetsyta och visa prisalternativ på fliken "Provider" på arbetsytan via: aka.ms/aq/myworkspaces.

Kör på IonQ QPU

Om du vill ansluta till verklig maskinvara (en kvantprocessorenhet (QPU)) anger du bara namnet target"ionq.qpu.aria-1"get_backend metoden:

qpu_backend = provider.get_backend("ionq.qpu.aria-1")

Skicka kretsen för att köra på Azure Quantum, hämta resultaten och kör plot_histogram för att rita resultatet.

Kommentar

Tiden som krävs för att köra en krets på QPU:n kan variera beroende på aktuella kötider.

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

Qiskit-kretsresultat på IonQ QPU

Viktigt!

Det går för närvarande inte att skicka flera kretsar på ett enda jobb. Som en lösning kan du anropa backend.run metoden för att skicka varje krets asynkront och sedan hämta resultatet av varje jobb. Till exempel:

jobs = []
for circuit in circuits:
    jobs.append(backend.run(circuit, shots=N))

results = []
for job in jobs:
    results.append(job.result())

Förutsättningar

Skapa en ny notebook-fil på din arbetsyta

  1. Logga in på Azure Portal och välj den arbetsyta som du skapade i föregående steg.
  2. Välj Notebooks på det vänstra bladet.
  3. Klicka på Mina anteckningsböcker och klicka på Lägg till ny.
  4. Skriv ett namn på filen, till exempel Qiskit.ipynb, och klicka på Skapa fil.

När den nya notebook-filen öppnas skapas automatiskt koden för den första cellen baserat på din prenumerations- och arbetsyteinformation.

from azure.quantum import Workspace
workspace = Workspace ( 
    resource_id = "", # Add your resource_id 
    location = ""  # Add your workspace location (for example, "westus") 
)

Kommentar

Om inget annat anges bör du köra varje cell i ordning när du skapar den för att undvika kompileringsproblem.

Klicka på den triangulära uppspelningsikonen till vänster om cellen för att köra koden.

Läs in nödvändiga importer

Först måste du importera några ytterligare moduler.

Klicka på + Kod för att lägga till en ny cell och lägg sedan till och kör följande kod:

from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from azure.quantum.qiskit import AzureQuantumProvider

Ansluta till Azure Quantum-tjänsten

Skapa sedan ett AzureQuantumProvider objekt med hjälp av Workspace objektet från föregående cell för att ansluta till din Azure Quantum-arbetsyta. Lägg till en ny cell med följande kod:

provider = AzureQuantumProvider(workspace)

Definiera en enkel krets

Skapa ett circuit objekt i en ny cell. Det här exemplet är en enkel slumpmässig kvantbitgenerator. Lägg till följande kod för att definiera och visa kretsen:

# 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 

Visa en lista över alla targets

Nu kan du visa alla kvantberäkning targets, eller serverdelar, som är tillgängliga på din arbetsyta. Lägg till en ny cell och kör följande rad:

print("This workspace's targets:")
for backend in provider.backends():
    print("- " + backend.name())
This workspace's targets:
- ionq.simulator
- ionq.qpu.aria-1
- microsoft.estimator
- quantinuum.qpu.h1-1
- quantinuum.sim.h1-1sc
- quantinuum.sim.h1-1e
- rigetti.sim.qvm
- rigetti.qpu.ankaa-9q-3
- rigetti.qpu.ankaa-3    

Välj en target för att köra programmet

Om du vill kontrollera koden innan du kör den på den faktiska kvantmaskinvaran kan du använda kvantsimulatorn IonQ, ionq.simulator.

Lägg till en ny cell och skapa ett objekt som representerar IonQ-kvantsimulatorn target:

# Get IonQ quantum simulator target:
simulator_backend = provider.get_backend("ionq.simulator")

Kör på IonQ-simulatorn

Om du vill köra kretsen i simulatorn lägger du till följande kod. I det run här exemplet används metoden target för att skicka jobbet och övervakar sedan jobbstatusen.

# Submit the circuit to run on Azure Quantum
job = simulator_backend.run(circuit, shots=8)
job_id = job.id()
print("Job id", job_id)

När jobbet har körts hämtar du jobbresultatet och visar dem:

# Get the job results:
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)

Eftersom den här result typen är ett objekt som är inbyggt i Qiskit-paketet kan du använda Qiskits result.get_counts och plot_histogram visualisera resultaten. För att se till att alla möjliga bitsträngsetiketter representeras lägger du till dem i 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}

Qiskit-kretsresultat på IonQ-simulator

Du kan också använda get_memory() funktionen för att visa enskilda skottdata från jobbet

result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']

Kommentar

Om du skickar ett jobb med ett udda antal skott i IonQ targetsavrundas resultatet ned till nästa jämna tal. Om du till exempel anger 9 skott visar resultatet data för 8 skott.

Beräkna jobbkostnad

Innan du kör ett jobb på den faktiska kvantmaskinvaran eller en kvantbearbetningsenhet (QPU) bör du uppskatta hur mycket det kostar att köra.

Den senaste prisinformationen finns i IonQ-priser eller hitta din arbetsyta och visa prisalternativ på bladet Providers på din arbetsyta.

Kör på IonQ QPU

När du har kört jobbet på IonQ-simulatorn och beräknat QPU-kostnaden är det dags att köra kretsen på maskinvaran.

Kommentar

Tiden som krävs för att köra en krets på QPU:n varierar beroende på aktuella kötider. Du kan visa den genomsnittliga kötiden för en target genom att välja bladet Providers för din arbetsyta.

Använd samma run metod och åtgärder som du använde tidigare med API Validator för att skicka och övervaka ditt jobb:

# Submit the circuit to run on Azure Quantum
job = qpu_backend.run(circuit, shots=100)
job_id = job.id()
print("Job id", job_id)

När jobbet är klart hämtar du jobbresultatet som tidigare och visar dem i ett diagram:

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 910b5ac8-98cd-11ec-b3ba-00155d5528cf
Job Status: job has successfully run
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='Job id 54e8c740-98d9-11ec-b382-00155d957f5d', 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}

Qiskit-kretsresultat på IonQ QPU

Viktigt!

Det går för närvarande inte att skicka flera kretsar på ett enda jobb. Som en lösning kan du anropa backend.run metoden för att skicka varje krets asynkront och sedan hämta resultatet av varje jobb. Till exempel:

jobs = []
for circuit in circuits:
    jobs.append(backend.run(circuit, shots=N))

results = []
for job in jobs:
    results.append(job.result())

Förutsättningar

Installationsinformation finns i Konfigurera QDK-tillägget.

Köra en grundläggande krets

Öppna en ny Python fil i VS Code för att definiera och köra en grundläggande krets med hjälp av den inbyggda glesa simulatorn i Qsharp-paketet.

# load the required imports 
from qiskit.circuit.random import random_circuit
from qsharp.interop.qiskit import QSharpBackend

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

Om du vill köra programmet väljer du ikonen Kör i det övre högra hörnet och väljer Kör Python fil. Utdata visas i ett nytt terminalfönster.

                  ┌─────────────────────────┐┌─┐
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}

Generera QIR för kretsen

Med samma krets kan du generera QIR som används för att köras på kvantmaskinvara.

Kommentar

När du genererar QIR måste alla register ha mätts in. Om det finns några oanvända register utlöses ett fel. Dessutom uppstår ett fel när du försöker generera QIR när profilen är inställd på Unrestricted. Profilen Unrestricted är endast giltig för simulering. Antingen TargetProfile.Base eller TargetProfile.Adaptive_RI måste användas. target_profile kan åsidosättas i backend.qir(...)-anropet för att växla profiler.

  1. Importera QSharpError och TargetProfile

    from qsharp import QSharpError, TargetProfile
    
  2. Ändra utdata för att generera QIR

        print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
    

Koden bör nu se ut så här:

# load the required imports 
from qiskit.circuit.random import random_circuit
from qsharp.interop.qiskit import QSharpBackend
from qsharp import QSharpError, TargetProfile

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

med utdata:

     ┌────────────┐             ┌─┐   
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}

Alla program kan inte köras på all maskinvara. Här kan du testa targetBase profilen, men vi kommer att få detaljerad information om vilka delar av programmet som inte stöds.

try:
    backend.qir(qc, target_profile=TargetProfile.Base)
except QSharpError as e:
    print(e)

Nästa steg