Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Erfahren Sie, wie Sie das Modul qdk.azurePython verwenden, um Schaltkreise in bestimmten Formaten an den Azure Quantum-Dienst zu übermitteln. In diesem Artikel wird gezeigt, wie Sie Schaltkreise in den folgenden Formaten übermitteln:
Weitere Informationen finden Sie unter Quantenschaltungen.
Voraussetzungen
Um Ihre Schaltkreise in Visual Studio Code (VS Code) zu entwickeln und auszuführen, müssen Sie folgendes haben:
Ein Azure Konto mit einem aktiven Abonnement. Wenn Sie kein Azure Konto haben, registrieren Sie sich kostenlos, und registrieren Sie sich für ein pay-as-you-go-Abonnement.
Ein Azure-Quantum-Arbeitsbereich. Weitere Informationen finden Sie unter Create an Azure Quantum workspace.
Eine Python-Umgebung, in der Python und Pip installiert ist.
VS Code mit Microsoft Quantum Development Kit (QDK), Python und Jupytererweiterungen installiert.
Die
qdkPython-Bibliothek mit demazure-Zusatz und demipykernel-Paket.python -m pip install --upgrade "qdk[azure]" ipykernel
Erstellen eines neuen Jupyter-Notizbuchs und Herstellen einer Verbindung mit Ihrem Quantum-Arbeitsbereich
Führen Sie die folgenden Schritte aus, um eine Verbindung mit Ihrem Arbeitsbereich in einem Jupyter-Notizbuch in VS Code herzustellen:
Öffnen Sie im VS Code das Menü "Ansicht" , und wählen Sie "Befehlspalette" aus.
Geben Sie Create: New Jupyter Notebook ein. Eine leere Jupyter Notebook Datei wird auf einer neuen Registerkarte geöffnet.
Führen Sie in der ersten Zelle des Notizbuchs den folgenden Code aus. Sie finden die Ressourcen-ID im Bereich Overview für Ihren Arbeitsbereich im Azure-Portal.
from qdk.azure import Workspace workspace = Workspace (resource_id="") # Add your resource ID
Übermitteln Sie QIR-formatierte Schaltkreise
Quantum Intermediate Representation (QIR) ist eine Zwischendarstellung, die als gemeinsame Schnittstelle zwischen Quantenprogrammiersprachen und gezielten Quantenberechnungsplattformen dient. Weitere Informationen finden Sie unter Quantum Intermediate Representation.
Führen Sie die folgenden Schritte aus, um einen QIR-formatierten Schaltkreis zu übermitteln:
Erstellen Sie den QIR-Schaltkreis. Führen Sie beispielsweise den folgenden Code in einer neuen Zelle aus, um eine einfache Veranglementschaltung zu erstellen.
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} """Erstellen Sie eine
submit_qir_job-Hilfsfunktion, um den QIR-Schaltkreis an einen target zu übermitteln. In diesem Beispiel sind die Formate der Eingabe- und Ausgabedaten jeweilsqir.v1undmicrosoft.quantum-results.v1.# 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 resultÜbermitteln Sie den QIR-Schaltkreis an eine bestimmte Azure Quantum target. Führen Sie beispielsweise den folgenden Code aus, um den QIR-Schaltkreis an den IonQ-Simulator targetzu übermitteln:
target = workspace.get_targets(name="ionq.simulator") result = submit_qir_job(target, QIR_routine, "QIR routine") result
Übermitteln eines Schaltkreises mit einem anbieterspezifischen Format an Azure Quantum
Jeder Azure Quantum Anbieter hat ein eigenes Format, um Quantenschaltungen darzustellen. Sie können Schaltkreise in anbieterspezifischen Formaten anstelle von QIR-Sprachen, z. B. Q# oder Qiskit, an Azure Quantum übermitteln.
Übermitteln eines Schaltkreises an IonQ im JSON-Format
IonQ nutzt das JSON-Format zum Ausführen von Schaltkreisen auf ihren targets. Weitere Informationen finden Sie in der IonQ targets- und ionQ-API-Dokumentation.
Im folgenden Beispiel wird eine Superposition zwischen drei Qubits im JSON-Format erstellt.
Erstellen Sie in einer neuen Zelle einen Quantenkreis im JSON-Format.
circuit = { "qubits": 3, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "control": 0, "target": 1 }, { "gate": "cnot", "control": 0, "target": 2 }, ] }Übermitteln Sie den Schaltkreis an den IonQ target. Im folgenden Beispiel wird der IonQ-Simulator verwendet, der ein
Job-Objekt zurückgibt.target = workspace.get_targets(name="ionq.simulator") job = target.submit(circuit)Wenn der Auftrag abgeschlossen ist, können Sie die Ergebnisse abrufen.
results = job.get_results() print(results)
Übermitteln eines Schaltkreises an PASQAL im Pulser SDK-Format
Sie können das Pulser SDK verwenden, um Pulssequenzen zu erstellen und sie an PASQAL targetszu übermitteln.
Installieren des Pulser SDK
Pulser ist ein Framework, mit dem Sie Impulssequenzen für neutrale Atom-Quantengeräte erstellen, simulieren und ausführen können. Pulser wurde von PASQAL als Pass-Through entwickelt, um Quantenexperimente an ihre Quantenprozessoren zu übermitteln. Weitere Informationen finden Sie in der Pulser-Dokumentation.
Um die Impulssequenzen zu übermitteln, installieren Sie zuerst die Pulser SDK-Pakete:
try:
import pulser
import pulser_pasqal
except ImportError:
!pip -q install pulser pulser-pasqal --index-url https://pypi.org/simple
Erstellen eines Quantenregisters
Definieren Sie sowohl ein Register als auch ein Layout. Das Register gibt an, wo die Atome angeordnet werden sollen, und das Layout gibt die Positionen von Fallen an, die die Atome innerhalb des Registers erfassen und strukturieren.
Ausführliche Informationen zu Layouts finden Sie in der Pulser-Dokumentation.
Erstellen Sie ein devices Objekt zum Importieren des PASQAL-Quantencomputers targetFresnel.
from pulser_pasqal import PasqalCloud
devices = PasqalCloud().fetch_available_devices()
QPU = devices["FRESNEL"]
Vorkalibrierungslayouts
Das Gerät definiert eine Liste der vordefinierten Layouts. Sie können Ihr Register aus einem dieser Layouts erstellen.
Verwenden Sie vorab kalibrierte Layouts, wenn möglich, da sie die Leistung der QPU verbessern.
Im folgenden Beispiel wird das erste vorab kalibrierte Layout auf dem Gerät verwendet:
# 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()
Beliebige Layouts
Verwenden Sie ein benutzerdefiniertes Layout, wenn die vordefinierten Layouts nicht den Anforderungen Ihres Experiments entsprechen.
Für ein bestimmtes beliebiges Register platziert ein neutrales Atom QPU Fallen nach dem Layout, das dann kalibriert werden muss. Da jede Kalibrierung Zeit in Anspruch nimmt, empfiehlt es sich, ein vorhandenes kalibriertes Layout nach Möglichkeit wiederzuverwenden.
Um ein beliebiges Layout zu erstellen, wählen Sie eine der folgenden Optionen aus:
Automatisches Generieren eines Layouts basierend auf einem angegebenen Register. Bei großen Registern kann dieser Prozess suboptimale Lösungen erzeugen. Zum Beispiel:
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)Definieren Sie manuell ein Layout, um Ihr Register zu erstellen. Erstellen Sie beispielsweise ein beliebiges Layout mit 20 Fallen, die zufällig in einer 2D-Ebene positioniert sind:
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()
Schreiben einer Impulssequenz
Neutrale Atome werden mit Laserpulsen gesteuert. Mit dem Pulser SDK können Sie Impulssequenzen erstellen, die auf das Quantenregister angewendet werden.
Definieren Sie die Impulssequenzattribute, indem Sie die Kanäle deklarieren, die die Atome steuern. Geben Sie eine
Register-Instanz zusammen mit dem Gerät an, auf dem die Sequenz ausgeführt wird, um eineSequencezu erstellen. Der folgende Code deklariert beispielsweise einen 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")Hinweis
Sie können das
QPU = devices["FRESNEL"]Gerät verwenden oder ein virtuelles Gerät aus Pulser importieren, um mehr Flexibilität zu erhalten. Die Verwendung einerVirtualDeviceErmöglicht die Sequenzerstellung, die weniger durch Gerätespezifikationen eingeschränkt ist, sodass Sie auf einem Emulator ausführen können. Weitere Informationen finden Sie in der Pulser-Dokumentation.Fügen Sie Ihrer Sequenz Impulse hinzu. Erstellen und fügen Sie dazu Impulse zu den Kanälen hinzu, die Sie deklariert haben. Der folgende Code erstellt z. B. einen Impuls und fügt ihn dem Kanal
ch0hinzu: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()Die folgende Abbildung zeigt die Impulssequenz:
Konvertieren der Sequenz in eine JSON-Zeichenfolge
Um die Impulssequenzen zu übermitteln, konvertieren Sie die Pulser-Objekte in eine JSON-Zeichenfolge, die als Eingabedaten verwendet werden kann.
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
Übermitteln der Impulssequenz an einen PASQAL target
Legen Sie die richtigen Eingabe- und Ausgabedatenformate fest. Der folgende Code legt z. B. das Eingabedatenformat
pasqal.pulser.v1und das Ausgabedatenformat aufpasqal.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 jobHinweis
Die zum Ausführen eines Auftrags auf der QPU erforderliche Zeit hängt von den aktuellen Warteschlangenzeiten ab. Sie können die durchschnittliche Warteschlangenzeit für einen target im Bereich "Anbieter " Ihres Arbeitsbereichs anzeigen.
Übermitteln Sie das Programm an PASQAL. Bevor Sie Ihren Code an echte Quantenhardware übermitteln, empfiehlt es sich, Den Code im Emulator
pasqal.sim.emu-tntargetzu testen.target = workspace.get_targets(name="pasqal.sim.emu-tn") # Change to "pasqal.qpu.fresnel" to use Fresnel 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 }
Reichen Sie einen OpenQASM-Schaltkreis bei Quantinuum ein
Erstellen Sie eine Quantenschaltung in der OpenQASM-Darstellung. Der folgende Code erstellt z. B. einen Teleportation-Schaltkreis:
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]; """Oder laden Sie den Schaltkreis aus einer OpenQASM-Datei:
with open("my_teleport.qasm", "r") as f: circuit = f.read()Übermitteln Sie den Schaltkreis an einen Quantinuum target. Im folgenden Beispiel wird der Auftrag an einen der Quantinuum-Simulator targetsübermittelt.
target = workspace.get_targets(name="quantinuum.sim.h2-1sc") job = target.submit(circuit, shots=500)Warten Sie, bis der Auftrag abgeschlossen ist, und rufen Sie dann die Ergebnisse ab.
results = job.get_results() print(results)
Hinweis
Diese Ergebnisse geben für jeden Schuss 000 zurück, was nicht zufällig ist. Dies liegt daran, dass der API-Validator nur überprüft, ob Ihr Code auf Quantinuum-Hardware ausgeführt werden kann, gibt aber für jede Quantenmessung 0 zurück. Für einen echten Zufallszahlengenerator müssen Sie Ihre Schaltung auf Quantenhardware ausführen.
Reichen Sie einen Quil-Schaltkreis bei Rigetti ein
Um einen Quil-Auftrag an einen Rigetti target zu übermitteln, verwenden Sie das Modul qdk.azurePython.
Laden Sie die erforderlichen Importe.
from azure.quantum import Workspace from azure.quantum.target.rigetti import Result, Rigetti, RigettiTarget, InputParamsErstellen Sie ein
targetObjekt, und übergeben Sie den Namen der Rigetti target , an die Sie Ihren Auftrag übermitteln möchten. Der folgende Code wählt z. B. dieQVMtarget.target = Rigetti(workspace=workspace, name=RigettiTarget.QVM)Erstellen Sie ein Quil-Programm. Damit Ihr Programm akzeptiert wird, müssen Sie den Ausgabewert auf
"ro"setzen.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 failedSie können ein Ergebnis mit dem Namen des Messwerts indizieren. Im folgenden Code ist
data_per_shoteine Liste mit der Längenum_shots, wobei jedes Element in dieser Liste eine weitere Liste ist, die die Daten für das Register aus dieser Aufnahme enthält.data_per_shot = result[readout] ro_data_first_shot = data_per_shot[0]In diesem Fall, da der Typ des Registers BIT ist, ist der Typ ganzzahlig und der Wert entweder 0 oder 1.
assert isinstance(ro_data_first_shot[0], int) assert ro_data_first_shot[0] == 1 or ro_data_first_shot[0] == 0Drucken Sie alle Daten aus.
print(f"Data from '{readout}' register:") for i, shot in enumerate(data_per_shot): print(f"Shot {i}: {shot}")
Wichtig
Sie können nicht mehrere Schaltkreise an einem einzigen Auftrag übermitteln. Als Problemumgehung können Sie die backend.run Methode aufrufen, um jeden Schaltkreis asynchron zu übermitteln, und dann die Ergebnisse jedes Auftrags abzurufen. Zum Beispiel:
jobs = []
for circuit in circuits:
jobs.append(backend.run(circuit, shots=N))
results = []
for job in jobs:
results.append(job.result())