Поделиться через


Отправка канала с помощью Qiskit в Azure Quantum

Узнайте, как отправить квантовый канал Qiskit с помощью azure-quantumPython пакета. Каналы Qiskit можно отправить в Azure Quantum с помощью записной книжки Azure Quantum, которая имеет встроенный azure-quantumPython пакет или на локальном компьютере. Вы также можете протестировать каналы с помощью локального разреженного симулятора.

Дополнительные сведения см. в разделе Квантовые цепи.

Необходимые компоненты

Дополнительные сведения об установке см. в разделе Настройка расширения QDK.

Создание новой записной книжки Jupyter Notebook

  1. В VS Code выберите > команд view и нажмите кнопку Create: New Jupyter Notebook.
  2. В правом верхнем углу VS Code обнаружит и отобразит версию виртуальной PythonPython среды, выбранной для записной книжки. Если у вас несколько Python сред, может потребоваться выбрать ядро с помощью средства выбора ядра в правом верхнем углу. Если среда не обнаружена, сведения о настройке см . в записных книжках Jupyter Notebook в VS Code .

Загрузка необходимых объектов импорта

В первой ячейке записной книжки выполните следующий код, чтобы загрузить необходимые импорты:

import azure.quantum
from azure.quantum import Workspace 
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from azure.quantum.qiskit import AzureQuantumProvider

Подключение к службе Azure Quantum

Чтобы подключиться к службе Azure Quantum, вам потребуется идентификатор ресурса и расположение рабочей области Azure Quantum.

  1. Вход в учетную запись Azure, https://portal.azure.com

  2. Выберите рабочую область Azure Quantum и перейдите к обзору.

  3. Скопируйте параметры в полях.

    Снимок экрана: Visual Studio Code, показывающий, как развернуть область обзора рабочей области Quantum.

Добавьте новую ячейку в записную книжку и используйте сведения об учетной записи для создания Workspace и AzureQuantumProvider подключения объектов к рабочей области Azure Quantum.

workspace = Workspace(  
    resource_id = "", # Add the resourceID of your workspace
    location = "" # Add the location of your workspace (for example "westus")
    )

provider = AzureQuantumProvider(workspace)

Вывод списка всех серверных компонентов

Теперь можно распечатать все серверные компоненты квантовых вычислений, доступные в рабочей области.

print("This workspace's targets:")
for backend in provider.backends():
    print("- " + backend.name())
This workspace's targets:
- ionq.qpu
- ionq.qpu.aria-1
- ionq.simulator
- microsoft.estimator
- quantinuum.hqs-lt-s1
- quantinuum.hqs-lt-s1-apival
- quantinuum.hqs-lt-s2
- quantinuum.hqs-lt-s2-apival
- quantinuum.hqs-lt-s1-sim
- quantinuum.hqs-lt-s2-sim
- quantinuum.qpu.h1-1
- quantinuum.sim.h1-1sc
- quantinuum.sim.h1-1e
- rigetti.sim.qvm
- rigetti.qpu.ankaa-9q-3
- rigetti.qpu.ankaa-3

Выполнение простой цепи

Сначала создайте простую цепь Qiskit для выполнения.

# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(3, 3)
circuit.name = "Qiskit Sample - 3-qubit GHZ circuit"
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure([0,1,2], [0, 1, 2])

# Print out the circuit
circuit.draw()
     ┌───┐          ┌─┐      
q_0: ┤ H ├──■───────┤M├──────
     └───┘┌─┴─┐     └╥┘┌─┐   
q_1: ─────┤ X ├──■───╫─┤M├───
          └───┘┌─┴─┐ ║ └╥┘┌─┐
q_2: ──────────┤ X ├─╫──╫─┤M├
               └───┘ ║  ║ └╥┘
c: 3/════════════════╩══╩══╩═
                     0  1  2 

Выберите программу target для запуска

Запуск в симуляторе IonQ

Прежде чем работать на реальном оборудовании, давайте протестируем канал в симуляторе. Используется get_backend для создания Backend объекта для подключения к серверной части симулятора IonQ:

simulator_backend = provider.get_backend("ionq.simulator")

Серверная часть IonQ поддерживает шлюзы из определенного набора шлюзов, которые компилируются для оптимального выполнения на оборудовании. Если канал содержит шлюзы, которые не указаны в этом списке, необходимо транспилировать в поддерживаемую gateset функцию, предоставляемую transpile Qiskit:

from qiskit import transpile
circuit = transpile(circuit, simulator_backend)

Функция транспиля возвращает новый объект канала, в котором шлюзы разложены в шлюзы, поддерживаемые на указанной серверной части.

Теперь можно запустить программу через службу Azure Quantum и получить результат. Следующая ячейка отправляет задание, которое запускает цепь со 100 снимками:

job = simulator_backend.run(circuit, shots=8)
job_id = job.id()
print("Job id", job_id)
Job id 00000000-0000-0000-0000-000000000000

Чтобы дождаться завершения задания и вернуть результаты, выполните:

result = job.result()
print(result)
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=8, success=True, meas_level=2, data=ExperimentResultData(counts={'000': 4, '111': 4}, memory=['000', '000', '000', '000', '111', '111', '111', '111'], probabilities={'000': 0.5, '111': 0.5}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits=3, metadata={}), status=JobStatus.DONE, name='Qiskit Sample - 3-qubit GHZ circuit')], date=None, status=None, header=None, error_data=None)

Так как результатом будет собственный объект пакета Qiskit, можно использовать result.get_counts и plot_histogram Qiskit для визуализации результатов. Чтобы гарантировать представление всех возможных меток в виде последовательности битов, добавьте их в counts.

counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
{'000': 4, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 4}

Результат цепи Qiskit в симуляторе IonQ

Вы также можете использовать функцию get_memory() для отображения отдельных данных снимка из задания.

result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']

Примечание.

При отправке задания с нечетным числом снимков IonQ targetsрезультаты будут округляться до следующего четного числа. Например, если указать 9 снимков, результаты будут отображать данные для 8 выстрелов.

Оценка стоимости задания

Перед выполнением задания на ЦП необходимо оценить, сколько стоит выполнить.

Актуальные сведения о ценах см. в статье Цены на IonQ, или найдите рабочую область и просмотрите параметры ценообразования на вкладке "Поставщик" с помощью команды: aka.ms/aq/myworkspaces.

Выполнение на QPU IonQ

Чтобы подключиться к реальному оборудованию ( QPU ), просто укажите имя target"ionq.qpu.aria-1"get_backend метода:

qpu_backend = provider.get_backend("ionq.qpu.aria-1")

Отправьте канал для запуска в Azure Quantum, получите результаты и запустите plot_histogram , чтобы отобразить результаты.

Примечание.

Время, необходимое для выполнения цепи на QPU, может отличаться в зависимости от времени в текущей очереди.

# Submit the circuit to run on Azure Quantum
job = qpu_backend.run(circuit, shots=100)
job_id = job.id()
print("Job id", job_id)

# Get the job results (this method waits for the Job to complete):
result = job.result()
print(result)
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
Job id 00000000-0000-0000-0000-000000000000
Job Status: job has successfully run
Result(backend_name='ionq.qpu.aria-1', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(counts={'0': 505, '1': 6, '2': 1, '3': 1, '4': 1, '5': 10, '6': 11, '7': 488}, probabilities={'0': 0.4932, '1': 0.0059, '2': 0.001, '3': 0.001, '4': 0.001, '5': 0.0098, '6': 0.0117, '7': 0.4766}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits='3', qiskit='True'))])
{'000': 505, '001': 6, '010': 1, '011': 1, '100': 1, '101': 10, '110': 11, '111': 488}

Результат цепи Qiskit на QPU IonQ

Внимание

Отправка нескольких цепей в одном задании в настоящее время не поддерживается. В качестве обходного решения можно вызвать метод backend.run для асинхронной отправки каждой цепи, а затем получить результаты каждого задания. Например:

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

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

Необходимые компоненты

Создание записной книжки в рабочей области

  1. Войдите на портал Azure и выберите рабочую область, созданную на предыдущем шаге.
  2. В левой колонке выберите Записные книжки.
  3. Щелкните Мои записные книжки и щелкните Добавить новую.
  4. Введите имя файла, например Qiskit.ipynb, и щелкните Создать файл.

При открытии новой записной книжки он автоматически создает код для первой ячейки на основе сведений о подписке и рабочей области.

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

Примечание.

Если не указано иное, следует выполнять ячейки в порядке их создания, чтобы избежать проблем компиляции.

Щелкните треугольный значок воспроизведения слева от ячейки, чтобы выполнить размещенный в ней код.

Загрузка необходимых объектов импорта

Сначала необходимо импортировать несколько дополнительных модулей.

Щелкните + Код, чтобы добавить новую ячейку, а затем добавьте и выполните следующий код:

from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from azure.quantum.qiskit import AzureQuantumProvider

Подключение к службе Azure Quantum

Затем создайте объект с помощью AzureQuantumProvider объекта из предыдущей Workspace ячейки для подключения к рабочей области Azure Quantum. Добавьте новую ячейку со следующим кодом:

provider = AzureQuantumProvider(workspace)

Настройка простой цепи

В новой ячейке создайте объект circuit. В этом примере используется простой квантовый генератор случайных битов. Добавьте следующий код для определения и отображения цепи:

# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(3, 3)
circuit.name = "Qiskit Sample - 3-qubit GHZ circuit"
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure([0, 1, 2], [0, 1, 2])

# Print out the circuit
circuit.draw()
     ┌───┐          ┌─┐      
q_0: ┤ H ├──■───────┤M├──────
     └───┘┌─┴─┐     └╥┘┌─┐   
q_1: ─────┤ X ├──■───╫─┤M├───
          └───┘┌─┴─┐ ║ └╥┘┌─┐
q_2: ──────────┤ X ├─╫──╫─┤M├
               └───┘ ║  ║ └╥┘
c: 3/════════════════╩══╩══╩═
                     0  1  2 

Список всех targets

Теперь вы можете отобразить все квантовые вычисления targetsили серверные серверы, доступные в рабочей области. Добавьте новую ячейку и выполните следующую строку:

print("This workspace's targets:")
for backend in provider.backends():
    print("- " + backend.name())
This workspace's targets:
- ionq.simulator
- ionq.qpu.aria-1
- microsoft.estimator
- quantinuum.qpu.h1-1
- quantinuum.sim.h1-1sc
- quantinuum.sim.h1-1e
- rigetti.sim.qvm
- rigetti.qpu.ankaa-9q-3
- rigetti.qpu.ankaa-3    

Выберите программу target для запуска

Для проверки кода перед запуском на реальном квантовом оборудовании можно применить квантовый симулятор IonQ ionq.simulator.

Добавьте новую ячейку и создайте объект для представления квантового симулятора targetIonQ:

# Get IonQ quantum simulator target:
simulator_backend = provider.get_backend("ionq.simulator")

Запуск в симуляторе IonQ

Чтобы запустить канал на симуляторе, добавьте следующий код. В этом примере используется run метод отправки target задания, а затем отслеживается состояние задания.

# Submit the circuit to run on Azure Quantum
job = simulator_backend.run(circuit, shots=8)
job_id = job.id()
print("Job id", job_id)

После успешного выполнения задания получите результаты задания и отобразите их:

# Get the job results:
result = job.result()
print(result)
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=8, success=True, meas_level=2, data=ExperimentResultData(counts={'000': 4, '111': 4}, memory=['000', '000', '000', '000', '111', '111', '111', '111'], probabilities={'000': 0.5, '111': 0.5}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits=3, metadata={}), status=JobStatus.DONE, name='Qiskit Sample - 3-qubit GHZ circuit')], date=None, status=None, header=None, error_data=None)

Так как типом result будет собственный объект пакета Qiskit, можно использовать result.get_counts и plot_histogram Qiskit для визуализации результатов. Чтобы гарантировать представление всех возможных меток в виде последовательности битов, добавьте их в counts.

counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
{'000': 4, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 4}

Результат цепи Qiskit в симуляторе IonQ

Вы также можете использовать функцию get_memory() для отображения отдельных данных снимка из задания.

result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']

Примечание.

При отправке задания с нечетным числом снимков IonQ targetsрезультаты будут округляться до следующего четного числа. Например, если указать 9 снимков, результаты будут отображать данные для 8 выстрелов.

Оценка стоимости задания

Перед выполнением задания на фактическом квантовом оборудовании или квантовой единице обработки (QPU) необходимо оценить, сколько стоит выполнить.

Актуальные сведения о ценах можно узнать на странице цен IonQ или найдите свою рабочую область и посмотрите в колонке Поставщики для рабочей области.

Выполнение на QPU IonQ

После успешного запуска задания на симуляторе IonQ и оценки стоимости QPU время запуска канала на оборудовании.

Примечание.

Время, необходимое для выполнения цепи на QPU, отличается в зависимости от времени в текущей очереди. Среднее время target очереди можно просмотреть, выбрав колонку "Поставщики " рабочей области.

Используйте тот же метод run и операции, которые вы ранее применяли для проверяющего элемента управления API, чтобы отправить и отобразить задание:

# Submit the circuit to run on Azure Quantum
job = qpu_backend.run(circuit, shots=100)
job_id = job.id()
print("Job id", job_id)

По завершении задания получите результаты задания, как и раньше, и отобразите их на диаграмме:

result = job.result()
print(result)
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
Job id 910b5ac8-98cd-11ec-b3ba-00155d5528cf
Job Status: job has successfully run
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='Job id 54e8c740-98d9-11ec-b382-00155d957f5d', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(counts={'0': 505, '1': 6, '2': 1, '3': 1, '4': 1, '5': 10, '6': 11, '7': 488}, probabilities={'0': 0.4932, '1': 0.0059, '2': 0.001, '3': 0.001, '4': 0.001, '5': 0.0098, '6': 0.0117, '7': 0.4766}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits='3', qiskit='True'))])
{'000': 505, '001': 6, '010': 1, '011': 1, '100': 1, '101': 10, '110': 11, '111': 488}

Результат цепи Qiskit на QPU IonQ

Внимание

Отправка нескольких цепей в одном задании в настоящее время не поддерживается. В качестве обходного решения можно вызвать метод backend.run для асинхронной отправки каждой цепи, а затем получить результаты каждого задания. Например:

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

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

Необходимые компоненты

Дополнительные сведения об установке см. в разделе Настройка расширения QDK.

  • Среда сPythonустановленной Python программой Pip.

  • VS Code с установленным пакетом средств разработки Azure Quantum и Python расширениями.

  • Пакет Azure Quantum qsharpPython с тегами qiskit и widget тегами.

    python pip install "qsharp[qiskit,widgets]>=1.9" 
    

    Внимание

    Убедитесь, что у вас установлена последняя версия Qiskit. Дополнительные сведения см. в статье Python Azure-Quantum.

Запуск базового канала

В VS Code откройте новый Python файл для определения и запуска базового канала с помощью встроенного разреженного симулятора в пакете Qsharp.

# load the required imports 
from qiskit.circuit.random import random_circuit
from qsharp.interop.qiskit import QSharpBackend

# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)

# run the circuit using the built-in sparse simulator
backend = QSharpBackend()
job = backend.run(circuit)
counts = job.result().get_counts()

print(counts)

Чтобы запустить программу, щелкните значок "Выполнить" в правом верхнем углу и выберите "Выполнить Python файл". Выходные данные отображаются в новом окне терминала.

                  ┌─────────────────────────┐┌─┐
q_0: ─■───────────┤0                        ├┤M├───
      │P(0.79983) │  (XX-YY)(1.9337,1.7385) │└╥┘┌─┐
q_1: ─■───────────┤1                        ├─╫─┤M├
                  └─────────────────────────┘ ║ └╥┘
c: 2/═════════════════════════════════════════╩══╩═
                                              0  1
{'11': 680, '00': 344}

Создать QIR для цепи

С помощью этого же канала можно создать QIR, который используется для запуска на квантовом оборудовании.

Примечание.

При создании QIR все регистры должны быть измерены. Если есть неиспользуемые регистры, возникает ошибка. Кроме того, при попытке создать QIR, если для профиля задано значение Unrestricted возникает ошибка. Профиль Unrestricted действителен только для моделирования. Необходимо использовать targetProfile.Base или TargetProfile.Adaptive_RI. target_profile можно переопределить в вызове backend.qir(...) для переключения профилей.

  1. Импорт QSharpError и TargetProfile

    from qsharp import QSharpError, TargetProfile
    
  2. Изменение выходных данных для создания QIR

        print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
    

Теперь код должен выглядеть следующим образом:

# load the required imports 
from qiskit.circuit.random import random_circuit
from qsharp.interop.qiskit import QSharpBackend
from qsharp import QSharpError, TargetProfile

# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)

# generate QIR for the circuit
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))

с выходными данными:

     ┌────────────┐             ┌─┐   
q_0: ┤ Rx(2.7195) ├─■───────────┤M├───
     └──┬─────┬───┘ │U1(5.5924) └╥┘┌─┐
q_1: ───┤ Tdg ├─────■────────────╫─┤M├
        └─────┘                  ║ └╥┘
c: 2/════════════════════════════╩══╩═
                                 0  1
%Result = type opaque
%Qubit = type opaque

define void @ENTRYPOINT__main() #0 {
block_0:
  call void @__quantum__qis__rx__body(double 2.7194945105768586, %Qubit* inttoptr (i64 0 to %Qubit*))
  call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 0 to %Qubit*))
  call void @__quantum__qis__t__adj(%Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__rz__body(double -2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
  call void @__quantum__rt__array_record_output(i64 2, i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
  ret void
}

declare void @__quantum__qis__rx__body(double, %Qubit*)

declare void @__quantum__qis__rz__body(double, %Qubit*)

declare void @__quantum__qis__t__adj(%Qubit*)

declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)

declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1

declare void @__quantum__rt__array_record_output(i64, i8*)

declare void @__quantum__rt__result_record_output(%Result*, i8*)

attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
attributes #1 = { "irreversible" }

; module flags

!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}

!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}
!4 = !{i32 1, !"classical_ints", i1 true}
!5 = !{i32 1, !"qubit_resetting", i1 true}
!6 = !{i32 1, !"classical_floats", i1 false}
!7 = !{i32 1, !"backwards_branching", i1 false}
!8 = !{i32 1, !"classical_fixed_points", i1 false}
!9 = !{i32 1, !"user_functions", i1 false}
!10 = !{i32 1, !"multiple_target_branching", i1 false}

Не все программы могут выполняться на всех оборудованиях. Здесь можно попытаться target профиль Base, но мы получим подробные ошибки о том, какие части программы не поддерживаются.

try:
    backend.qir(qc, target_profile=TargetProfile.Base)
except QSharpError as e:
    print(e)

Следующие шаги