Зміни функцій у Qiskit 1.0
Цей посібник описує шляхи міграції для найважливіших змін функцій у Qiskit 1.0, організованих за модулями. Використовуй зміст праворуч для переходу до потрібного мод уля.
Інструмент міграції Qiskit 1.0
Щоб спростити процес міграції, можна скористатись інструментом
flake8-qiskit-migration
для виявлення видалених шляхів імпорту у твоєму коді та отримання альтернатив.
- Run with pipx
- Run with venv
Якщо у тебе встановлено pipx, просто виконай
таку команду.
pipx run flake8-qiskit-migration <path-to-source-directory>
Це встановить пакет у тимчасове віртуальне середовище та запустить його на твоєму коді.
Якщо ти не хочеш використовувати pipx, можна вручну створити нове
середовище для інструмента. Цей підхід також дозволяє використовувати
nbqa для перевірки прикладів коду в
Jupyter-ноутбуках. Видали середовище після завершення.
# Make new environment and install
python -m venv .flake8-qiskit-migration-venv
source .flake8-qiskit-migration-venv/bin/activate
pip install flake8-qiskit-migration
# Run plugin on Python code
flake8 --select QKT100 <path-to-source-directory> # e.g. `src/`
# (Optional) run plugin on notebooks
pip install nbqa
nbqa flake8 ./**/*.ipynb --select QKT100
# Deactivate and delete environment
deactivate
rm -r .flake8-qiskit-migration-venv
Цей інструмент виявляє лише видалені шляхи імпорту. Він не виявляє використання видалених
методів (наприклад, QuantumCircuit.qasm) або аргументів. Він також не відстежує
присвоєння на кшталт qk = qiskit, хоча може обробляти псевдоніми, наприклад
import qiskit as qk.
Докладніше дивись у репозиторії проекту.
Глобальні екземпляри та функції
Aer
Об'єкт qiskit.Aer недоступний у Qiskit 1.0. Натомість використовуй
той самий об'єкт з простору імен qiskit_aer, який є взаємозамінним замінником.
Щоб встановити qiskit_aer, виконай:
pip install qiskit-aer
BasicAer
Об'єкт qiskit.BasicAer недоступний у Qiskit 1.0. Дивись
розділ міграції basicaer для
варіантів міграції.
execute
Функція qiskit.execute недоступна у Qiskit 1.0. Ця
функція слугувала високорівневою обгорткою навколо функцій
transpile та
run у Qiskit.
Замість qiskit.execute використовуй функцію
transpile, а після неї —
backend.run().
# Legacy path
from qiskit import execute
job = execute(circuit, backend)
# New path
from qiskit import transpile
new_circuit = transpile(circuit, backend)
job = backend.run(new_circuit)
Альтернативно, примітив Sampler
є семантично еквівалентним видаленій функції qiskit.execute.
Клас
BackendSampler є
загальною оберткою для бекендів, які не підтримують примітиви:
from qiskit.primitives import BackendSampler
sampler = BackendSampler(backend)
job = sampler.run(circuit)
qiskit.circuit
QuantumCircuit.qasm
Метод QuantumCircuit.qasm було видалено. Натомість використовуй
qasm2.dump або
qasm2.dumps.
Для виводу з форматуванням Pygments використовуй самостійний пакет
openqasm-pygments,
оскільки qasm2.dump та qasm2.dumps не надають кольоровий вивід Pygments.
from qiskit import QuantumCircuit
qc = QuantumCircuit(1)
# Old
qasm_str = qc.qasm()
# Alternative
from qiskit.qasm2 import dumps
qasm_str = dumps(qc)
# Alternative: Write to file
from qiskit.qasm2 import dump
with open("my_file.qasm", "w") as f:
dump(qc, f)
Вентилі QuantumCircuit
Наступні методи вентилів було видалено на користь більш усталених методів, що додають ті самі вентилі:
| Видалено | Альтернатива |
|---|---|
QuantumCircuit.cnot | QuantumCircuit.cx |
QuantumCircuit.toffoli | QuantumCircuit.ccx |
QuantumCircuit.fredkin | QuantumCircuit.cswap |
QuantumCircuit.mct | QuantumCircuit.mcx |
QuantumCircuit.i | QuantumCircuit.id |
QuantumCircuit.squ | QuantumCircuit.unitary |
Наступні методи схеми було видалено. Натомість ці вентилі можна
додати до схеми за допомогою QuantumCircuit.append.
| Видалено | Альтернатива (append) |
|---|---|
QuantumCircuit.diagonal | DiagonalGate |
QuantumCircuit.hamiltonian | HamiltonianGate |
QuantumCircuit.isometry | Isometry |
QuantumCircuit.iso | Isometry |
QuantumCircuit.uc | UCGate |
QuantumCircuit.ucrx | UCRXGate |
QuantumCircuit.ucry | UCRYGate |
QuantumCircuit.ucrz | UCRZGate |
Наприклад, для DiagonalGate:
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import DiagonalGate # new location in the circuit library
circuit = QuantumCircuit(2)
circuit.h([0, 1]) # some initial state
gate = DiagonalGate([1, -1, -1, 1])
qubits = [0, 1] # qubit indices on which to apply the gate
circuit.append(gate, qubits) # apply the gate
Також були видалені такі методи QuantumCircuit:
| Видалено | Альтернатива |
|---|---|
QuantumCircuit.bind_parameters | QuantumCircuit.assign_parameters |
QuantumCircuit.snapshot | інструкції збереження від qiskit-aer |
qiskit.converters
Функцію qiskit.converters.ast_to_dag було видалено з Qiskit. Вона перетворювала
абстрактне синтаксичне дерево, згенероване застарілим парсером OpenQASM 2, на
DAGCircuit. Оскільки застарілий
парсер OpenQASM 2 теж видалено (дивись qiskit.qasm), ця
функція більше не потрібна. Натомість парсуй файли OpenQASM 2 у
QuantumCircuit за допомогою конструкторних методів
QuantumCircuit.from_qasm_file
або
QuantumCircuit.from_qasm_str
(або модуля qiskit.qasm2), а потім
перетворюй QuantumCircuit на
DAGCircuit за допомогою
circuit_to_dag.
# Previous
from qiskit.converters import ast_to_dag
from qiskit.qasm import Qasm
dag = ast_to_dag(Qasm(filename="myfile.qasm").parse())
# Current alternative
import qiskit.qasm2
from qiskit.converters import circuit_to_dag
dag = circuit_to_dag(qiskit.qasm2.load("myfile.qasm"))
qiskit.extensions
Модуль qiskit.extensions більше недоступний. Більшість його об'єктів було
інтегровано до бібліотеки схем
(qiskit.circuit.library). Щоб перейти на
новий шлях, просто заміни qiskit.extensions на qiskit.circuit.library
у шляху імпорту об'єкта. Це взаємозамінний замінник.
# Previous
from qiskit.extensions import DiagonalGate
# Current alternative
from qiskit.circuit.library import DiagonalGate
Класи, переміщені до qiskit.circuit.library:
DiagonalGateHamiltonianGateInitializeIsometryqiskit.circuit.library.generalized_gates.mcg_up_diag.MCGupDiagUCGateUCPauliRotGateUCRXGateUCRYGateUCRZGateUnitaryGate
Наступні класи було повністю видалено з кодової бази, оскільки їхні
функції були або надлишковими, або пов'язаними з модулем extensions:
| Видалено | Альтернатива |
|---|---|
SingleQubitUnitary | qiskit.circuit.library.UnitaryGate |
Snapshot | Використовуй інструкції збереження від qiskit-aer |
ExtensionError | Відповідний клас помилки |
qiskit.primitives
Найважливіша зміна в модулі qiskit.primitives —
введення нового інтерфейсу примітивів V2. У цьому розділі показано, як перенести свій
робочий процес з примітивів V1 на примітиви V2, а також кілька змін у вхідних даних,
прийнятих інтерфейсом V1.
Починаючи з релізу 1.0, ми будемо називати інтерфейс примітивів до версії 1.0 «примітивами V1».
Міграція з V1 на V2
Формальна відмінність між API примітивів V1 та V2 полягає у базових класах, від яких
успадковуються реалізації примітивів. Щоб перейти на нові базові класи, можна
зберегти початковий шлях імпорту з qiskit.primitives:
| Мігрувати з | Замінити на |
|---|---|
BaseEstimator | BaseEstimatorV2 |
BaseSampler | BaseSamplerV2 |
Назви реалізацій примітивів V2 у ядрі Qiskit (тих, що імпортуються з qiskit.primitives),
були змінені, щоб прояснити їхнє призначення як реалізацій, що можуть запускатись локально
на бекенді-симуляторі statevector. Нові назви не містять суфікса -V2.
| Мігрувати з | Замінити на |
|---|---|
qiskit.primitives.Estimator | qiskit.primitives.StatevectorEstimator |
qiskit.primitives.Sampler | qiskit.primitives.StatevectorSampler |
Є деякі концептуальні відмінності, які варто врахувати при міграції з V1 на V2.
Ці відмінності визначаються базовим класом, але показані в наступних прикладах
з використання м реалізацій statevector, знайдених у qiskit.primitives:
Для наступних прикладів передбачається такий імпорт та ініціалізація примітивів:
from qiskit.primitives import (
Sampler,
StatevectorSampler,
Estimator,
StatevectorEstimator,
)
estimator_v1 = Estimator()
sampler_v1 = Sampler()
estimator_v2 = StatevectorEstimator()
sampler_v2 = StatevectorSampler()
# define circuits, observables and parameter values
Sampler та Estimator: Нові примітиви V2 розроблені для прийому векторизованих вхідних даних, де окремі схеми можуть групуватися зі специфікаціями у вигляді масивів. Тобто одна схема може виконуватись для масивів зnнаборів параметрів,nспостережуваних, або обох одночасно (для estimator). Кожна група називається примітивним уніфікованим блоком (pub) і може бути представлена як кортеж:(1 x схема, [n x спостережуваних], [n x параметрів]). Інтерфейс V1 не мав такої гнучкості. Натомість кількість вхідних схем мала відповідати кількості спостережуваних і наборів параметрів, як показано в наступних прикладах (вибери вкладку, щоб переглянути кожен приклад):
- Estimator, 1 circuit, 4 observables
- Sampler, 1 circuit, 3 parameter sets
- Estimator, 1 circuit, 4 observables, 2 parameter sets
# executing 1 circuit with 4 observables using Estimator V1
job = estimator_v1.run([circuit] * 4, [obs1, obs2, obs3, obs4])
evs = job.result().values
# executing 1 circuit with 4 observables using Estimator V2
job = estimator_v2.run([(circuit, [obs1, obs2, obs3, obs4])])
evs = job.result()[0].data.evs
# executing 1 circuit with 3 parameter sets using Sampler V1
job = sampler_v1.run([circuit] * 3, [vals1, vals2, vals3])
dists = job.result().quasi_dists
# executing 1 circuit with 3 parameter sets using Sampler V2
job = sampler_v2.run([(circuit, [vals1, vals2, vals3])])
counts = job.result()[0].data.meas.get_counts()
# executing 1 circuit with 4 observables and 2 parameter sets using Estimator V1
job = estimator_v1.run([circuit] * 8, [obs1, obs2, obs3, obs4] * 2, [vals1, vals2] * 4)
evs = job.result().values
# executing 1 circuit with 4 observables and 2 parameter sets using Estimator V2
job = estimator_v2.run([(circuit, [[obs1, obs2, obs3, obs4]], [[vals1], [vals2]])])
evs = job.result()[0].data.evs
Примітиви V2 приймають кілька PUB як вхідні дані, і кожен pub отримує власний результат. Це дозволяє запускати різні схеми з різними комбінаціями параметрів/спостережуваних, що не завжди було можливим в інтерфейсі V1:
- Sampler, 2 circuits, 1 parameter set
- Estimator, 2 circuits, 2 different observables
# executing 2 circuits with 1 parameter set using Sampler V1
job = sampler_v1.run([circuit1, circuit2], [vals1] * 2)
dists = job.result().quasi_dists
# executing 2 circuits with 1 parameter set using Sampler V2
job = sampler_v2.run([(circuit1, vals1), (circuit2, vals1)])
counts1 = job.result()[0].data.meas.get_counts() # result for pub 1 (circuit 1)
counts2 = job.result()[1].data.meas.get_counts() # result for pub 2 (circuit 2)
# executing 2 circuits with 2 different observables using Estimator V1
job = estimator_v1.run([circuit1, circuit2] , [obs1, obs2])
evs = job.result().values
# executing 2 circuits with 2 different observables using Estimator V2
job = estimator_v2.run([(circuit1, obs1), (circuit2, obs2)])
evs1 = job.result()[0].data.evs # result for pub 1 (circuit 1)
evs2 = job.result()[1].data.evs # result for pub 2 (circuit 2)
-
Sampler: Sampler V2 тепер повертає результати вимірювань у вигляді бітрядків або підрахунків, замість квазіймовірнісних розподілів з інтерфейсу V1. Бітрядки показують результати вимірювань, зберігаючи порядок шотів, в якому вони вимірювались. Об'єкти результатів Sampler V2 організовують дані за назвами класичних регістрів вхідних схем для сумісності з динамічними схемами.
# Define quantum circuit with 2 qubits
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
circuit.draw()┌───┐ ░ ┌─┐
q_0: ┤ H ├──■───░─┤M├───
└───┘┌─┴─┐ ░ └╥┘┌─┐
q_1: ─────┤ X ├─░──╫─┤M├
└───┘ ░ ║ └╥┘
meas: 2/══════════════╩══╩═
0 1Назва класичного регістру за замовчуваннямУ схемі вище зверни увагу, що ім'я класичного регістру за замовчуванням —
"meas". Це ім'я використовуватиметься далі для доступу до бітрядків вимірювань.# Run using V1 sampler
result = sampler_v1.run(circuit).result()
quasi_dist = result.quasi_dists[0]
print(f"The quasi-probability distribution is: {quasi_dist}")The quasi-probability distribution is: {0: 0.5, 3: 0.5}# Run using V2 sampler
result = sampler_v2.run([circuit]).result()
# Access result data for pub 0
data_pub = result[0].data
# Access bitstrings for the classical register "meas"
bitstrings = data_pub.meas.get_bitstrings()
print(f"The number of bitstrings is: {len(bitstrings)}")
# Get counts for the classical register "meas"
counts = data_pub.meas.get_counts()
print(f"The counts are: {counts}")The number of bitstrings is: 1024
The counts are: {'00': 523, '11': 501} -
Sampler та Estimator: Витрати на вибірку, які зазвичай задавались через опцію запускуshotsу реалізаціях V1, тепер є аргументом методуrun()примітивів, який можна вказати на рівні PUB. Базові класи V2 надають аргументи у форматах, відмінних від API V1:-
BaseSamplerV2.runнадає аргументshots(подібно до попереднього робочого процесу):# Sample two circuits at 128 shots each.
sampler_v2.run([circuit1, circuit2], shots=128)
# Sample two circuits at different amounts of shots. The "None"s are necessary
# as placeholders
# for the lack of parameter values in this example.
sampler_v2.run([(circuit1, None, 123), (circuit2, None, 456)]) -
EstimatorV2.runвводить аргументprecision, який задає планки похибок, яких реалізація примітива має досягти для оцінок очікуваних значень:# Estimate expectation values for two PUBs, both with 0.05 precision.
estimator_v2.run([(circuit1, obs_array1), (circuit2, obs_array_2)], precision=0.05)
-