Отправка определенных форматированных каналов в Azure Quantum
Узнайте, как использовать azure-quantum
Python пакет для отправки каналов в определенных форматах в службу Azure Quantum. В этой статье показано, как отправлять каналы в следующих форматах:
Дополнительные сведения см. в разделе Квантовые цепи.
Необходимые компоненты
Чтобы запустить каналы в записной книжке в портал 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
Quantum Intermediate Representation (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
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")
Перед выполнением задания на ЦП необходимо оценить, сколько будет стоить выполнение.
Примечание.
Актуальные сведения о ценах см. в статье Цены на 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
Создание квантового регистра
Перед продолжением необходимо определить как регистр, так и макет. Регистр указывает, где будут упорядочены атомы, в то время как макет указывает расположение ловушек, необходимых для захвата и структуры этих атомов в регистре.
Дополнительные сведения о макетах см. в документации по Pulser.
Сначала вы создадите объект "devices" для импорта квантового компьютера targetPASQAL , Fresnel.
from pulser_pasqal import PasqalCloud devices = PasqalCloud().fetch_available_devices() QPU = devices["FRESNEL"]
Предварительно откалиброванные макеты
Устройство определяет список предварительно настроенных макетов. Вы можете создать регистрацию из одного из этих макетов.
Это рекомендуемый вариант, так как он улучшит производительность QPU.
Вариант 1. Определение регистрации с помощью предварительно настроенных макетов
Проверьте макеты, доступные в Fresnel, и определите регистр из этого макета. Дополнительные сведения о том, как это сделать, см. в документации по пульсу.
Пример:
# 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()
Произвольные макеты
Если предварительно настроенные макеты не соответствуют требованиям эксперимента, можно создать пользовательский макет.
Для любого заданного произвольного регистра ЦП нейтрального атома будет размещать ловушки в соответствии с макетом, который затем должен пройти калибровку. Так как для каждой калибровки требуется время, обычно рекомендуется повторно использовать существующий макет калибровки по возможности.
Вариант 2. Автоматическое наследование макета из определенного регистра
Этот параметр позволяет автоматически создать макет на основе указанного регистра. Однако для больших регистров этот процесс может привести к подоптимальным решениям из-за ограничений в алгоритме, используемом для создания макета.
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. Определение регистрации с помощью вручную определенного макета
- Создание произвольного макета с 20 ловушками случайным образом, расположенным в плоскости 2D
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")
- Определение регистра с определенными идентификаторами ловушки
trap_ids = [4, 8, 19, 0] reg = layout.define_register(*trap_ids, qubit_ids=["a", "b", "c", "d"]) reg.draw()
Запись импульсной последовательности
Нейтральные атомы контролируются лазерными импульсами. Пакет SDK для Pulser позволяет создавать последовательности импульсов для применения к квантовому регистру.
Во-первых, вы определяете атрибуты последовательности пульса, объявляя каналы, которые будут использоваться для управления атомами. Чтобы создать
Sequence
экземпляр, необходимо предоставитьRegister
экземпляр вместе с устройством, где будет выполнена последовательность. Например, следующий код объявляет один канал:ch0
Примечание.
Вы можете использовать устройство или импортировать виртуальное
QPU = devices["FRESNEL"]
устройство из Pulser для повышения гибкости. ИспользованиеVirtualDevice
функции позволяет создавать последовательность, которая менее ограничена спецификациями устройств, что делает его подходящим для выполнения в эмуляторе. Дополнительные сведения см . в документации по Pulser.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")
Добавьте импульсы в последовательность. Для этого вы создаете и добавляете импульсы в объявленные каналы. Например, следующий код создает импульс и добавляет его в канал
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-tn
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 }
Отправка канала в 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 для всех квантовых измерений. Для генератора по-настоящему случайных чисел необходимо запустить цепь на квантовом оборудовании.
Перед выполнением задания на ЦП необходимо оценить, сколько будет стоить выполнение.
Примечание.
Дополнительные сведения о ценах см. в разделе "Цены на 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-9Q-3") 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())