Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Lär dig hur du använder modulen qdk.azurePython för att skicka kretsar i specifika format till Azure Quantum-tjänsten. Den här artikeln visar hur du skickar kretsar i följande format:
Mer information finns i Kvantkretsar.
Förutsättningar
Om du vill utveckla och köra dina kretsar i Visual Studio Code (VS Code) måste du ha följande:
Ett Azure konto med en aktiv prenumeration. Om du inte har ett Azure konto registrerar du dig kostnadsfritt och registrerar dig för en betala per användning-prenumeration.
En Azure Quantum-arbetsyta. Mer information finns i Skapa en Azure Quantum arbetsyta.
En Python-miljö med Python och Pip installerat.
VS Code med Microsoft Quantum Development Kit (QDK), Python och Jupyter tillägg installerade.
biblioteket
qdkPython medazureextra och paketetipykernel.python -m pip install --upgrade "qdk[azure]" ipykernel
Skapa en ny Jupyter-anteckningsbok och anslut till din Quantum-arbetsyta
Följ dessa steg för att ansluta till din arbetsyta i en Jupyter-anteckningsbok i VS Code:
Öppna menyn Visa i VS Code och välj Kommandopalett.
Skriv in Skapa: En Ny Jupyter Notebook. En tom Jupyter Notebook fil öppnas på en ny flik.
Kör följande kod i den första cellen i notebook-filen. Du hittar resurs-ID:t i fönstret Overview för arbetsytan i Azure-portalen.
from qdk.azure import Workspace workspace = Workspace (resource_id="") # Add your resource ID
Skicka QIR-formaterade kretsar
Quantum Intermediate Representation (QIR) är en mellanliggande representation som fungerar som ett gemensamt gränssnitt mellan kvantprogrammeringsspråk och riktade kvantberäkningsplattformar. Mer information finns i Quantum Intermediate Representation(Kvantintermediär representation).
Följ dessa steg för att skicka en QIR-formaterad krets:
Skapa QIR-kretsen. Kör till exempel följande kod i en ny cell för att skapa en enkel sammanflätningskrets.
QIR_routine = """%Result = type opaque %Qubit = type opaque define void @ENTRYPOINT__main() #0 { call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 0 to %Qubit*)) call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*)) call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*)) call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*)) call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 2 to %Qubit*)) call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*)) call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*)) call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 3 to %Qubit*)) call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 0 to %Result*)) #1 call void @__quantum__qis__mz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 1 to %Result*)) #1 call void @__quantum__rt__tuple_record_output(i64 2, i8* null) call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null) call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null) ret void } declare void @__quantum__qis__ccx__body(%Qubit*, %Qubit*, %Qubit*) declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*) declare void @__quantum__qis__cy__body(%Qubit*, %Qubit*) declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*) declare void @__quantum__qis__rx__body(double, %Qubit*) declare void @__quantum__qis__rxx__body(double, %Qubit*, %Qubit*) declare void @__quantum__qis__ry__body(double, %Qubit*) declare void @__quantum__qis__ryy__body(double, %Qubit*, %Qubit*) declare void @__quantum__qis__rz__body(double, %Qubit*) declare void @__quantum__qis__rzz__body(double, %Qubit*, %Qubit*) declare void @__quantum__qis__h__body(%Qubit*) declare void @__quantum__qis__s__body(%Qubit*) declare void @__quantum__qis__s__adj(%Qubit*) declare void @__quantum__qis__t__body(%Qubit*) declare void @__quantum__qis__t__adj(%Qubit*) declare void @__quantum__qis__x__body(%Qubit*) declare void @__quantum__qis__y__body(%Qubit*) declare void @__quantum__qis__z__body(%Qubit*) declare void @__quantum__qis__swap__body(%Qubit*, %Qubit*) declare void @__quantum__qis__mz__body(%Qubit*, %Result* writeonly) #1 declare void @__quantum__rt__result_record_output(%Result*, i8*) declare void @__quantum__rt__array_record_output(i64, i8*) declare void @__quantum__rt__tuple_record_output(i64, i8*) attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="4" "required_num_results"="2" } attributes #1 = { "irreversible" } ; module flags !llvm.module.flags = !{!0, !1, !2, !3} !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} """Skapa en
submit_qir_jobhjälpfunktion för att skicka QIR-kretsen till en target. I det här exemplet ärqir.v1indata- och utdataformaten, ochmicrosoft.quantum-results.v1är respektive.# Submit the job with proper input and output data formats def submit_qir_job(target, input, name, count=100): job = target.submit( input_data=input, input_data_format="qir.v1", output_data_format="microsoft.quantum-results.v1", name=name, input_params = { "entryPoint": "ENTRYPOINT__main", "arguments": [], "count": count } ) print(f"Queued job: {job.id}") job.wait_until_completed() print(f"Job completed with state: {job.details.status}") #if job.details.status == "Succeeded": result = job.get_results() return resultSkicka QIR-kretsen till en specifik Azure Quantum target. Om du till exempel vill skicka QIR-kretsen till IonQ-simulatorn targetkör du följande kod:
target = workspace.get_targets(name="ionq.simulator") result = submit_qir_job(target, QIR_routine, "QIR routine") result
Skicka en krets med ett providerspecifikt format till Azure Quantum
Varje Azure Quantum-provider har sitt eget format för att representera kvantkretsar. Du kan skicka kretsar till Azure Quantum i providerspecifika format i stället för QIR-språk, till exempel Q# eller Qiskit.
Skicka en krets till IonQ i JSON-format
IonQ använder JSON-format för att köra kretsar på deras targets. Mer information finns i IonQ targets och IonQ API-dokumentationen.
Följande exempel skapar en superposition mellan tre kvantbitar i JSON-format.
Skapa en kvantkrets i JSON-format i en ny cell.
circuit = { "qubits": 3, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "control": 0, "target": 1 }, { "gate": "cnot", "control": 0, "target": 2 }, ] }Skicka kretsen till IonQ target. I följande exempel används IonQ-simulatorn, som returnerar ett
Jobobjekt.target = workspace.get_targets(name="ionq.simulator") job = target.submit(circuit)När jobbet är klart får du resultatet.
results = job.get_results() print(results)
Skicka en krets till Pasqal i Pulser SDK-format
Du kan använda Pulser SDK för att skapa pulssekvenser och skicka dem till Pasqal targets.
Installera Pulser SDK
Pulser är ett ramverk som gör att du kan skapa, simulera och köra pulssekvenser för kvantenheter med neutral atom. Pulser är utformat av PASQAL som ett gränssnitt för att lämna in kvantexperiment till sina kvantprocessorer. Mer information finns i Pulser-dokumentationen.
Om du vill skicka pulssekvenserna installerar du först Pulser SDK-paketen:
try:
import pulser
import pulser_pasqal
except ImportError:
!pip -q install pulser pulser-pasqal --index-url https://pypi.org/simple
Skapa ett kvantregister
Definiera både ett register och en layout. Registret anger var atomerna ska ordnas, och layouten anger positionerna för traps som fångar in och strukturerar atomerna i registret.
Mer information om layouter finns i Pulser-dokumentationen.
Skapa ett devices objekt för att importera Pasqal-kvantdatorn target, FRESNEL_CAN1.
from pulser_pasqal import PasqalCloud
devices = PasqalCloud().fetch_available_devices()
QPU = devices["FRESNEL_CAN1"]
Förkalibrerade layouter
Enheten definierar en lista över förkalibrerade layouter. Du kan skapa ditt register från någon av dessa layouter.
Använd förkalibrerade layouter när det är möjligt eftersom de förbättrar QPU:ns prestanda.
I följande exempel används den första förkalibrerade layouten på enheten:
# Use the first layout available on the device
layout = QPU.pre_calibrated_layouts[0]
# Select traps 1, 3 and 5 of the layout to define the register
traps = [1,v3,v5]
reg = layout.define_register(*traps)
# Draw the register to verify that it matches your expectations
reg.draw()
Godtyckliga layouter
Använd en anpassad layout när de förkalibrerade layouterna inte uppfyller kraven för experimentet.
För ett godtyckligt register placerar en QPU med neutrala atomer fällor enligt layouten, som sedan måste kalibreras. Eftersom varje kalibrering tar tid är det bästa praxis att återanvända en befintlig kalibrerad layout när det är möjligt.
Om du vill skapa en godtycklig layout väljer du något av följande alternativ:
Generera automatiskt en layout baserat på ett angivet register. För stora register kan den här processen skapa suboptimala lösningar. Till exempel:
from pulser import Register qubits = { "q0": (0, 0), "q1": (0, 10), "q2": (8, 2), "q3": (1, 15), "q4": (-10, -3), "q5": (-8, 5), } reg = Register(qubits).with_automatic_layout(device)Definiera en layout manuellt för att skapa registret. Skapa till exempel en godtycklig layout med 20 traps som placeras slumpmässigt i ett 2D-plan:
import numpy as np from pulser.register.register_layout import RegisterLayout # Generate random coordinates np.random.seed(301122) # Keeps results consistent between runs traps = np.random.randint(0, 30, size=(20, 2)) traps = traps - np.mean(traps, axis=0) # Create the layout layout = RegisterLayout(traps, slug="random_20") # Define your register with specific trap IDs trap_ids = [4, 8, 19, 0] reg = layout.define_register(*trap_ids, qubit_ids=["a", "b", "c", "d"]) reg.draw()
Skriva en pulssekvens
Neutrala atomer styrs med laserpulser. Med Pulser SDK kan du skapa pulssekvenser som ska tillämpas på kvantregistret.
Definiera pulssekvensattributen genom att deklarera kanalerna som styr atomerna. För att skapa en
Sequence, tillhandahåll enRegisterinstans tillsammans med enheten där sekvensen skall utföras. Följande kod deklarerar till exempel en kanal:ch0.from pulser import Sequence seq = Sequence(reg, QPU) # Print the available channels for your sequence print(seq.available_channels) # Declare a channel. For example, `rydberg_global` seq.declare_channel("ch0", "rydberg_global")Anteckning
Du kan använda
QPU = devices["FRESNEL_CAN1"]enheten eller importera en virtuell enhet från Pulser för mer flexibilitet. Med hjälp av enVirtualDevicekan du skapa sekvenser som är mindre begränsade av enhetsspecifikationer, vilket gör att du kan köra på en emulator. Mer information finns i Pulser-dokumentationen.Lägg till pulser i sekvensen. Det gör du genom att skapa och lägga till pulser i de kanaler som du deklarerade. Följande kod skapar till exempel en puls och lägger till den i kanalen
ch0:from pulser import Pulse from pulser.waveforms import RampWaveform, BlackmanWaveform import numpy as np amp_wf = BlackmanWaveform(1000, np.pi) det_wf = RampWaveform(1000, -5, 5) pulse = Pulse(amp_wf, det_wf, 0) seq.add(pulse, "ch0") seq.draw()Följande bild visar pulssekvensen:
Konvertera sekvensen till en JSON-sträng
Om du vill skicka pulssekvenserna konverterar du Pulser-objekten till en JSON-sträng som kan användas som indata.
import json
# Convert the sequence to a JSON string
def prepare_input_data(seq):
input_data = {}
input_data["sequence_builder"] = json.loads(seq.to_abstract_repr())
to_send = json.dumps(input_data)
return to_send
Skicka pulssekvensen till Pasqal target
Ange rätt indata- och utdataformat. Följande kod anger till exempel indataformatet till
pasqal.pulser.v1och utdataformatet tillpasqal.pulser-results.v1.# Submit the job with proper input and output data formats def submit_job(target, seq, shots): job = target.submit( input_data=prepare_input_data(seq), # Take the JSON string previously defined as input data input_data_format="pasqal.pulser.v1", output_data_format="pasqal.pulser-results.v1", name="Pasqal sequence", shots=shots # Number of shots ) print(f"Queued job: {job.id}") return jobAnteckning
Den tid som krävs för att köra ett jobb på QPU:n beror på aktuella kötider. Du kan visa den genomsnittliga kötiden för en target i Providers-rutan i arbetsytan.
Skicka programmet till Pasqal. Innan du skickar koden till verklig kvantmaskinvara är det bästa praxis att testa koden på emulatorn
pasqal.sim.emu-mpstarget.target = workspace.get_targets(name="pasqal.sim.emu-mps") # Change to "pasqal.qpu.fresnel-can1" to use FRESNEL_CAN1 QPU job = submit_job(target, seq, 10) job.wait_until_completed() print(f"Job completed with state: {job.details.status}") result = job.get_results() print(result){ "1000000": 3, "0010000": 1, "0010101": 1 }
Skicka en OpenQASM-krets till Quantinuum
Skapa en kvantkrets i OpenQASM-representationen. Följande kod skapar till exempel en teleporteringskrets:
circuit = """OPENQASM 2.0; include "qelib1.inc"; qreg q[3]; creg c0[3]; h q[0]; cx q[0], q[1]; cx q[1], q[2]; measure q[0] -> c0[0]; measure q[1] -> c0[1]; measure q[2] -> c0[2]; """Eller läs in kretsen från en OpenQASM-fil:
with open("my_teleport.qasm", "r") as f: circuit = f.read()Skicka kretsen till en Quantinuum target. I följande exempel skickas jobbet till en av Quantinuum-simulatorn targets.
target = workspace.get_targets(name="quantinuum.sim.h2-1sc") job = target.submit(circuit, shots=500)Vänta tills jobbet är klart och hämta sedan resultatet.
results = job.get_results() print(results)
Anteckning
Dessa resultat returnerar 000 för varje skott, vilket inte är slumpmässigt. Det beror på att API-validatorn endast kontrollerar om koden kan köras på Quantinuum-maskinvara, men returnerar 0 för varje kvantmätning. För en verklig slumptalsgenerator måste du köra kretsen på kvantmaskinvara.
Skicka en Quil-krets till Rigetti
Om du vill skicka ett Quil-jobb till en Rigetti target använder du modulen qdk.azurePython.
Läs in nödvändiga importer.
from azure.quantum import Workspace from azure.quantum.target.rigetti import Result, Rigetti, RigettiTarget, InputParamsSkapa ett
targetobjekt och skicka namnet på den Rigetti target som du vill skicka jobbet till. Till exempel väljer följande kodQVMtarget.target = Rigetti(workspace=workspace, name=RigettiTarget.QVM)Skapa ett Quil-program. För att programmet ska accepteras måste du ställa in avläsningen på
"ro".readout = "ro" bell_state_quil = f""" DECLARE {readout} BIT[2] H 0 CNOT 0 1 MEASURE 0 {readout}[0] MEASURE 1 {readout}[1] """ num_shots = 5 job = target.submit( input_data=bell_state_quil, name="bell state", shots=100, input_params=InputParams(skip_quilc=False) ) print(f"Job completed with state: {job.details.status}") result = Result(job) # This throws an exception if the job failedDu kan indexera ett resultat med namnet på avläsningen. I följande kod är
data_per_shoten lista med längdnum_shots, och varje objekt i listan är en annan lista som innehåller data för registret från det skottet.data_per_shot = result[readout] ro_data_first_shot = data_per_shot[0]I det här fallet, eftersom typen av registret är BIT, är typen heltal och värdet 0 eller 1.
assert isinstance(ro_data_first_shot[0], int) assert ro_data_first_shot[0] == 1 or ro_data_first_shot[0] == 0Skriv ut alla data.
print(f"Data from '{readout}' register:") for i, shot in enumerate(data_per_shot): print(f"Shot {i}: {shot}")
Viktigt!
Du kan inte skicka flera kretsar i ett och samma 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())