Перейти до основного вмісту
Цей проєкт у бета-версії. Знайшов(-ла) помилку? Відкрити issue на GitHub. Є запитання чи ідея? Запитати в Discussions — будемо раді твоєму відгуку!
Яка якість перекладу на цій сторінці?

Відкладене розв'язання часових параметрів за допомогою stretch

Специфікація мови OpenQASM 3 містить тип stretch, за допомогою якого можна вказувати відносний час операцій замість абсолютного. Підтримку stretch як тривалості для інструкцій Delay було додано у Qiskit v2.0.0. Конкретне значення тривалості stretch розв'язується під час компіляції, після того як стають відомі точні тривалості відкаліброваних вентилів. Компілятор намагається мінімізувати тривалість stretch з урахуванням часових обмежень на одному або кількох кубітах. Це дозволяє виражати такі конструкції вентилів, як рівномірне розташування вентилів (наприклад, для реалізації послідовності ехо-розв'язки вищого порядку), вирівнювання послідовності вентилів по лівому краю або застосування вентиля протягом тривалості певної підсхеми — без знання точного часу.

Приклади​

Динамічна розв'язка​

Поширеним варіантом використання stretch є застосування динамічної розв'язки до простоюючого кубіта, поки інший кубіт виконує умовні операції.

Наприклад, за допомогою stretch можна застосувати послідовність динамічної розв'язки XX до кубіта 1 протягом умовного блоку, що застосовується до кубіта 0, як показано на такій діаграмі:

Image illustrating the following circuit

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

from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.classical import expr

qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits

# Add barriers to define the boundaries
circuit.barrier()
circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)) as else_:
circuit.h(q0)
with else_:
circuit.x(q0)

# Apply an XX DD sequence with stretch on qubit 1
s = circuit.add_stretch("s")
circuit.delay(s, q1)
circuit.x(q1)
circuit.delay(expr.mul(s, 2), q1)
circuit.x(q1)
circuit.delay(s, q1)
circuit.barrier()

Вирівнювання під час планування​

У цьому прикладі stretch використовується для забезпечення вирівнювання послідовності вентилів між двома бар'єрами по лівому краю, незалежно від їхньої фактичної тривалості:

from qiskit import QuantumCircuit
from numpy import pi

qc = QuantumCircuit(5)
qc.barrier()
qc.cx(0, 1)
qc.u(pi/4, 0, pi/2, 2)
qc.cx(3, 4)

a = qc.add_stretch("a")
b = qc.add_stretch("b")
c = qc.add_stretch("c")

# Use the stretches as Delay duration.
qc.delay(a, [0, 1])
qc.delay(b, 2)
qc.delay(c, [3, 4])
qc.barrier()
примітка

При використанні stretch з IBM Quantum Compute Service будь-який залишок від розв'язання stretch додається до першої затримки, що використовує цей stretch.

Example:

a = circuit.add_stretch("a")
circuit.barrier(q0, q1)
circuit.delay(100, q0)
circuit.delay(a, q1) # resolve to 26
circuit.x(q1) # duration: 8
circuit.delay(a, q1) # resolve to 25
circuit.x(q1) # duration: 8
circuit.delay(a, q1) # resolve to 25
circuit.x(q1) # duration: 8
circuit.barrier(q0, q1)

Наведений вище код розв'язується до значення 25 із залишком 1. До першої затримки [a] буде додано залишок.

Рівняння розв'язання stretch: a+8+a+8+a+8=100=3∗a+24a + 8 + a + 8 + a + 8 = 100 = 3*a + 24

Перегляд значень stretch у IBM Quantum Compute Service​

Фактичне значення тривалості stretch розв'язується під час компіляції після планування схеми. При запуску завдання Sampler у IBM Quantum Compute Service ти можеш переглядати розв'язані значення stretch у метаданих результату завдання. Підтримка stretch у Quantum Compute наразі є експериментальною, тому спочатку потрібно встановити експериментальний параметр для увімкнення його отримання, а потім звернутися до даних безпосередньо з метаданих таким чином:

# Enable stretch value retrieval.
sampler.options.experimental = {
"execution": {
"stretch_values": True,
"scheduler_timing": True,
},
}

# Access the stretch values from the metadata.
job_result = job.result()
circuit_stretch_values = (
job_result[0].metadata["compilation"]["stretch_values"]
)

# Visualize the timing.
# Use the sliders at the bottom, the controls at the top, and the
# legend on the side of the output to customize the view.
draw_circuit_schedule_timing(ob.result()[0].metadata['compilation']
['scheduler_timing']['timing'])
примітка

Хоча загальний час схеми повертається в метаданих "compilation", це НЕ час, що використовується для тарифікації (час QPU).

Розуміння виводу метаданих​

Метадані stretch_values повертають таку інформацію:

  • Name (Ім'я): Назва застосованого stretch.

  • Value (Значення): Запитуване цільове значення.

  • Remainder (Залишок): Залишок від розв'язання stretch, що додається до першої затримки, яка використовує цей stretch.

  • Expanded values (Розгорнуті значення): Набори значень, що вказують початок stretch та його тривалість.

Приклад​

# Define the circuit
circuit = QuantumCircuit(4)
foo = circuit.add_stretch("foo")
bar = circuit.add_stretch("bar")
circuit.barrier()
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.cz(0, 1)

circuit.delay(foo, 2)
circuit.x(2)
# 3*foo
circuit.delay(expr.mul(3, foo), 2)
circuit.x(2)
# 2*foo
circuit.delay(expr.mul(2, foo), 2)

circuit.delay(bar, 3)
circuit.x(3)
circuit.delay(bar, 3)

circuit.measure_all()

Вивід метаданих​

[{'name': 'bar',
'value': 29,
'remainder': 1,
'expanded_values': [[1365, 30], [1404, 29]]},
{'name': 'foo',
'value': 8,
'remainder': 2,
'expanded_values': [[1365, 10], [1384, 24], [1417, 16]]}
]

Значення, що повертаються для тривалості, залежать від цільового значення та обчисленого залишку. Наприклад, ось тривалості, що повертаються для foo:

  • foo value + remainder (8+2 = 10)

  • foo value * 3 (8 x 3 = 24)

  • foo value * 2 (8 x 2 = 16)

Для розуміння та перевірки часових параметрів можна використати візуалізацію.

draw_circuit_schedule_timing(job.result()[0].metadata
['compilation']['scheduler_timing']['timing'])

На наступному зображенні, що базується на прикладному виводі, foo відповідає stretch на кубіті 2. Перша затримка stretch, що використовує foo, починається наприкінці init_play (1365). Тривалість stretch становить 10, тому ця затримка закінчується, коли починається вентиль x (1365+10=1375). Аналогічно можна інтерпретувати другий і третій stretch.

The output from the draw_circuit_schedule_timing command is shown.

Використовуй повзунки внизу, елементи керування вгорі (наведи курсор на зображення виводу, щоб їх відобразити) та легенду збоку від виводу для налаштування вигляду. Наведи курсор на зображення, щоб переглянути точні дані.

Для отримання повної інформації дивись тему Візуалізація часових параметрів схеми.

Обмеження Quantum Compute​

Підтримка stretch у Quantum Compute наразі є експериментальною і має такі обмеження:

  • Не більше однієї змінної stretch на набір кубітів між бар'єрами (неявними та явними). Набір кубітів — це один або кілька кубітів; ці набори мають бути взаємовиключними.

    a = circuit.add_stretch("a")
    b = circuit.add_stretch("b")
    circuit.delay(a, (q0, q1))
    circuit.delay(b, q0) # Invalid because 2 stretches are applied on q0
  • Область, оточена набором бар'єрів, називається бар'єрним регіоном. Змінна stretch не може використовуватися в кількох бар'єрних регіонах.

    # Stretch a is used in two barrier regions
    a = circuit.add_stretch("a")
    circuit.barrier((q0, q1))
    circuit.delay(a, q0)
    circuit.barrier((q0, q1))
    circuit.delay(a, q0)
    circuit.barrier((q0, q1))

    Illustration of the previous code output

  • Вирази stretch обмежені формою X*stretch + Y, де X та Y є константами з плаваючою точкою або цілими числами.

    a = circuit.add_stretch("a")
    b = circuit.add_stretch("b")
    c = circuit.add_stretch("c")

    # (a / b) * c is not supported
    circuit.delay(expr.mul(expr.div(a, b), c), q1)
  • Вирази stretch можуть містити лише одну змінну stretch.

    a = circuit.add_stretch("a")
    b = circuit.add_stretch("b")
    circuit.delay(expr.add(a, b), 0)
  • Вирази stretch не можуть розв'язуватися до від'ємних значень затримки. Поточний розв'язувач не виводить обмеження невід'ємності автоматично.

    from qiskit.circuit import Duration

    circuit.barrier((q0, q1))
    circuit.delay(20, q1)
    # The length of this barrier region is 20dt, meaning the
    # equation for solving stretch 'a' is a + 40dt = 20dt, giving a = -20dt.
    circuit.delay(expr.add(a, Duration.dt(40)), q0)
    circuit.barrier((q0, q1))