Lanjutkan Qiskit dalam Python dengan C
Untuk mempercepatkan program Python Qiskit anda dengan C, anda boleh menggunakan sambungan C Qiskit untuk Python. Ini memerlukan langkah tambahan berbanding penggunaan C secara kendiri; untuk maklumat lanjut, lihat panduan Pasang Qiskit C API.
Qiskit C API masih dalam peringkat eksperimental, dan belum lagi komited kepada antara muka pengaturcaraan atau binari yang sepenuhnya stabil. Modul sambungan yang dibina terhadap Qiskit hanya dijamin berfungsi dengan versi Qiskit yang digunakan semasa pembinaan.
Arahan ini hanya telah diuji pada sistem seperti UNIX. Arahan Windows sedang dalam proses.
Keperluanβ
Mulakan dengan memastikan anda telah memasang Qiskit C API. Seterusnya, pasang antara muka Python Qiskit, seperti berikut:
pip install -r requirements.txt -c constraints.txt
pip install .
Takrifkan sambungan Cβ
Terdapat pelbagai pilihan untuk menulis sambungan C bagi Python. Untuk memudahkan, panduan ini bermula dengan pendekatan yang menggunakan modul ctypes terbina dalam Python. Dalam bahagian seterusnya, bahagian sambungan C Manual menyediakan contoh pembinaan sambungan C menggunakan C API Python untuk mengurangkan overhed masa jalan.
Sebagai contoh, andaikan anda menulis fungsi C untuk membina observable dan ingin mengembalikannya ke Python. Anda boleh menukar QkObs* di sisi C kepada objek SparseObservable di sisi Python, menggunakan penukar yang disediakan
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;
}
Berikut menunjukkan cara mengkompil ini ke dalam perpustakaan dikongsi - contohnya, qiskit_cextension.so.
Setelah ini selesai, anda boleh memanggil program C daripada Python:
# 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)
Binaβ
Pertama, anda perlu membina sambungan Python Qiskit. Ini merangkumi simbol C supaya anda boleh mengakses kedua-dua antara muka melalui perpustakaan dikongsi yang sama. Ini penting untuk memastikan data boleh dihantar dengan betul merentas C dan Python.
python setup.py build_rust --inplace --release
Perpustakaan dikongsi dipanggil _accelerate.<bahagian-khusus-platform>. Cari lokasi dan namanya seperti berikut:
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__))")
Anda perlu mengetahui lokasi include Python persekitaran (Python.h) dan perpustakaan (libpython.<suffix>).
Ini boleh, sebagai contoh, dikenal pasti dengan
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")
(Jika anda sudah mengetahui lokasi dan nama ini, anda juga boleh menetapkannya secara langsung.)
Pautβ
Penautan boleh berbeza mengikut platform dan penaut. Berikut menerangkan penyelesaian untuk penaut yang
menyokong perpustakaan dengan nama sewenang-wenangnya, menggunakan bendera -l: (seperti penaut GNU ld).
Lihat di bawah jika penaut anda memerlukan perpustakaan dipanggil lib<sesuatu> (seperti penaut ldd
yang biasa pada MacOS).
Anda boleh membina sambungan dengan menentukan nama penuh perpustakaan _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
Kemudian, masukkan sahaja python main.py untuk menjalankan program Python.
Alternatif kepada penggunaan nama perpustakaan tepat dengan -l: ialah dengan membuat symlink perpustakaan _accelerate
kepada nama yang dikehendaki.
Untuk menyertakan perpustakaan dikongsi _accelerate, buat symlinknya kepada format yang dijangka oleh penaut iaitu lib<nama perpustakaan>.<suffix>:
ln -s $QKLIB/$QKNAME $QKLIB/libqiskit.<suffix>
di mana <suffix> ialah contohnya so pada Linux atau dylib pada MacOS. Ini membolehkan penggunaan qiskit sebagai nama perpustakaan:
gcc extension.c -fpic -shared -o qiskit_cextension.so \
-I/path/to/dist/c/include -L$QKLIB -lqiskit \
-I$PYINCLUDE -L$PYLIB -l$PYNAME
Kemudian, masukkan sahaja python main.py untuk menjalankan program Python.
Sambungan C Manualβ
Selain menggunakan ctypes, anda boleh membina sambungan untuk Python secara manual menggunakan C API Python secara langsung. Ini berpotensi lebih pantas berbanding menggunakan ctypes, walaupun memerlukan lebih usaha untuk dilaksanakan.
Kod berikut ialah contoh ringkas cara mencapainya.
// 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); }
Untuk mengkompil perpustakaan dikongsi, paut kedua-dua perpustakaan Python dan Qiskit, seperti yang diterangkan dalam
bahagian Bina di atas. Skrip Python kemudian tidak memerlukan ctypes
tetapi boleh mengimport modul cextension secara langsung (pastikan ia ada dalam laluan Python anda):
# 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)