Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Meer informatie over het gebruik van de module qdk.azurePython om circuits in specifieke indelingen naar de Azure Quantum-service te verzenden. In dit artikel leest u hoe u circuits in de volgende indelingen verzendt:
Zie Quantum-circuits voor meer informatie.
Vereisten
Als u uw circuits wilt ontwikkelen en uitvoeren in Visual Studio Code (VS Code), moet u het volgende hebben:
Een Azure-account met een actief abonnement. Als u geen Azure account hebt, registreert u zich gratis en registreert u zich voor een pay-as-you-go-abonnement.
Een Azure Quantum werkruimte. Zie Maak een Azure Quantum werkruimte voor meer informatie.
Een Python-omgeving waarop Python en Pip zijn geïnstalleerd.
VS Code met de Microsoft Quantum Development-kit (QDK), Python en Jupyter-extensies geïnstalleerd.
De
qdkPython-bibliotheek met deazure-extra's en hetipykernel-pakket.python -m pip install --upgrade "qdk[azure]" ipykernel
Een nieuw Jupyter-notebook maken en verbinding maken met uw Quantum-werkruimte
Volg deze stappen om verbinding te maken met uw werkruimte in een Jupyter-notebook in VS Code:
Open in VS Code het menu Beeld en kies Opdrachtpalet.
Voer Create: New Jupyter Notebook in. Er wordt een leeg Jupyter Notebook bestand geopend op een nieuw tabblad.
Voer in de eerste cel van het notebook de volgende code uit. U vindt de resource-id in het deelvenster Overview voor uw werkruimte in de Azure-portal.
from qdk.azure import Workspace workspace = Workspace (resource_id="") # Add your resource ID
QIR-geformatteerde circuits verzenden
Quantum Intermediate Representation (QIR) is een tussenliggende weergave die fungeert als een gemeenschappelijke interface tussen kwantumprogrammeertalen en doelplatforms voor kwantumberekeningen. Zie Quantum Intermediate Representation voor meer informatie.
Voer de volgende stappen uit om een QIR-geformatteerd circuit te verzenden:
Maak het QIR-circuit. Voer bijvoorbeeld de volgende code uit in een nieuwe cel om een eenvoudig verstrengelingscircuit te maken.
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} """Maak een
submit_qir_jobhelper functie om het QIR-circuit naar een target in te dienen. In dit voorbeeld zijn de gegevensindelingen voor invoer en uitvoer respectievelijkqir.v1enmicrosoft.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 resultVerzend het QIR-circuit naar een specifieke Azure Quantum target. Als u bijvoorbeeld het QIR-circuit wilt verzenden naar de IonQ-simulator target, voert u de volgende code uit:
target = workspace.get_targets(name="ionq.simulator") result = submit_qir_job(target, QIR_routine, "QIR routine") result
Een circuit met een providerspecifieke indeling verzenden naar Azure Quantum
Elke Azure Quantum provider heeft een eigen indeling die kwantumcircuits vertegenwoordigt. U kunt circuits verzenden naar Azure Quantum in providerspecifieke indelingen in plaats van QIR-talen, zoals Q# of Qiskit.
Een circuit verzenden naar IonQ in JSON-indeling
IonQ gebruikt JSON-formaat om circuits op hun targets uit te voeren. Zie ionQ en de IonQ targetsAPI-documentatie voor meer informatie.
In het volgende voorbeeld wordt een superpositie gemaakt tussen drie qubits in JSON-indeling.
Maak in een nieuwe cel een kwantumcircuit in JSON-indeling.
circuit = { "qubits": 3, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "control": 0, "target": 1 }, { "gate": "cnot", "control": 0, "target": 2 }, ] }Verzend het circuit naar de IonQ target. In het volgende voorbeeld wordt de IonQ-simulator gebruikt, die een
Jobobject retourneert.target = workspace.get_targets(name="ionq.simulator") job = target.submit(circuit)Wanneer de taak is voltooid, haalt u de resultaten op.
results = job.get_results() print(results)
Een circuit verzenden naar Pasqal in Pulser SDK-indeling
U kunt de Pulser SDK gebruiken om pulse-reeksen te maken en deze naar Pasqal targetste verzenden.
De Pulser SDK installeren
Pulser is een framework waarmee u pulse-reeksen kunt maken, simuleren en uitvoeren voor kwantumapparaten met neutraal atoom. Pulser is door PASQAL ontworpen als een doorgeefluik om kwantumexperimenten naar hun kwantumprocessors te verzenden. Zie de Pulser-documentatie voor meer informatie.
Als u de pulse-reeksen wilt verzenden, installeert u eerst de Pulser SDK-pakketten:
try:
import pulser
import pulser_pasqal
except ImportError:
!pip -q install pulser pulser-pasqal --index-url https://pypi.org/simple
Een kwantumregister maken
Definieer zowel een register als een indeling. In het register wordt aangegeven waar de atomen moeten worden gerangschikt en in de indeling worden de posities van traps opgegeven die de atomen in het register vastleggen en structuren.
Zie de Pulser-documentatie voor meer informatie over indelingen.
Maak een devices object om de Pasqal-kwantumcomputer targette importeren , FRESNEL_CAN1.
from pulser_pasqal import PasqalCloud
devices = PasqalCloud().fetch_available_devices()
QPU = devices["FRESNEL_CAN1"]
Vooraf gekalibreerde indelingen
Het apparaat definieert een lijst met vooraf gekalibreerde indelingen. U kunt uw register maken op basis van een van deze indelingen.
Gebruik indien mogelijk vooraf gekalibreerde indelingen omdat ze de prestaties van de QPU verbeteren.
In het volgende voorbeeld wordt de eerste vooraf gekalibreerde indeling op het apparaat gebruikt:
# 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()
Willekeurige indelingen
Gebruik een aangepaste indeling wanneer de vooraf gekalibreerde indelingen niet voldoen aan de vereisten van uw experiment.
Voor een bepaald willekeurig register plaatst een neutraal-atom QPU traps volgens de indeling, die vervolgens moeten worden gekalibreerd. Omdat elke kalibratie tijd kost, is het een best practice om een bestaande gekalibreerde indeling indien mogelijk opnieuw te gebruiken.
Als u een willekeurige indeling wilt maken, kiest u een van de volgende opties:
Automatisch een indeling genereren op basis van een opgegeven register. Voor grote registers kan dit proces suboptimale oplossingen produceren. Voorbeeld:
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)Definieer handmatig een indeling om uw register te maken. Maak bijvoorbeeld een willekeurige indeling met 20 traps die willekeurig in een 2D-vlak worden geplaatst:
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()
Een pulsreeks schrijven
Neutrale atomen worden geregeld met laserpulsen. Met de Pulser SDK kunt u pulse-reeksen maken die van toepassing zijn op het kwantumregister.
Definieer de pulsreekskenmerken door de kanalen te declareren die de atomen beheren. Als u een
Sequenceexemplaar wilt maken, geeft u eenRegisterexemplaar op samen met het apparaat waarop de reeks wordt uitgevoerd. De volgende code declareert bijvoorbeeld één kanaal: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")Notitie
U kunt het
QPU = devices["FRESNEL_CAN1"]apparaat gebruiken of een virtueel apparaat importeren vanuit Pulser voor meer flexibiliteit. Het gebruik van eenVirtualDevicemaakt het mogelijk om reeksen te maken die minder beperkt zijn door apparaatspecificaties, waardoor op een emulator kan worden uitgevoerd. Zie de Pulser-documentatie voor meer informatie.Voeg pulsen toe aan uw reeks. Hiervoor maakt en voegt u pulsen toe aan de kanalen die u hebt gedeclareerd. Met de volgende code wordt bijvoorbeeld een puls gemaakt en toegevoegd aan het kanaal
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()In de volgende afbeelding ziet u de pulsreeks:
De reeks converteren naar een JSON-tekenreeks
Als u de pulse-reeksen wilt verzenden, converteert u de Pulser-objecten naar een JSON-tekenreeks die kan worden gebruikt als invoergegevens.
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
De pulsreeks verzenden naar Pasqal target
Stel de juiste indelingen voor invoer- en uitvoergegevens in. Met de volgende code wordt bijvoorbeeld de indeling van de invoergegevens ingesteld op
pasqal.pulser.v1en de indeling van de uitvoergegevens oppasqal.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 jobNotitie
De tijd die nodig is om een taak uit te voeren op de QPU, is afhankelijk van de huidige wachtrijtijden. U kunt de gemiddelde wachtrijtijd voor een target in het deelvenster Providers van uw werkruimte bekijken.
Verzend het programma naar Pasqal. Voordat u uw code naar echte kwantumhardware verzendt, is het een best practice om uw code op de emulator
pasqal.sim.emu-mpstargette testen.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 }
Een OpenQASM-circuit verzenden naar Quantinuum
Maak een kwantumcircuit in de OpenQASM-weergave . Met de volgende code wordt bijvoorbeeld een teleportatiecircuit gemaakt:
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]; """Of laad het circuit vanuit een OpenQASM-bestand:
with open("my_teleport.qasm", "r") as f: circuit = f.read()Verzend het circuit naar een Quantinuum target. In het volgende voorbeeld wordt de taak verzonden naar een van de Quantinuum-simulator targets.
target = workspace.get_targets(name="quantinuum.sim.h2-1sc") job = target.submit(circuit, shots=500)Wacht totdat de taak is voltooid en haal vervolgens de resultaten op.
results = job.get_results() print(results)
Notitie
Deze resultaten geven 000 terug voor elke poging, wat geen toeval is. Dit komt doordat de API Validator alleen controleert of uw code kan worden uitgevoerd op Quantinuum-hardware, maar 0 retourneert voor elke kwantummeting. Voor een echte generator voor willekeurige getallen moet u uw circuit uitvoeren op kwantumhardware.
Een Quil-circuit verzenden naar Rigetti
Als u een Quil-taak naar een Rigetti-target wilt verzenden, gebruikt u de module qdk.azurePython.
Laad de vereiste importen.
from azure.quantum import Workspace from azure.quantum.target.rigetti import Result, Rigetti, RigettiTarget, InputParamsMaak een
targetobject en geef de naam door van de Rigetti target waarnaar u uw taak wilt verzenden. Met de volgende code selecteert u bijvoorbeeld deQVMtarget.target = Rigetti(workspace=workspace, name=RigettiTarget.QVM)Maak een Quil-programma. Als u uw programma wilt accepteren, moet u de leesbewerking instellen op
"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 failedU kunt een resultaat indexeren met de naam van de uitlezing. In de volgende code
data_per_shotis een lijst met lengtenum_shotsen elk item in de lijst is een andere lijst die de gegevens voor het register van die opname bevat.data_per_shot = result[readout] ro_data_first_shot = data_per_shot[0]Omdat het type van het register BIT is, is het type geheel getal en de waarde 0 of 1.
assert isinstance(ro_data_first_shot[0], int) assert ro_data_first_shot[0] == 1 or ro_data_first_shot[0] == 0Alle gegevens afdrukken.
print(f"Data from '{readout}' register:") for i, shot in enumerate(data_per_shot): print(f"Shot {i}: {shot}")
Belangrijk
U kunt niet meerdere circuits verzenden voor één taak. Als tijdelijke oplossing kunt u de backend.run methode aanroepen om elk circuit asynchroon te verzenden en vervolgens de resultaten van elke taak op te halen. Voorbeeld:
jobs = []
for circuit in circuits:
jobs.append(backend.run(circuit, shots=N))
results = []
for job in jobs:
results.append(job.result())