Odeslání konkrétních formátovaných okruhů do Azure Quantum
Naučte se používat azure-quantum
Python balíček k odesílání okruhů v konkrétních formátech do služby Azure Quantum. V tomto článku se dozvíte, jak odesílat okruhy v následujících formátech:
Další informace najdete v tématu Kvantové obvody.
Požadavky
Ke spuštění okruhů v poznámkovém bloku na webu Azure Portal potřebujete:
- Účet Azure s aktivním předplatným. Pokud nemáte účet Azure, zaregistrujte se zdarma a zaregistrujte si předplatné s průběžným platbou.
- Pracovní prostor Azure Quantum. Další informace najdete v tématu Vytvoření pracovního prostoru Azure Quantum.
K vývoji a spouštění okruhů v editoru Visual Studio Code potřebujete také:
Prostředí Python s nainstalovaným Python nástrojem Pip .
VS Code s nainstalovanou sadou Azure Quantum Development KitPython a rozšířeními Jupyter.
Azure Quantum
qsharp
azure-quantum
aipykernel
balíčky.python -m pip install --upgrade qsharp azure-quantum ipykernel
Vytvoření nového poznámkového bloku Jupyter
Poznámkový blok můžete vytvořit ve VS Code nebo přímo na portálu Azure Quantum.
- Přihlaste se k webu Azure Portal a vyberte pracovní prostor z předchozího kroku.
- V levém okně vyberte Poznámkové bloky.
- Klikněte na Moje poznámkové bloky a klikněte na Přidat nový.
- V typu jádra vyberte IPython.
- Zadejte název souboru a klikněte na Vytvořit soubor.
Když se nový poznámkový blok otevře, automaticky vytvoří kód pro první buňku na základě informací o vašem předplatném a pracovním prostoru.
from azure.quantum import Workspace
workspace = Workspace (
resource_id = "", # Your resource_id
location = "" # Your workspace location (for example, "westus")
)
Odeslání okruhů ve formátu QIR
Quantum Intermediate Representation (QIR) je průběžná reprezentace, která slouží jako společné rozhraní mezi kvantovými programovacími jazyky a architekturami a cílovými kvantovými výpočetními platformami. Další informace naleznete v tématu Kvantové zprostředkující reprezentace.
Vytvořte okruh QIR. Například následující kód vytvoří jednoduchý propletení okruhu.
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} """
Vytvořte pomocnou
submit_qir_job
funkci pro odeslání okruhu QIR do .target Všimněte si, že vstupní a výstupní datové formáty jsou zadány jakoqir.v1
amicrosoft.quantum-results.v1
v uvedeném pořadí.# 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
target Vyberte okruh QIR a odešlete ho do Azure Quantum. Například k odeslání okruhu QIR do simulátoru targetIonQ:
target = workspace.get_targets(name="ionq.simulator") result = submit_qir_job(target, QIR_routine, "QIR routine") result
{'Histogram': ['(0, 0)', 0.5, '(1, 1)', 0.5]}
Odeslání okruhu s formátem specifickým pro poskytovatele do Azure Quantum
Kromě jazyků QIR, jako je Q# nebo Qiskit, můžete do Azure Quantum odesílat kvantové okruhy ve formátech specifických pro poskytovatele. Každý poskytovatel má vlastní formát pro reprezentaci kvantových obvodů.
Odeslání okruhu do IonQ ve formátu JSON
Vytvořte kvantový okruh pomocí formátu JSON nezávislého na jazyce podporovaném ionQtargets, jak je popsáno v dokumentaci k rozhraní IonQ API. Například následující ukázka vytvoří superpozici mezi třemi qubity:
circuit = { "qubits": 3, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "control": 0, "target": 1 }, { "gate": "cnot", "control": 0, "target": 2 }, ] }
Odešlete okruh do IonQ target. Následující příklad používá simulátor IonQ, který vrací
Job
objekt.target = workspace.get_targets(name="ionq.simulator") job = target.submit(circuit)
Počkejte, až se úloha dokončí, a pak načtěte výsledky.
results = job.get_results() print(results)
..... {'duration': 8240356, 'histogram': {'0': 0.5, '7': 0.5}}
Výsledky pak můžete vizualizovat pomocí knihovny Matplotlib.
import pylab as pl pl.rcParams["font.size"] = 16 hist = {format(n, "03b"): 0 for n in range(8)} hist.update({format(int(k), "03b"): v for k, v in results["histogram"].items()}) pl.bar(hist.keys(), hist.values()) pl.ylabel("Probabilities")
Před spuštěním úlohy v QPU byste měli odhadnout, kolik bude stát spuštění.
Poznámka:
Nejaktuálnější podrobnosti o cenách najdete v tématu Ceny IonQ nebo vyhledejte svůj pracovní prostor a zobrazte cenové možnosti na kartě Poskytovatel vašeho pracovního prostoru prostřednictvím: aka.ms/aq/myworkspaces.
Odeslání okruhu do PASQAL pomocí sady Pulser SDK
Pokud chcete odeslat okruh do PASQAL, můžete pomocí sady Pulser SDK vytvořit sekvence impulsů a odeslat je do PASQAL target.
Instalace sady Pulser SDK
Pulser je architektura pro vytváření, simulaci a spouštění pulzních sekvencí pro kvantová zařízení s neutrálním atomem. Je navržená nástrojem PASQAL jako průchozím pro odesílání kvantových experimentů do jejich kvantových procesorů. Další informace najdete v dokumentaci k Pulseru.
Pokud chcete odeslat sekvence impulsů, nejprve nainstalujte balíčky Pulser SDK:
try:
import pulser
except ImportError:
!pip -q install pulser
Vytvoření kvantového registru
Než budete pokračovat, musíte definovat registr i rozložení. Registr určuje, kde budou atomy uspořádány, zatímco rozložení určuje umístění pastí nezbytných k zachycení a strukturování těchto atomů v registru.
Podrobnosti o rozloženích najdete v dokumentaci pulseru.
Nejprve vytvoříte objekt "devices" pro import kvantového počítače targetPASQAL , Fresnel.
from pulser_pasqal import PasqalCloud devices = PasqalCloud().fetch_available_devices() QPU = devices["FRESNEL"]
Předkalibrované rozložení
Zařízení definuje seznam předkalibrovaných rozložení. Můžete vytvořit registr z jednoho z těchto rozložení.
Toto je doporučená možnost, protože zlepší výkon QPU.
Možnost 1: Definování registru pomocí předem kalibrovaných rozložení
Prozkoumejte rozložení dostupná na Fresnelu a definujte registr z tohoto rozložení. Další informace o tom, jak to udělat, najdete v dokumentaci k pulseru.
Příklad:
# let's say we are interested in 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,3,5] reg = layout.define_register(*traps) # You can draw the resulting register to verify it matches your expectations reg.draw()
Libovolná rozložení
Pokud předem kalibrovaná rozložení nevyhovují požadavkům experimentu, můžete vytvořit vlastní rozložení.
U jakéhokoliv libovolného registru umístí QPU neutrálního atomu pasti podle rozložení, které pak musí proběhnout kalibrací. Vzhledem k tomu, že každá kalibrace vyžaduje čas, je obecně vhodné opakovaně použít existující kalibrované rozložení, kdykoli je to možné.
Možnost 2: Automaticky odvodit rozložení z definovaného registru
Tato možnost umožňuje automatické generování rozložení na základě zadaného registru. U velkých registrů ale tento proces může přinést suboptimální řešení z důvodu omezení algoritmu použitého k vytvoření rozložení.
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)
Možnost 3: Definování registru pomocí ručně definovaného rozložení
- Vytvoření libovolného rozložení s náhodně umístěnými 20 soutisky v 2D rovině
import numpy as np # Generating 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) # Creating the layout layout = RegisterLayout(traps, slug="random_20")
- Definování registru s konkrétními ID soutisku
trap_ids = [4, 8, 19, 0] reg = layout.define_register(*trap_ids, qubit_ids=["a", "b", "c", "d"]) reg.draw()
Zápis sekvence impulsů
Neutrální atomy jsou řízeny laserovými impulsy. Sada Pulser SDK umožňuje vytvářet sekvence impulsů, které se použijí pro kvantový registr.
Nejprve definujete atributy sekvence impulsů deklarováním kanálů, které se použijí k řízení atomů. Pokud chcete vytvořit
Sequence
instanci, musíte poskytnoutRegister
instanci spolu se zařízením, ve kterém se sekvence spustí. Například následující kód deklaruje jeden kanál:ch0
.Poznámka:
Můžete použít
QPU = devices["FRESNEL"]
zařízení nebo importovat virtuální zařízení z Pulseru, abyste měli větší flexibilitu. PoužitíVirtualDevice
umožňuje vytvoření sekvence, které je méně omezené specifikacemi zařízení, což je vhodné pro spuštění v emulátoru. Další informace najdete v dokumentaci k Pulseru.from pulser import Sequence seq = Sequence(reg, QPU) # print the available channels for your sequence print(seq.available_channels) # Declare a channel. In this example we will be using `rydberg_global` seq.declare_channel("ch0", "rydberg_global")
Přidejte do sekvence impulsy. Uděláte to tak, že vytvoříte a přidáte impulsy do kanálů, které jste deklarovali. Například následující kód vytvoří impuls a přidá ho do kanálu
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()
Následující obrázek znázorňuje sekvenci impulsů.
Převod sekvence na řetězec JSON
Pokud chcete odeslat sekvence impulsů, musíte převést objekty Pulser na řetězec JSON, který lze použít jako vstupní data.
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
Odeslání sekvence impulsů do PASQAL target
Nejprve je potřeba nastavit správné formáty vstupních a výstupních dat. Následující kód například nastaví formát vstupních dat na
pasqal.pulser.v1
formát výstupních dat a na formát výstupních dat .pasqal.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 job
Poznámka:
Doba potřebná ke spuštění úlohy v QPU závisí na aktuálních časech fronty. Průměrnou dobu target fronty můžete zobrazit výběrem okna Poskytovatelé vašeho pracovního prostoru.
Odešlete program do PASQAL. Před odesláním kódu do skutečného kvantového hardwaru můžete svůj kód otestovat pomocí emulátoru
pasqal.sim.emu-tn
jako .targettarget = 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 }
Odeslání okruhu do Quantinuum pomocí OpenQASM
Vytvořte kvantový okruh v reprezentaci OpenQASM . Například následující příklad vytvoří teleportační okruh:
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]; """
Volitelně můžete okruh načíst ze souboru:
with open("my_teleport.qasm", "r") as f: circuit = f.read()
Odešle okruh do Quantinuum target. Následující příklad používá validátor rozhraní API Quantinuum, který vrací
Job
objekt.target = workspace.get_targets(name="quantinuum.sim.h1-1sc") job = target.submit(circuit, shots=500)
Počkejte, až se úloha dokončí, a pak načtěte výsledky.
results = job.get_results() print(results)
........ {'c0': ['000', '000', '000', '000', '000', '000', '000', ... ]}
Výsledky pak můžete vizualizovat pomocí knihovny Matplotlib.
import pylab as pl pl.hist(results["c0"]) pl.ylabel("Counts") pl.xlabel("Bitstring")
Při pohledu na histogram si můžete všimnout, že generátor náhodných čísel vrátil 0 pokaždé, což není příliš náhodné. Je to proto, že zatímco validátor rozhraní API zajišťuje úspěšné spuštění kódu na hardwaru Quantinuum, vrátí také hodnotu 0 pro každé kvantové měření. Pro skutečný generátor náhodných čísel musíte spustit okruh na kvantovém hardwaru.
Před spuštěním úlohy v QPU byste měli odhadnout, kolik bude stát spuštění.
Poznámka:
Nejaktuálnější podrobnosti o cenách najdete v tématu Ceny služby Azure Quantum nebo vyhledejte svůj pracovní prostor a zobrazte cenové možnosti na kartě Poskytovatel vašeho pracovního prostoru prostřednictvím: aka.ms/aq/myworkspaces.
Odeslání okruhu do Rigetti pomocí Quilu
Nejjednodušší způsob, jak odesílat úlohy Quil, je použití balíčku pyquil-for-azure-quantum , protože umožňuje používat nástroje a dokumentaci knihovny pyQuil . Bez tohoto balíčku lze pyQuil použít k vytváření programů Quil, ale ne k jejich odeslání do Azure Quantum.
Programy Quil můžete také sestavit ručně a odeslat je přímo pomocí azure-quantum
balíčku.
Nejprve načtěte požadované importy.
from pyquil.gates import CNOT, MEASURE, H from pyquil.quil import Program from pyquil.quilbase import Declare from pyquil_for_azure_quantum import get_qpu, get_qvm
get_qvm
Pomocí funkce můžeteget_qpu
získat připojení k QVM nebo QPU.qc = get_qvm() # For simulation # qc = get_qpu("Ankaa-9Q-3") for submitting to a QPU
Vytvořte program Quil. Jakýkoli platný program Quil je přijat, ale čtení musí být pojmenováno
ro
.program = Program( Declare("ro", "BIT", 2), H(0), CNOT(0, 1), MEASURE(0, ("ro", 0)), MEASURE(1, ("ro", 1)), ).wrap_in_numshots_loop(5) # Optionally pass to_native_gates=False to .compile() to skip the compilation stage result = qc.run(qc.compile(program)) data_per_shot = result.readout_data["ro"]
Tady je
numpy
pole,data_per_shot
takže můžete použítnumpy
metody.assert data_per_shot.shape == (5, 2) ro_data_first_shot = data_per_shot[0] assert ro_data_first_shot[0] == 1 or ro_data_first_shot[0] == 0
Vytiskněte všechna data.
print("Data from 'ro' register:") for i, shot in enumerate(data_per_shot): print(f"Shot {i}: {shot}")
Důležité
Odesílání více okruhů v jedné úloze se v současné době nepodporuje. Jako alternativní řešení můžete volat metodu backend.run
pro asynchronní odeslání každého okruhu a pak načíst výsledky každé úlohy. Příklad:
jobs = []
for circuit in circuits:
jobs.append(backend.run(circuit, shots=N))
results = []
for job in jobs:
results.append(job.result())