Palawakin ang Qiskit sa Python gamit ang C
Para mapabilis ang iyong mga Qiskit Python program gamit ang C, maaari mong gamitin ang Qiskit C extension para sa Python. Kailangan nito ng ilang karagdagang hakbang kumpara sa standalone na paggamit ng C; para sa mas detalyadong impormasyon, tingnan ang gabay sa Pag-install ng Qiskit C API.
Ang Qiskit C API ay eksperimental pa rin at hindi pa nakapirmi ang programming o binary interface nito. Ang mga extension module na ginawa gamit ang Qiskit ay garantisadong gagana lamang sa bersyon ng Qiskit na ginamit sa pagbuo.
Ang mga instruksyong ito ay nasubok lamang sa mga UNIX-like na sistema. Ang mga instruksyon para sa Windows ay kasalukuyang ginagawa.
Mga Kinakailanganβ
Magsimula sa pamamagitan ng pagtitiyak na naka-install ang Qiskit C API. Pagkatapos, i-install ang Qiskit Python interface, tulad ng sumusunod:
pip install -r requirements.txt -c constraints.txt
pip install .
Tukuyin ang C extensionβ
May iba't ibang paraan para sumulat ng C extension para sa Python. Para sa pagiging simple, ang gabay na ito ay nagsisimula sa isang paraan na gumagamit ng built-in na ctypes module ng Python. Sa susunod na seksyon, ang seksyon ng Manual C extension ay nagbibigay ng halimbawa ng pagbuo ng C extension gamit ang Python's C API para mabawasan ang runtime overhead.
Bilang halimbawa, ipagpalagay na sumulat ka ng C function para gumawa ng observable at nais mong ibalik ito sa Python. Maaari mong i-convert ang isang QkObs* sa gilid ng C patungo sa isang SparseObservable na object sa gilid ng Python, gamit ang ibinigay na converter na 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;
}
Ipinapakita ng sumusunod kung paano i-compile ito sa isang shared library β halimbawa, qiskit_cextension.so.
Kapag tapos na ito, maaari mong tawagin ang C program mula sa 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)
Pagbuoβ
Una, kailangan mong buuin ang Qiskit Python extension. Kasama dito ang mga C symbol para ma-access mo ang parehong interface sa pamamagitan ng iisang shared library. Mahalaga ito para matiyak na maaaring maipasa nang tama ang data sa pagitan ng C at Python.
python setup.py build_rust --inplace --release
Ang shared library ay tinatawag na _accelerate.<platform-specific-part>. Hanapin ang lokasyon at pangalan nito tulad ng sumusunod:
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__))")
Kailangan mong malaman ang lokasyon ng Python includes (Python.h) at libraries (libpython.<suffix>) ng environment.
Maaari itong matukoy, halimbawa, gamit ang:
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")
(Kung alam mo na ang mga lokasyon at pangalan na ito, maaari mo rin itong itakda nang direkta.)
I-linkβ
Maaaring mag-iba ang pag-link depende sa platform at linker. Inilalarawan ng sumusunod ang isang solusyon para sa mga linker na sumusuporta sa mga library na may arbitrary na pangalan, gamit ang -l: flag (tulad ng GNU's ld linker). Tingnan sa ibaba kung ang iyong linker ay nangangailangan na ang library ay tawaging lib<something> (tulad ng ldd linker na karaniwang makikita sa MacOS).
Maaari mong buuin ang extension na tinutukoy ang buong pangalan ng _accelerate library:
gcc extension.c -fpic -shared -o cextension.so \
-I/path/to/dist/c/include -L$QKLIB -l:$QKNAME \
-I$PYINCLUDE -L$PYLIB -l$PYNAME
Pagkatapos, ilagay lang ang python main.py para patakbuhin ang Python program.
Bilang alternatibo sa paggamit ng eksaktong pangalan ng library gamit ang -l:, maaari kang gumawa ng symlink ng _accelerate library sa gustong pangalan.
Para isama ang _accelerate shared library, gumawa ng symlink nito sa format na inaasahan ng linker na lib<library name>.<suffix>:
ln -s $QKLIB/$QKNAME $QKLIB/libqiskit.<suffix>
kung saan ang <suffix> ay halimbawa so sa Linux o dylib sa MacOS. Pinapayagan nito ang paggamit ng qiskit bilang pangalan ng library:
gcc extension.c -fpic -shared -o qiskit_cextension.so \
-I/path/to/dist/c/include -L$QKLIB -lqiskit \
-I$PYINCLUDE -L$PYLIB -l$PYNAME
Pagkatapos, ilagay lang ang python main.py para patakbuhin ang Python program.
Manual na C extensionβ
Sa halip na gumamit ng ctypes, posible ring manu-manong bumuo ng extension para sa Python gamit ang Python's C API nang direkta. May potensyal itong maging mas mabilis kaysa sa paggamit ng ctypes, bagaman nangangailangan ito ng mas maraming pagsisikap sa pagpapatupad.
Ang sumusunod na code ay isang maikling halimbawa kung paano ito makakamit.
// 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); }
Para mag-compile ng shared library, i-link ang parehong Python at Qiskit library, tulad ng inilarawan sa seksyon ng Pagbuo sa itaas. Ang Python script ay hindi na kailangan ng ctypes at maaaring direktang mag-import ng cextension module (tiyaking nasa iyong Python path ito):
# 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)