Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Узнайте, как использовать модуль qdk.azurePython для отправки схем в определённых форматах в службу Azure Quantum. В этой статье показано, как отправлять схемы в следующих форматах:
Дополнительные сведения см. в разделе Квантовые цепи.
Предварительные требования
Для разработки и запуска схем в Visual Studio Code (VS Code) необходимо иметь следующее:
Учетная запись Azure с активной подпиской. Если у вас нет учетной записи Azure, зарегистрируйтесь бесплатно и зарегистрируйтесь для подписки pay-as-you-go.
Рабочая область Azure Quantum. Дополнительные сведения см. в разделе Создание рабочей области Azure Quantum.
Среда Python с установленными Python и Pip.
VS Code с установленными расширениями Microsoft Quantum Development Kit (QDK), Python и Jupyter.
Пакет
qdkPython с дополнительным пакетомazureи пакетомipykernel.python -m pip install --upgrade "qdk[azure]" ipykernel
Создайте новую записную книжку Jupyter и подключитесь к Quantum рабочей среде
Чтобы подключиться к рабочей области в записной книжке Jupyter в VS Code, выполните следующие действия:
В VS Code откройте меню "Вид " и выберите палитру команд.
Введите Create: New Jupyter Notebook. Пустой файл Jupyter Notebook открывается на новой вкладке.
В первой ячейке записной книжки выполните следующий код. Идентификатор ресурса можно найти в области Overview для рабочей области на портале Azure.
from qdk.azure import Workspace workspace = Workspace (resource_id="") # Add your resource ID
Отправьте схемы с форматированием QIR
Квантовое промежуточное представление (QIR) — это промежуточное представление, которое служит общим интерфейсом между языками квантового программирования и целевыми квантовыми вычислительными платформами. Дополнительные сведения см. в статье о квантовом промежуточном представлении.
Чтобы отправить схему в формате QIR, выполните следующие действия.
Создайте канал 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Отправьте схему QIR в определенный Azure Quantum target. Например, чтобы отправить канал QIR в симулятор targetIonQ, выполните следующий код:
target = workspace.get_targets(name="ionq.simulator") result = submit_qir_job(target, QIR_routine, "QIR routine") result
Отправка схемы в формате, определяемом поставщиком, в Azure Quantum
Каждый поставщик Azure Quantum имеет собственный формат для представления квантовых каналов. Каналы можно отправлять в Azure Quantum в форматах, зависящих от поставщика, а не на языках QIR, таких как Q# или Qiskit.
Отправьте схему в IonQ в формате JSON
IonQ использует формат JSON для запуска квантовых схем на targets. Дополнительные сведения см. в IonQtargets и в документации по API IonQ.
В следующем примере создается суперпозиция между тремя кубитами в формате JSON.
В новой ячейке создайте квантовый канал в формате JSON.
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)
Отправьте схему в Pasqal в формате Pulser SDK
Пакет SDK для Pulser можно использовать для создания последовательностей импульсов и отправки их в Pasqal targets.
Установка SDK Pulser
Pulser — это платформа, которая позволяет создавать, имитировать и запускать последовательности импульсов для квантовых устройств нейтрального атома. Pulser разработан PASQAL в качестве средства для отправки квантовых экспериментов на их квантовые процессоры. Дополнительные сведения см. в документации по Pulser.
Чтобы отправить пульсовые последовательности, сначала установите пакеты SDK Pulser.
try:
import pulser
import pulser_azure
except ImportError:
!pip -q install pulser pulser-azure --index-url https://pypi.org/simple
Создание квантового регистра
Определите как регистр, так и макет. Регистр указывает, где упорядочивать атомы, а макет указывает позиции ловушек, которые захватывают и структурируют атомы в регистре.
Дополнительные сведения о макетах см. в документации по Pulser.
Создайте объект devices для импорта квантового компьютера Pasqal target, FRESNEL_CAN1.
from pulser_azure import AzureConnection
connection = AzureConnection(resource_id="") # Add your resource ID
devices = connection.fetch_available_devices()
QPU = devices["pasqal.qpu.fresnel-can1"]
Настройка макета
Используйте пользовательский макет, если предварительно откалиброванные макеты не соответствуют требованиям эксперимента.
Для заданного произвольного регистра, квантовый процессор на основе нейтральных атомов размещает ловушки в соответствии со схемой, которую затем необходимо откалибровать. Так как каждая калибровка занимает некоторое время, рекомендуется повторно использовать существующий макет калибровки, когда это возможно.
Чтобы создать произвольный макет, выберите один из следующих вариантов:
Автоматически создайте макет на основе указанного регистра. Для больших регистров этот процесс может создавать субоптимальные решения. Например:
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(QPU)Чтобы вручную задать макет для создания вашего регистра, см. документацию по Pulser.
Написание импульсной последовательности
Нейтральные атомы контролируются лазерными импульсами. Пакет SDK для Pulser позволяет создавать последовательности импульсов для применения к квантовому регистру.
Определите атрибуты последовательности импульсов, объявив каналы, управляющие атомами. Чтобы создать
Sequenceэкземпляр, укажитеRegisterэкземпляр вместе с устройством, где будет выполняться последовательность. Например, следующий код объявляет один канал:ch0from 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")Примечание.
Вы можете использовать
QPU = devices["pasqal.qpu.fresnel-can1"]устройство или импортировать виртуальное устройство из Pulser для большей гибкости. ИспользованиеVirtualDeviceпозволяет создавать последовательности, которые менее ограничены спецификациями устройств, что даёт возможность работать на эмуляторе. Дополнительные сведения см. в документации Pulser.Добавьте импульсы в последовательность. Для этого создайте и добавьте импульсы в заданные каналы. Например, следующий код создает импульс и добавляет его в канал
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()На следующем рисунке показана последовательность пульса:
Преобразование последовательности в строку 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)
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, 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Примечание.
Время, необходимое для выполнения задания на ЦП, зависит от текущего времени очереди. Среднее время target очереди можно просмотреть на панели "Поставщики " рабочей области.
Отправьте программу в Pasqal. Перед отправкой кода в реальное квантовое оборудование рекомендуется протестировать код в эмуляторе
pasqal.sim.emu-mpstarget.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){ "counter": { "1000000": 8, "0010000": 1, "0010101": 1 } }
Используйте бэкенды Pulser для выполнения последовательности
С AzureConnection помощью pulser-azure можно напрямую использовать серверную часть QPU или серверную часть удаленного эмулятора для выполнения последовательности.
from pulser.backends import RemoteMPSBackend, QPUBackend
backend = RemoteMPSBackend(sequence=seq, connection=connection) # Replace RemoteMPSBackend with QPUBackend to execute the sequence on the QPU
results = backend.run(job_params=[{"runs": 10}], wait=True)
print(results.results[0].final_bitstrings)
Counter({"1000000": 8, "0010000": 1, "0010101": 1})
Отправьте схему OpenQASM в Quantinuum
Создайте квантовую цепь в представлении 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]; """Загрузите схему из файла OpenQASM.
with open("my_teleport.qasm", "r") as f: circuit = f.read()Отправьте цепь в Quantinuum target. В следующем примере задание отправляется в один из симуляторов targets Quantinuum.
target = workspace.get_targets(name="quantinuum.sim.h2-1sc") job = target.submit(circuit, shots=500)Дождитесь завершения задания и получите результаты.
results = job.get_results() print(results)
Примечание.
Эти результаты возвращают 000 для каждого выстрела, который не является случайным. Это связано с тем, что валидатор API проверяет, может ли код выполняться на оборудовании Quantinuum, но всегда возвращает 0 для каждого квантового измерения. Для генератора по-настоящему случайных чисел необходимо запустить цепь на квантовом оборудовании.
Отправьте схему Quil в Rigetti
Чтобы отправить задание Quil в Rigetti target, используйте модуль qdk.azurePython.
Загрузите необходимые импорты.
from azure.quantum import Workspace from azure.quantum.target.rigetti import Result, Rigetti, RigettiTarget, InputParamstargetСоздайте объект и передайте имя Rigettitarget, в которое вы хотите отправить задание. Например, следующий код выбираетQVMtarget.target = Rigetti(workspace=workspace, name=RigettiTarget.QVM)Создайте программу Quil. Для принятия вашей программы необходимо установить значение считывания на
"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 failedМожно индексировать результат с помощью имени считываемого параметра. В следующем коде
data_per_shotсодержится список длиныnum_shots, и каждый элемент списка представляет собой другой список, содержащий данные для регистра из этого кадра.data_per_shot = result[readout] ro_data_first_shot = data_per_shot[0]В этом случае, поскольку тип регистра — BIT, тип является целым числом и значением 0 или 1.
assert isinstance(ro_data_first_shot[0], int) assert ro_data_first_shot[0] == 1 or ro_data_first_shot[0] == 0Распечатайте все данные.
print(f"Data from '{readout}' 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())