דלג לתוכן הראשי

הרחבת Qiskit בפייתון עם C

כדי להאיץ את תוכניות הפייתון שלך עם Qiskit באמצעות C, תוכל להשתמש בתוסף C של Qiskit לפייתון. הדבר מצריך שלבים נוספים מעבר לשימוש העצמאי ב-C; לפרטים נוספים, ראה את מדריך התקנת Qiskit C API.

אזהרה

ה-Qiskit C API עדיין ניסיוני, ועדיין לא מחויב לממשק תכנות או בינארי יציב לחלוטין. מודולי תוסף שנבנו מול Qiskit מובטחים לעבוד רק מול גרסת Qiskit שבה השתמשת בזמן הבנייה.

הערה

הוראות אלו נבדקו רק על מערכות דמויות-UNIX. הוראות עבור Windows נמצאות בפיתוח.

דרישות

התחל בכך שתוודא שהתקנת את Qiskit C API. לאחר מכן, התקן את ממשק הפייתון של Qiskit, כך:

pip install -r requirements.txt -c constraints.txt
pip install .

הגדרת תוסף ה-C

קיימות אפשרויות שונות לכתיבת תוסף C לפייתון. לשם הפשטות, מדריך זה מתחיל בגישה שמשתמשת במודול המובנה של פייתון ctypes. בחלק הבא, הסעיף תוסף C ידני מציג דוגמה לבניית תוסף C באמצעות C API של פייתון, כדי להפחית עומס בזמן ריצה.

כדוגמה, נניח שכתבת פונקציית C לבניית observable ותרצה להחזיר אותה לפייתון. תוכל להמיר QkObs* בצד C לאובייקט SparseObservable בצד פייתון, באמצעות הממיר המסופק qk_obs_to_python:

// file: extension.c
#define PY_SSIZE_T_CLEAN
#include <Python.h> // include Python header for access to PyObject
#define QISKIT_C_PYTHON_INTERFACE // enable C->Python conversion functions
#include <qiskit.h>

PyObject *build_observable(void) {
QkObs *obs = qk_obs_zero(100);
// build the observable ...
PyObject *pyobj = qk_obs_to_python(obs); // convert to Qiskit's Python ``SparseObservable``
qk_obs_free(obs);
return pyobj;
}

הדוגמה הבאה מראה כיצד לקמפל את הקוד לספרייה משותפת — לדוגמה, qiskit_cextension.so. לאחר שתסיים, תוכל לקרוא לתוכנת C מתוך פייתון:

# file: main.py
import qiskit
import ctypes

# Load the extension, ensuring the global interpreter lock (GIL) is acquired for function calls,
# which you need for the C->Python object conversion.
lib = ctypes.PyDLL("/path/to/qiskit_cextension.so")
lib.build_observable.argtypes = None # set argument types to the function
lib.build_observable.restype = ctypes.py_object # set return type

# now you can directly call the function
obs = lib.build_observable()
print("SparseObservable instance?", isinstance(obs, qiskit.quantum_info.SparseObservable))
print(obs)

בנייה

ראשית, עליך לבנות את תוסף הפייתון של Qiskit. זה כולל את סמלי ה-C כדי שתוכל לגשת לשני הממשקים דרך אותה ספרייה משותפת. חשוב שהנתונים יועברו כראוי בין C לפייתון.

python setup.py build_rust --inplace --release

הספרייה המשותפת נקראת _accelerate.<platform-specific-part>. מצא את מיקומה ושמה כך:

QKLIB=$(python -c "import os; import qiskit; print(os.path.dirname(qiskit._accelerate.__file__))")
QKNAME=$(python -c "import os; import qiskit; print(os.path.basename(qiskit._accelerate.__file__))")

תצטרך לדעת את מיקום ה-includes של פייתון בסביבה שלך (Python.h) ואת הספריות (libpython.<suffix>). לדוגמה, ניתן לזהות אותן כך:

PYINCLUDE=$(python -c "import sysconfig; print(sysconfig.get_path('include'))")
PYLIB=$(python -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
PYNAME=$(find $PYLIB -maxdepth 1 -name "libpython*" | grep -oE "[^/]+$" | grep -oE "python[0-9]+\.[0-9]+" || echo "python")

(אם כבר ידועים לך המיקומות והשמות האלו, אפשר גם להגדיר אותם ישירות.)

הקישור עשוי להשתנות בין פלטפורמות ומקשרים שונים. הדוגמה הבאה מתארת פתרון עבור מקשרים התומכים בספריות עם שמות שרירותיים, תוך שימוש בדגל -l: (כגון מקשר ld של GNU). ראה להלן אם המקשר שלך דורש שהספרייה תיקרא lib<something> (כגון מקשר ldd הנפוץ ב-MacOS).

תוכל לבנות את התוסף תוך ציון השם המלא של ספריית _accelerate:

gcc extension.c -fpic -shared -o cextension.so \
-I/path/to/dist/c/include -L$QKLIB -l:$QKNAME \
-I$PYINCLUDE -L$PYLIB -l$PYNAME

לאחר מכן, פשוט הרץ python main.py כדי להריץ את תוכנית הפייתון.

חלופה לשימוש בשם המדויק של הספרייה עם -l: היא יצירת symlink לספריית _accelerate עם השם הרצוי. כדי לכלול את הספרייה המשותפת _accelerate, צור symlink לפורמט הצפוי על ידי המקשר lib<library name>.<suffix>:

ln -s $QKLIB/$QKNAME $QKLIB/libqiskit.<suffix>

כאשר <suffix> הוא לדוגמה so על Linux או dylib על MacOS. פעולה זו מאפשרת להשתמש ב-qiskit כשם ספרייה:

gcc extension.c -fpic -shared -o qiskit_cextension.so \
-I/path/to/dist/c/include -L$QKLIB -lqiskit \
-I$PYINCLUDE -L$PYLIB -l$PYNAME

לאחר מכן, פשוט הרץ python main.py כדי להריץ את תוכנית הפייתון.

תוסף C ידני

במקום להשתמש ב-ctypes, ניתן לבנות ידנית תוסף לפייתון באמצעות C API של פייתון ישירות. לגישה זו יש פוטנציאל להיות מהירה יותר משימוש ב-ctypes, אם כי היא מצריכה מאמץ רב יותר לממשה. הקוד הבא הוא דוגמה קצרה כיצד להשיג זאת.

// file: extension.c
#define PY_SSIZE_T_CLEAN
#include <Python.h>

#include <stdio.h>
#define QISKIT_C_PYTHON_INTERFACE
#include <qiskit.h>

QkObs *build_observable() {
// build a 100-qubit empty observable
u_int32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);

// add the term 2 * (X0 Y1 Z2) to the observable
complex double coeff = 2; // the coefficient
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z}; // bit terms: X Y Z
uint32_t indices[3] = {0, 1, 2}; // indices: 0 1 2
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term); // append the term

return obs;
}

/// Define the Python function, which will internally build the QkObs using the
/// C function defined above, and then convert the C object to the Python equivalent:
/// a SparseObservable, handled as PyObject.
static PyObject *cextension_build_observable(PyObject *self, PyObject *args) {
// At this point, ``args`` could be parsed for arguments. See PyArg_ParseTuple for details.
QkObs *obs = build_observable(); // call the C function to build the observable
PyObject *py_obs = qk_obs_to_python(obs); // convert QkObs to the Python-equivalent
return py_obs;
}

/// Define the module methods.
static PyMethodDef CExtMethods[] = {
{"build_observable", cextension_build_observable, METH_VARARGS, "Build an observable."},
{NULL, NULL, 0, NULL}, // sentinel
};

/// Define the module, which here is called ``cextension``.
static struct PyModuleDef cextension = {
PyModuleDef_HEAD_INIT,
"cextension", // module name
NULL, // docs
-1, // keep the module state in global variables
CExtMethods,
};

PyMODINIT_FUNC PyInit_cextension(void) { return PyModule_Create(&cextension); }

כדי לקמפל ספרייה משותפת, קשר הן את ספריות פייתון והן את ספריות Qiskit, כפי שמתואר בחלק בנייה לעיל. סקריפט הפייתון אז אינו זקוק ל-ctypes אלא יכול לייבא ישירות את המודול cextension (ודא שהוא נמצא ב-Python path שלך):

# file: main.py
import qiskit
import cextension

# directly call the function
obs = cextension.build_observable()
print("SparseObservable instance?", isinstance(obs, qiskit.quantum_info.SparseObservable))
print(obs)