تغييرات ميزات Qiskit v1.0
يصف هذا الدليل مسارات الترحيل لأهم تغييرات الميزات في Qiskit v1.0، مرتبةً حسب الوحدة البرمجية (module). استخدم جدول المحتويات على الجانب الأيمن للتنقل إلى الوحدة التي تريدها.
أداة ترحيل Qiskit v1.0
لتسهيل عملية الترحيل، يمكنك استخدام أداة
flake8-qiskit-migration
للكشف عن مسارات الاستيراد المحذوفة في كودك واقتراح بدائل لها.
- التشغيل باستخدام pipx
- التشغيل باستخدام 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 v1.0. استخدم بدلاً منه
نفس الكائن من مساحة الاسم qiskit_aer، وهو بديل متوافق تماماً.
لتثبيت qiskit_aer، شغّل:
pip install qiskit-aer
BasicAer
كائن qiskit.BasicAer غير متاح في Qiskit v1.0. اطلع على
قسم ترحيل basicaer للاطلاع على
خيارات الترحيل المتاحة.
execute
دالة qiskit.execute غير متاحة في Qiskit v1.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 هو
غلاف عام للـ backends التي لا تدعم البدائيات (primitives):
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. كانت تحوّل
شجرة الصياغة المجردة (abstract syntax tree) التي ينتجها محلل 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 هو إطلاق واجهة primitives V2 الجديدة. يوضح هذا القسم كيفية الانتقال من primitives V1 إلى primitives V2، إلى جانب التغييرات الطفيفة التي طرأت على المدخلات التي تقبلها واجهة V1.
ابتداءً من إصدار v1.0، سنشير إلى واجهة primitives السابقة للإصدار 1.0 بـ "primitives V1".
الانتقال من V1 إلى V2
الفارق الجوهري بين واجهتَي primitives V1 وV2 هو الفئات الأساسية التي ترث منها تطبيقات primitives. للانتقال إلى الفئات الأساسية الجديدة، يمكنك الإبقاء على مسار الاستيراد الأصلي من qiskit.primitives:
| الانتقال من | الاستبدال بـ |
|---|---|
BaseEstimator | BaseEstimatorV2 |
BaseSampler | BaseSamplerV2 |
تم تعديل أسماء تطبيقات Qiskit الأساسية لـ V2 primitives (تلك التي يمكن استيرادها من qiskit.primitives)، وذلك لتوضيح غرضها كتطبيقات قابلة للتشغيل محلياً باستخدام محاكي statevector. الأسماء الجديدة لا تتضمن اللاحقة -V2.
| الانتقال من | الاستبدال بـ |
|---|---|
qiskit.primitives.Estimator | qiskit.primitives.StatevectorEstimator |
qiskit.primitives.Sampler | qiskit.primitives.StatevectorSampler |
ثمة فروق مفاهيمية ينبغي مراعاتها عند الانتقال من V1 إلى V2.
تفرضها الفئة الأساسية، وتوضحها الأمثلة التالية باستخدام تطبيقات statevector الموجودة في qiskit.primitives:
في الأمثلة التالية، افترض الاستيرادات وتهيئات primitive التالية:
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 and Estimator: صُمِّمت primitives V2 الجديدة لقبول مدخلات متجهية (vectorized inputs)، حيث يمكن تجميع دائرة واحدة مع مواصفات ذات قيم مصفوفية. بمعنى أنه يمكن تنفيذ دائرة واحدة على مصفوفات منnمجموعة معاملات أوnمؤثراً (observable)، أو كليهما معاً (في حالة المُقدِّر Estimator). يُسمى كل تجمع primitive unified bloc (PUB)، ويمكن تمثيله كصف (tuple):(1 x circuit, [n x observables], [n x parameters]). لم تتح واجهة V1 هذه المرونة؛ إذ كان لا بد أن يتطابق عدد دوائر الإدخال مع عدد المؤثرات ومجموعات المعاملات، كما توضح الأمثلة التالية (اختر تبويباً لرؤية كل مثال):
- Estimator، دائرة واحدة، 4 مؤثرات
- Sampler، دائرة واحدة، 3 مجموعات معاملات
- Estimator، دائرة واحدة، 4 مؤثرات، مجموعتا معاملات
# 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
تقبل primitives V2 عدة PUBs كمدخلات، ولكل PUB نتيجته الخاصة. يتيح ذلك تشغيل دوائر مختلفة بتركيبات متنوعة من المعاملات والمؤثرات، وهو ما لم يكن ممكناً دائماً في واجهة V1:
- Sampler، دائرتان، مجموعة معاملات واحدة
- Estimator، دائرتان، مؤثران مختلفان
# 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 الآن نتائج قياسات على شكل سلاسل بتية (bitstrings) أو عدادات (counts)، بدلاً من التوزيعات الشبه-احتمالية (quasi-probability distributions) التي كانت تُنتجها واجهة V1. تعرض سلاسل البتات نتائج القياسات مع الحفاظ على ترتيب القياسات (shot order). تُنظِّم كائنات نتائج 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 and Estimator: التكلفة الحسابية الناجمة عن أخذ العينات (shots)، التي كانت تُحدَّد في تطبيق ات V1 عبر خيار التشغيلshots، أصبحت الآن وسيطةً (argument) في دالةrun()الخاصة بـ primitives، يمكن تحديدها على مستوى PUB بشكل مستقل. تعرض الفئتان الأساسيتان V2 هذه الوسيطات بصيغة تختلف عن واجهة 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التي تحدد هامش الخطأ الذي ينبغي أن يستهدفه تطبيق primitive في تقدير قيم التوقع:# Estimate expectation values for two PUBs, both with 0.05 precision.
estimator_v2.run([(circuit1, obs_array1), (circuit2, obs_array_2)], precision=0.05)
-
تحديثات واجهة V1
-
لم يعد مسموحاً بالتحويل الضمني من
BaseOperatorكثيف إلىSparsePauliOpفي وسيطات المؤثرات الخاصة بـEstimator. ينبغي التحويل الصريح إلىSparsePauliOpباستخدامSparsePauliOp.from_operator(operator)بدلاً من ذلك. -
لم يعد مسموحاً باستخدام
PauliListفي وسيطات المؤثرات الخاصة بـ Estimator. ينبغي التحويل الصريح للوسيطة باستخدامSparsePauliOp(pauli_list)أولاً.
qiskit.providers
basicaer
استُبدل معظم ما في وحدة qiskit.providers.basicaer بالوحدة الجديدة
qiskit.providers.basic_provider،
باستثناء فئتَي UnitarySimulatorPy وStatevectorSimulatorPy
اللتين أُزيلتا تماماً؛ إذ كانت وظيفتهما متاحة مسبقاً في
وحدة quantum_info.
الانتقال إلى المسارات الجديدة أمر بسيط. يمكنك استبدال معظم فئات
qiskit.providers.basicaer بما يقابلها في
qiskit.providers.basic_provider
(استبدال مباشر). لاحظ أن الفئات التالية لها مسارات وأسماء جديدة:
| المُزال | البديل |
|---|---|
qiskit.providers.basicaer | qiskit.providers.basic_provider |
BasicAerProvider | BasicProvider |
BasicAerJob | BasicProviderJob |
QasmSimulatorPy | BasicSimulator |
انتبه إلى أي نسخ عامة عند الانتقال إلى الوحدة الجديدة. لا يوجد بديل للنسخة العامة BasicAer التي كان يمكن استيرادها مباشرةً كـ qiskit.BasicAer. هذا يعني أن from qiskit import BasicProvider لم تعد صيغة استيراد صحيحة.
بدلاً من ذلك، يجب استيراد فئة provider من وحدتها الفرعية وإنشاء نسخة منها يدوياً:
# Previous
from qiskit import BasicAer
backend = BasicAer.get_backend("backend_name")
# Current
from qiskit.providers.basic_provider import BasicProvider
backend = BasicProvider().get_backend("backend_name")
يمكن استبدال محاكيَي المصفوفة الأحادية (unitary) وـstatevector بفئات مختلفة من
quantum_info. هذا ليس استبدالاً مباشراً، لكن التغييرات بسيطة. انظر أمثلة الانتقال التالية:
| المُزال | البديل |
|---|---|
UnitarySimulatorPy | quantum_info.Operator |
StatevectorSimulatorPy | quantum_info.Statevector |
توضح الأمثلة التالية مسارات الانتقال لمحاكيات basicaer.
- محاكي Statevector
- محاكي Unitary
- محاكي QASM
from qiskit import QuantumCircuit
qc = QuantumCircuit(3)
qc.h(0)
qc.h(1)
qc.cx(1, 2)
qc.measure_all()
# Previous
from qiskit import BasicAer
backend = BasicAer.get_backend("statevector_simulator")
statevector = backend.run(qc).result().get_statevector()
# Current
qc.remove_final_measurements() # no measurements allowed
from qiskit.quantum_info import Statevector
statevector = Statevector(qc)
from qiskit import QuantumCircuit
qc = QuantumCircuit(3)
qc.h(0)
qc.h(1)
qc.cx(1, 2)
qc.measure_all()
# Previous
from qiskit import BasicAer
backend = BasicAer.get_backend("unitary_simulator")
result = backend.run(qc).result()
# Current
qc.remove_final_measurements() # no measurements allowed
from qiskit.quantum_info import Operator
result = Operator(qc).data
from qiskit import QuantumCircuit
qc = QuantumCircuit(3)
qc.h(0)
qc.h(1)
qc.cx(1, 2)
qc.measure_all()
# Previous
from qiskit import BasicAer
backend = BasicAer.get_backend("qasm_simulator")
result = backend.run(qc).result()
# One current option
from qiskit.providers.basic_provider import BasicProvider
backend = BasicProvider().get_backend("basic_simulator")
result = backend.run(qc).result()
# Another current option is to specify it directly
from qiskit.providers.basic_provider import BasicSimulator
backend = BasicSimulator()
result = backend.run(qc).result()
fake_provider
جُرى ترحيل معظم مكونات qiskit.providers.fake_provider الموجهة للمستخدم
إلى حزمة Python الخاصة بـ qiskit-ibm-runtime. يشمل ذلك فئات fake provider،
وجميع الـ backends الوهمية المخصصة للأجهزة (مثل FakeVigo وFakeNairobiV2 وFakeSherbrooke)،
والفئات الأساسية للـ backends الوهمية. انقر على التبويبات التالية لعرض الفئات المتأثرة.
- Backends الوهمية
- Providers الوهمية
- أي فئة في
qiskit.providers.fake_provider.backends fake_provider.fake_backend.FakeBackendfake_provider.fake_backend.FakeBackendV2
fake_provider.FakeProviderfake_provider.FakeProviderForBackendV2fake_provider.FakeProviderFactory
للانتقال إلى المسار الجديد:
-
ثبِّت
qiskit-ibm-runtimeبالإصدار0.17.1أو أحدث:pip install 'qiskit-ibm-runtime>=0.17.1' -
استبدل
qiskit.providers.fake_providerفي الكود بـqiskit_ibm_runtime.fake_provider. على سبيل المثال:# Old
from qiskit.providers.fake_provider import FakeProvider
backend1 = FakeProvider().get_backend("fake_ourense")
from qiskit.providers.fake_provider import FakeSherbrooke
backend2 = FakeSherbrooke()
# Alternative
from qiskit_ibm_runtime.fake_provider import FakeProvider
backend1 = FakeProvider().get_backend("fake_ourense")
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke
backend2 = FakeSherbrooke()
جرى ترحيل الفئات الأساسية للـ backends الوهمية أيضاً، لكن مع بعض الاختلاف في مسار الاستيراد:
| المُزال | البديل |
|---|---|
qiskit.providers.fake_provider.FakeQasmBackend | qiskit_ibm_runtime.fake_provider.fake_qasm_backend.FakeQasmBackend |
qiskit.providers.fake_provider.FakePulseBackend | qiskit_ibm_runtime.fake_provider.fake_pulse_backend.FakePulseBackend |
إذا كنت تعتمد على backends وهمية في اختبارات الوحدة لمكتبة تابعة، وواجهت تعارضاً مع تبعية qiskit-ibm-runtime، يمكنك الاستعاضة عنها ببدائل Qiskit-native للـ backends ال وهمية العامة.
وتشمل هذه فئات BackendV1 التالية (استبدال مباشر):
qiskit.providers.fake_provider.Fake5QV1qiskit.providers.fake_provider.Fake20QV1qiskit.providers.fake_provider.Fake7QPulseV1qiskit.providers.fake_provider.Fake27QPulseV1qiskit.providers.fake_provider.Fake127QPulseV1
وهذه فئة قابلة للتهيئة تُعيد نسخاً من BackendV2: