Отправка определенных форматированных каналов в Azure Quantum
Узнайте, как использовать azure-quantum
Python пакет для отправки каналов в определенных форматах в службу Azure Quantum. В этой статье показано, как отправлять каналы в следующих форматах:
Дополнительные сведения см. в разделе Квантовые цепи.
Примечание.
Пакет средств разработки Microsoft Quantum (классический QDK) больше не будет поддерживаться после 30 июня 2024 г. Если вы являетесь разработчиком QDK, рекомендуется перейти на новый пакет средств разработки Azure Quantum (современный QDK), чтобы продолжить разработку квантовых решений. Дополнительные сведения см. в разделе "Перенос кода Q# на современный QDK".
Необходимые компоненты
Чтобы запустить каналы в записной книжке в портал Azure, вам потребуется:
- Учетная запись Azure с активной подпиской. Если у вас нет учетной записи Azure, зарегистрируйтесь бесплатно и зарегистрируйтесь для подписки с оплатой по мере использования.
- Рабочая область Azure Quantum. Дополнительные сведения см. в статье Создание рабочей области Azure Quantum.
Для разработки и запуска каналов в Visual Studio Code также потребуется:
Среда сPythonустановленной Python программой Pip.
VS Code с установленными расширениями Jupyter для Azure Quantum Development KitPython и Jupyter.
Azure Quantum
qsharp
azure-quantum
иipykernel
пакеты.python -m pip install --upgrade qsharp azure-quantum ipykernel
Создание новой записной книжки Jupyter Notebook
Записную книжку можно создать в VS Code или непосредственно на портале Azure Quantum.
- Войдите на портал Azure и выберите рабочую область, которую вы назначили на предыдущем шаге.
- В левой колонке выберите Записные книжки.
- Щелкните Мои записные книжки и щелкните Добавить новую.
- В поле Тип ядра выберите IPython.
- Введите имя файла и нажмите кнопку "Создать файл".
При открытии новой записной книжки автоматически создается код для первой ячейки на основе сведений о подписке и рабочей области.
from azure.quantum import Workspace
workspace = Workspace (
resource_id = "", # Your resource_id
location = "" # Your workspace location (for example, "westus")
)
Отправка каналов с форматированием QIR
Квантовое промежуточное представление (QIR) — это промежуточное представление, которое служит общим интерфейсом между языками и платформами квантового программирования и targetплатформами квантовых вычислений. Дополнительные сведения см. в статье о квантовом промежуточном представлении.
Создайте канал QIR. Например, следующий код создает простой канал запутания.
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} """
Создайте вспомогательную
submit_qir_job
функцию для отправки канала QIR в targetобъект. Обратите внимание, что форматы входных и выходных данных указываются как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
target Выберите и отправьте канал QIR в Azure Quantum. Например, чтобы отправить канал QIR в симулятор 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]}
Отправка канала с форматом, определенным поставщиком, в Azure Quantum
Помимо языков QIR, таких как Q# или Qiskit, можно отправлять квантовые каналы в форматы, относящиеся к поставщику, в Azure Quantum. Каждый поставщик имеет собственный формат для представления квантовых каналов.
Отправка канала в IonQ с помощью формата JSON
Создайте квантовый канал с помощью формата JSON, не зависящего от языка, поддерживаемого IonQ targets, как описано в документации по API IonQ. Например, в приведенном ниже примере создается суперпозиция между тремя кубитами:
circuit = { "qubits": 3, "circuit": [ { "gate": "h", "target": 0 }, { "gate": "cnot", "control": 0, "target": 1 }, { "gate": "cnot", "control": 0, "target": 2 }, ] }
Отправьте канал в IonQ target. В следующем примере используется симулятор IonQ, который возвращает объект
Job
.target = workspace.get_targets(name="ionq.simulator") job = target.submit(circuit)
Дождитесь завершения задания и получите результаты.
results = job.get_results() print(results)
..... {'duration': 8240356, 'histogram': {'0': 0.5, '7': 0.5}}
Затем результаты можно визуализировать с помощью 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")
Перед выполнением задания на QPU вы можете оценить, сколько будет стоить его выполнение. Чтобы оценить затраты на выполнение задания в QPU, можно использовать метод
estimate_cost
:target = workspace.get_targets(name="ionq.qpu") cost = target.estimate_cost(circuit, shots=500) print(f"Estimated cost: {cost.estimated_total}")
Это действие выводит оценочные затраты в долларах США (USD).
Примечание.
Актуальные сведения о ценах см. в статье Цены на IonQ, или найдите рабочую область и просмотрите параметры ценообразования на вкладке "Поставщик" с помощью команды: aka.ms/aq/myworkspaces.
Отправка канала в PASQAL с помощью пакета SDK Для Пульса
Чтобы отправить канал в PASQAL, можно использовать пакет SDK Для Пульса для создания последовательностей импульсов и отправки их в PASQAL target.
Установка пакета SDK Для Pulser
Pulser — это платформа для создания, имитации и выполнения последовательностей импульсов для квантовых устройств нейтрального атома. Он разработан PASQAL в качестве сквозной передачи для отправки квантовых экспериментов на их квантовые процессоры. Дополнительные сведения см . в документации по Pulser.
Чтобы отправить последовательности импульсов, сначала установите пакеты ПАКЕТА SDK Для Pulser:
try:
import pulser
except ImportError:
!pip -q install pulser
!pip -q install pulser-core
Создание квантового регистра
Сначала загрузите необходимые импорты:
import numpy as np import pulser from pprint import pprint from pulser import Pulse, Sequence, Register
ЦП PASQAL состоит из нейтральных атомов, захваченных на хорошо определенных позициях в решетке. Чтобы определить квантовые регистры, вы создадите массив кубитов в решетке. Например, следующий код создает 4x4 квадратных решеток кубитов:
L = 4 square = np.array([[i, j] for i in range(L) for j in range(L)], dtype=float) square -= np.mean(square, axis=0) square *= 5 qubits = dict(enumerate(square)) reg = Register(qubits) reg.draw()
Запись импульсной последовательности
Нейтральные атомы контролируются лазерными импульсами. Пакет SDK для Pulser позволяет создавать последовательности импульсов для применения к квантовому регистру.
Сначала необходимо настроить последовательность импульсов и объявить каналы, которые будут использоваться для управления атомами. Например, следующий код объявляет два канала:
ch0
иch1
.from pulser.devices import Chadoq2 seq = Sequence(reg, Chadoq2) seq.declare_channel("ch0", "raman_local") print("Available channels after declaring 'ch0':") pprint(seq.available_channels) seq.declare_channel("ch1", "rydberg_local", initial_target=4) print("\nAvailable channels after declaring 'ch1':") pprint(seq.available_channels)
Несколько вещей, которые следует рассмотреть:
- В
Sequence
Пульсе — это ряд операций, выполняемых в квантовом регистре. - Код настраивает последовательность операций, выполняемых на
AnalogDevice
устройстве.AnalogDevice
— это предопределенное устройство в Pulser, представляющее квантовый компьютер Fresnel1.
- В
Создайте последовательность импульсов. Для этого вы создаете и добавляете импульсы в объявленные каналы. Например, следующий код создает простой импульс и добавляет его в канал
ch0
, а затем создает сложный импульс и добавляет его в каналch1
.seq.target(1, "ch0") # Target qubit 1 with channel "ch0" simple_pulse = Pulse.ConstantPulse(200, 2, -10, 0) seq.add(simple_pulse, "ch0") # Add the pulse to channel "ch0" seq.delay(100, "ch1") from pulser.waveforms import RampWaveform, BlackmanWaveform duration = 1000 # Create a Blackman waveform with a duration of 1000 ns and an area of pi/2 rad amp_wf = BlackmanWaveform(duration, np.pi / 2) # Create a ramp waveform with a duration of 1000 ns and a linear sweep from -20 to 20 rad/µs detuning_wf = RampWaveform(duration, -20, 20) # Create a pulse with the amplitude waveform amp_wf, the detuning waveform detuning_wf, and a phase of 0 rad. complex_pulse = Pulse(amp_wf, detuning_wf, phase=0) complex_pulse.draw() seq.add(complex_pulse, "ch1") # Add the pulse to channel "ch1"
На изображении показан простой и сложный пульс.
Преобразование последовательности в строку JSON
Чтобы отправить импульсные последовательности, необходимо преобразовать объекты Pulser в строку JSON, которая может использоваться в качестве входных данных.
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)
#print(json.dumps(input_data, indent=4, sort_keys=True))
return to_send
Отправка последовательности импульсов в PASQAL target
Сначала необходимо задать правильные форматы входных и выходных данных. Например, следующий код задает формат
pasqal.pulser.v1
входных данных и форматpasqal.pulser-results.v1
выходных данных.# Submit the job with proper input and output data formats def submit_job(target, seq): 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=100 # Number of shots ) print(f"Queued job: {job.id}") job.wait_until_completed() print(f"Job completed with state: {job.details.status}") result = job.get_results() return result
Примечание.
Требуемое время для выполнения цепи на QPU может оказаться разным в зависимости от текущего времени в очереди. Среднее время target очереди можно просмотреть, выбрав колонку "Поставщики " рабочей области.
Отправьте программу в PASQAL. Например, вы можете отправить программу в PASQAL Emu-TN target.
target = workspace.get_targets(name="pasqal.sim.emu-tn") submit_job(target, seq)
{'0000000000000000': 59, '0000100000000000': 39, '0100000000000000': 1, '0100100000000000': 1}
Отправка канала в Quantinuum с помощью OpenQASM
Создайте квантовую цепь в представлении OpenQASM. Например, в приведенном ниже примере создается цепь телепортации:
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]; """
При желании цепь можно загрузить из файла:
with open("my_teleport.qasm", "r") as f: circuit = f.read()
Отправьте канал в Quantinuum target. В следующем примере используется проверяющий элемент управления API Quantinuum, который возвращает объект
Job
.target = workspace.get_targets(name="quantinuum.sim.h1-1sc") job = target.submit(circuit, shots=500)
Дождитесь завершения задания и получите результаты.
results = job.get_results() print(results)
........ {'c0': ['000', '000', '000', '000', '000', '000', '000', ... ]}
Затем результаты можно визуализировать с помощью Matplotlib.
import pylab as pl pl.hist(results["c0"]) pl.ylabel("Counts") pl.xlabel("Bitstring")
На гистограмме показано, что генератор случайных чисел возвращает 0 каждый раз, что не является случайным результатом. Это связано с тем, что валидатор API гарантирует возможность успешно выполнить код оборудовании Quantinuum, но возвращает 0 для всех квантовых измерений. Для генератора по-настоящему случайных чисел необходимо запустить цепь на квантовом оборудовании.
Перед выполнением задания на QPU вы можете оценить, сколько будет стоить его выполнение. Чтобы оценить затраты на выполнение задания в QPU, можно использовать метод
estimate_cost
.target = workspace.get_targets(name="quantinuum.qpu.h1-1") cost = target.estimate_cost(circuit, shots=500) print(f"Estimated cost: {cost.estimated_total}")
Будет отображена оценочная стоимость в кредитах HQC (H-System Quantum Credits).
Примечание.
Чтобы выполнить оценку затрат по quantinuum target, необходимо сначала перезагрузить пакет Azure-quantumPython с параметром [qiskit] и убедиться, что у вас есть последняя версия Qiskit. Дополнительные сведения см. в статье об обновлении пакета Azure-QuantumPython.
Примечание.
Дополнительные сведения о ценах см. в разделе "Цены на Azure Quantum" или найдите рабочую область и просмотрите параметры ценообразования на вкладке "Поставщик" рабочей области с помощью aka.ms/aq/myworkspaces.
Отправка канала в Rigetti с помощью Quil
Самый простой способ отправки заданий Quil — использовать пакет pyquil-for-azure-quantum , так как он позволяет использовать инструменты и документацию библиотеки pyQuil . Без этого пакета pyQuil можно использовать для создания программ Quil, но не для отправки их в Azure Quantum.
Вы также можете создавать программы Quil вручную и отправлять их напрямую с помощью пакета azure-quantum
.
Сначала загрузите необходимые импорты.
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
Используйте илиget_qpu
функцию, чтобы получить подключение к QVM или QPU.qc = get_qvm() # For simulation # qc = get_qpu("Ankaa-2") for submitting to a QPU
Создайте программу Quil. Любая допустимая программа Quil принимается, но чтение должно быть названо
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"]
Вот массив,
data_per_shot
numpy
поэтому можно использоватьnumpy
методы.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
Распечатайте все данные.
print("Data from 'ro' register:") for i, shot in enumerate(data_per_shot): print(f"Shot {i}: {shot}")
Внимание
Отправка нескольких цепей в одном задании в настоящее время не поддерживается. В качестве обходного решения можно вызвать метод backend.run
для асинхронной отправки каждой цепи, а затем получить результаты каждого задания. Например:
jobs = []
for circuit in circuits:
jobs.append(backend.run(circuit, shots=N))
results = []
for job in jobs:
results.append(job.result())
Связанный контент
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по