Megosztás a következőn keresztül:


Adott formázott kapcsolatcsoportok elküldése az Azure Quantumba

Ebből a azure-quantumPython cikkből megtudhatja, hogyan küldhet el kapcsolatcsoportokat adott formátumban az Azure Quantum service-nek a csomag használatával. Ez a cikk bemutatja, hogyan küldhet be kapcsolatcsoportokat a következő formátumokban:

További információ: Kvantum-kapcsolatcsoportok.

Előfeltételek

Ha a kapcsolatcsoportokat egy Jegyzetfüzetben szeretné futtatni az Azure Portalon, a következőkre van szüksége:

  • Egy Azure-fiók, aktív előfizetéssel. Ha nem rendelkezik Azure-fiókkal, regisztráljon ingyenesen, és regisztráljon használatalapú fizetéses előfizetésre.
  • Egy Azure Quantum-munkaterület. További információ: Azure Quantum-munkaterület létrehozása.

A kapcsolatcsoportok Visual Studio Code-ban való fejlesztéséhez és futtatásához a következőkre is szükség van:

Új Jupyter Notebook létrehozása

Jegyzetfüzetet a VS Code-ban vagy közvetlenül az Azure Quantum Portalon hozhat létre.

  1. Jelentkezzen be az Azure Portalra , és válassza ki a munkaterületet az előző lépésből.
  2. A bal oldali panelen válassza a Jegyzetfüzetek lehetőséget.
  3. Kattintson a Saját jegyzetfüzetek elemre, majd az Új hozzáadása parancsra.
  4. Kerneltípusban válassza az IPython lehetőséget.
  5. Írja be a fájl nevét, és kattintson a Fájl létrehozása parancsra.

Amikor megnyílik az új jegyzetfüzet, automatikusan létrehozza az első cellához tartozó kódot az előfizetés és a munkaterület adatai alapján.

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

QIR-formátumú kapcsolatcsoportok küldése

A kvantum köztes reprezentáció (QIR) egy köztes reprezentáció, amely a kvantumprogramozási nyelvek/keretrendszerek és a célzott kvantumszámítási platformok közös interfésze. További információ: Kvantum köztes ábrázolás.

  1. Hozza létre a QIR-kapcsolatcsoportot. A következő kód például létrehoz egy egyszerű összefonódási áramkört.

    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}
    """
    
  2. Hozzon létre egy submit_qir_job segédfüggvényt a QIR-kapcsolatcsoport elküldéséhez egy target. Vegye figyelembe, hogy a bemeneti és kimeneti adatformátumok és a kimeneti adatformátumok is meg vannak adva qir.v1 microsoft.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
    
  3. Válasszon ki egy QIR-kapcsolatcsoportot target , és küldje el az Azure Quantumnak. Például a QIR-kapcsolatcsoport elküldése az IonQ-szimulátorba target:

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

Szolgáltatóspecifikus formátumú kapcsolatcsoport beküldése az Azure Quantumba

A QIR-nyelvek, például a Q# vagy a Qiskit mellett szolgáltatóspecifikus formátumban is küldhet kvantum áramköröket az Azure Quantumnak. Minden szolgáltató saját formátummal rendelkezik a kvantumkörök ábrázolásához.

Kapcsolatcsoport beküldése az IonQ-ba JSON formátum használatával

  1. Hozzon létre egy kvantumköröket az IonQ targetsáltal támogatott nyelvi JSON-formátummal, az IonQ API dokumentációjában leírtak szerint. Az alábbi minta például egy szuperpozíciót hoz létre három qubit között:

    circuit = {
        "qubits": 3,
        "circuit": [
            {
            "gate": "h",
            "target": 0
            },
            {
            "gate": "cnot",
            "control": 0,
            "target": 1
            },
            {
            "gate": "cnot",
            "control": 0,
            "target": 2
            },
        ]
    }
    
  2. Küldje el a kapcsolatcsoportot az IonQ-nak target. Az alábbi példa az IonQ-szimulátort használja, amely egy objektumot Job ad vissza.

    target = workspace.get_targets(name="ionq.simulator")
    job = target.submit(circuit)
    
  3. Várjon, amíg a feladat befejeződik, majd kérje le az eredményeket.

    results = job.get_results()
    print(results)
    
    .....
    {'duration': 8240356, 'histogram': {'0': 0.5, '7': 0.5}}
    
  4. Ezután megjelenítheti az eredményeket a Matplotlib használatával.

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

    IonQ-feladat kimenete

  5. Mielőtt futtatna egy feladatot a QPU-n, meg kell becsülnie, hogy mennyibe fog kerülni a futtatás.

    Feljegyzés

    A legfrissebb díjszabási részletekért tekintse meg az IonQ díjszabását, vagy keresse meg a munkaterületet, és tekintse meg a díjszabási beállításokat a munkaterület "Szolgáltató" lapján a következő aka.ms/aq/myworkspaces keresztül.

Kapcsolatcsoport elküldése a PASQAL-ba a Pulser SDK használatával

Ha a PASQAL-nak szeretne áramkört küldeni, a Pulser SDK-val impulzussorozatokat hozhat létre, és elküldheti őket a PASQAL-nak target.

A Pulser SDK telepítése

A Pulser a semleges atom kvantumeszközök impulzusütemezéseinek írására, szimulálására és végrehajtására szolgáló keretrendszer. A PASQAL úgy lett kialakítva, hogy továbbítsa a kvantumkísérleteket a kvantumprocesszoraiknak. További információt a Pulser dokumentációjában talál.

Az impulzusütemezések elküldéséhez először telepítse a Pulser SDK-csomagokat:

try:
    import pulser
    import pulser_pasqal
except ImportError:
    !pip -q install pulser pulser-pasqal --index-url https://pypi.org/simple

Kvantumregisztrációs regiszter létrehozása

A folytatás előtt meg kell határoznia a nyilvántartást és az elrendezést is. A regiszter meghatározza az atomok elhelyezésének helyét, míg az elrendezés meghatározza az atomok rögzítéséhez és szerkezetéhez szükséges csapdák helyét a regiszterben.

Az elrendezésekkel kapcsolatos részletekért tekintse meg a Pulser dokumentációját.

  • Először létre kell hoznia egy "eszközök" objektumot a PASQAL kvantumszámítógép target( Fresnel) importálásához.

    from pulser_pasqal import PasqalCloud
    
    devices = PasqalCloud().fetch_available_devices()
    QPU = devices["FRESNEL"]
    
Előre kalibrált elrendezések

Az eszköz előre kalibrált elrendezések listáját határozza meg. A regisztrációt ezen elrendezések egyikéből hozhatja létre.

Ez az ajánlott lehetőség, mert javítja a QPU teljesítményét.

  • 1. lehetőség: A regisztráció definiálása előre kalibrált elrendezésekkel

    Vizsgálja meg a Fresnelen elérhető elrendezéseket, és határozza meg a nyilvántartást ebből az elrendezésből. Erről további információt a pulser dokumentációjában talál.

    Példa:

    # 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()
    
Tetszőleges elrendezések

Ha az előre kalibrált elrendezések nem felelnek meg a kísérlet követelményeinek, létrehozhat egy egyéni elrendezést.

Bármely tetszőleges regiszter esetében a semleges atom QPU az elrendezésnek megfelelően csapdákat helyez el, amelyeket ezután kalibrálásnak kell alávetni. Mivel minden kalibrációhoz idő szükséges, általában célszerű a meglévő kalibrált elrendezést újra felhasználni, amikor csak lehetséges

  • 2. lehetőség: Elrendezés automatikus levezetése a megadott regiszterből

    Ez a beállítás lehetővé teszi egy elrendezés automatikus létrehozását egy megadott regiszter alapján. A nagy méretű regiszterek esetében azonban ez a folyamat az elrendezés létrehozásához használt algoritmus korlátai miatt az optimálisnál rosszabb megoldásokat eredményezhet.

    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) 
    
  • 3. lehetőség: A regisztráció definiálása manuálisan meghatározott elrendezés használatával

    • Tetszőleges elrendezés létrehozása 20 trap véletlenszerű elhelyezésével egy 2D síkban
    import numpy as np
    from pulser.register.register_layout import RegisterLayout
    
    # 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")
    
    • A regisztráció definiálása adott trapazonosítókkal
    trap_ids = [4, 8, 19, 0]
    reg = layout.define_register(*trap_ids, qubit_ids=["a", "b", "c", "d"])
    reg.draw()
    

Impulzusütemezés írása

A semleges atomokat lézerimpulzusokkal irányítják. A Pulser SDK lehetővé teszi, hogy impulzussorozatokat hozzon létre a kvantumregisztrációs regiszterre való alkalmazáshoz.

  1. Először meg kell határoznia az impulzusütemezési attribútumokat az atomok vezérléséhez használt csatornák deklarálásával. A létrehozáshoz Sequencemeg kell adnia egy példányt, valamint azt Register az eszközt, amelyben a sorozat végrehajtásra kerül. A következő kód például egy csatornát deklarál: ch0.

    Feljegyzés

    A nagyobb rugalmasság érdekében használhatja az QPU = devices["FRESNEL"] eszközt, vagy importálhat egy virtuális eszközt a Pulserből. A használat VirtualDevice lehetővé teszi a sorozat létrehozását, amely kevésbé korlátozza az eszköz specifikációi, így alkalmas a végrehajtás egy emulátor. További információt a Pulser dokumentációjában talál.

    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")
    
  2. Adjon hozzá impulzusokat a sorozathoz. Ehhez impulzusokat hozhat létre és adhat hozzá a deklarált csatornákhoz. Az alábbi kód például létrehoz egy impulzust, és hozzáadja a csatornához 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()
    

    Az alábbi képen az impulzussorozat látható. Impulzusütemezés

A sorozat átalakítása JSON-sztringgé

Az impulzusütemezések elküldéséhez a Pulser-objektumokat JSON-sztringgé kell konvertálnia, amely bemeneti adatokként használható.

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

Az impulzusütemezés elküldése a PASQAL-nak target

  1. Először meg kell adnia a megfelelő bemeneti és kimeneti adatformátumokat. A következő kód például a bemeneti adatformátumot pasqal.pulser.v1 állítja be, a kimeneti adatformátumot pedig a következőre 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
    

    Feljegyzés

    A feladat QPU-n való futtatásához szükséges idő az aktuális várakozási időtől függ. Az átlagos üzenetsor-időt target a munkaterület Szolgáltatók paneljének kiválasztásával tekintheti meg.

  2. Küldje el a programot a PASQAL-nak. Mielőtt valódi kvantumhardverbe küldené a kódot, tesztelheti a kódot az emulátor pasqal.sim.emu-tn használatával target.

    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
    }
    

Kapcsolatcsoport elküldése a Quantinuumba az OpenQASM használatával

  1. Hozzon létre egy kvantum-kapcsolatcsoportot az OpenQASM-ábrázolásban . Az alábbi példa például létrehoz egy Teleportation-kapcsolatcsoportot:

    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];
    """
    

    A kapcsolatcsoportot egy fájlból is betöltheti:

    with open("my_teleport.qasm", "r") as f:
        circuit = f.read()
    
  2. Küldje el a kapcsolatcsoportot a Quantinuumnak target. Az alábbi példa a Quantinuum API-érvényesítőt használja, amely egy objektumot Job ad vissza.

    target = workspace.get_targets(name="quantinuum.sim.h1-1sc")
    job = target.submit(circuit, shots=500)
    
  3. Várjon, amíg a feladat befejeződik, majd kérje le az eredményeket.

    results = job.get_results()
    print(results)
    
    ........
    {'c0': ['000',
    '000',
    '000',
    '000',
    '000',
    '000',
    '000',
    ...
    ]}
    
  4. Ezután megjelenítheti az eredményeket a Matplotlib használatával.

    import pylab as pl
    pl.hist(results["c0"])
    pl.ylabel("Counts")
    pl.xlabel("Bitstring")
    

    Quantinuum-feladat kimenete

    A hisztogramot vizsgálva észreveheti, hogy a véletlenszerű számgenerátor minden alkalommal 0-t ad vissza, ami nem túl véletlenszerű. Ennek az az oka, hogy bár az API Validator biztosítja, hogy a kód sikeresen fusson a Quantinuum hardveren, a 0 értéket is visszaadja minden kvantumméréshez. Egy valódi véletlenszám-generátorhoz kvantumhardveren kell futtatnia a kapcsolatcsoportot.

  5. Mielőtt futtatna egy feladatot a QPU-n, meg kell becsülnie, hogy mennyibe fog kerülni a futtatás.

    Feljegyzés

    A legfrissebb díjszabási részletekért tekintse meg az Azure Quantum díjszabását, vagy keresse meg a munkaterületet, és tekintse meg a díjszabási lehetőségeket a munkaterület "Szolgáltató" lapján a következő aka.ms/aq/myworkspaces keresztül.

Kapcsolatcsoport elküldése Rigettinek a Quil használatával

A Quil-feladatok elküldésének legegyszerűbb módja a pyquil-for-azure-quantum csomag használata, mivel lehetővé teszi a pyQuil-kódtár eszközeinek és dokumentációjának használatát. A csomag nélkül a pyQuil használható Quil-programok létrehozására, de nem az Azure Quantumba való beküldésére.

A Quil-programokat manuálisan is létrehozhatja, és közvetlenül a azure-quantum csomag használatával küldheti el őket.

  1. Először töltse be a szükséges importálásokat.

    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
    
  2. A vagy get_qpu függvény get_qvm használatával kapcsolatot létesíthet a QVM-hez vagy a QPU-hoz.

    qc = get_qvm()  # For simulation
    # qc = get_qpu("Ankaa-3") for submitting to a QPU
    
  3. Hozzon létre egy Quil-programot. A rendszer elfogadja az érvényes Quil-programokat, de az olvasást el kell nevezni 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"]
    
  4. data_per_shot Itt egy numpy tömb található, így használhat numpy módszereket.

    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
    
  5. Nyomtassa ki az összes adatot.

    print("Data from 'ro' register:")
    for i, shot in enumerate(data_per_shot):
        print(f"Shot {i}: {shot}")
    

Fontos

Több kapcsolatcsoport elküldése egy feladaton jelenleg nem támogatott. Áthidaló megoldásként meghívhatja a metódust az backend.run egyes áramkörök aszinkron elküldéséhez, majd lekérheti az egyes feladatok eredményeit. Példa:

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

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