-
Notifications
You must be signed in to change notification settings - Fork 141
8. pyqpp
pyqpp is a Python 3 wrapper for Quantum++.
pyqpp is a Python 3
wrapper for Quantum++. pyqpp requires the same dependencies as Quantum++,
and can be installed using pip
pip install git+https://github.com/softwareQinc/qpp
In case autocompletion (or static type checking via mypy) does not work properly in your editor/IDE, you may need to create python stubs for the package. To do this, execute
mkdir ~/python_stubs
export MYPATH=$MYPATH:~/python_subs # put this in your .profile or .bashrc
. ~/venv/bin/activate
stubgen -p pyqpp -o ~/python_stubs
ln -s ~/python_stubs/pyqpp ~/venv/lib/python3.11/site-packagesIn the above, we assumed that your platform is UNIX/UNIX-like, and that you
have pyqpp installed in a virtual environment under ~/venv. Please modify
accordingly for your system.
pyqpp includes BitCircuit, DynamicBitset, QCircuitT, QEngineT,
QNoisyEngineT, and several other derived Engine classes. Additionally,
pyqpp provides commonly used quantum gates and states, and some basic
Eigen operations.
Example:
import numpy as np
from pyqpp import *
print("Qubit teleportation quantum circuit simulation\n")
# quantum circuit with 3 qubits and 2 classical bits
qc = QCircuit(3, 2)
# set the qubit 0 to a random state
U = randU(2)
# apply the gate U with name randU to qubit 0
qc.gate(U, 0, "randU")
# set the MES between qubits 1 and 2
qc.gate(gates.H, 1)
qc.CTRL(gates.X, 1, 2)
# perform the Bell measurement between qubits 0 and 1
qc.CTRL(gates.X, 0, 1)
qc.gate(gates.H, 0)
qc.measure([0, 1])
# apply the classical controls
qc.cCTRL(gates.X, 1, 2)
qc.cCTRL(gates.Z, 0, 2)
# initialize the quantum engine with a circuit
engine = QEngine(qc)
# display the quantum circuit and its corresponding resources
print(qc)
print()
print(qc.get_resources())
print()
# execute the entire circuit
engine.execute()
# display the measurement statistics
print(engine)
print()
# verify that the teleportation was successful
psi_in = np.matmul(U, states.z0)
psi_out = engine.get_state()
print("Teleported state:")
print(dirac(psi_out))
print("Norm difference:\n", norm(psi_out - psi_in))Use pyqpp.qasm.read_from_file to obtain the QCircuit representation of an
OpenQASM 2.0 file.
pyqpp was created using pybind11, see
pyqpp/qpp_wrapper.cpp.
To wrap a custom function, use pybind11::module::def.
template<typename Func, typename ...Extra>
module &def(const char *name_, Func &&f, const Extra&... extra)Func can be a plain C++ function, a function pointer, or a lambda function.
For example, consider the qpp::randU method
cmat randU(idx D = 2);which is wrapped as
PYBIND11_MODULE(pyqpp, m) {
...
m.def("randU", &qpp::randU, "Generates a random unitary matrix",
py::arg("D") = 2);
...
}We cannot wrap templated functions; instead, we must explicitly instantiate
them. For example, consider the qpp::norm method
template <typename Derived>
double norm(const Eigen::MatrixBase<Derived>& A);One way to wrap this is
PYBIND11_MODULE(pyqpp, m) {
...
m.def("norm", [](const cmat& A) { return qpp::norm(A); }, "Frobenius norm");
m.def("norm", [](const ket& A) { return qpp::norm(A); }, "Frobenius norm");
...
}This creates the overloaded pyqpp.norm function, which can accept cmat
or ket types. To avoid repetition of boilerplate code, we can templatize the
binding:
template<typename T>
void def_norm(pybind11::module &m) {
m.def("norm", [](const T& A) { return qpp::norm(A); }, "Frobenius norm");
}
PYBIND11_MODULE(pyqpp, m) {
...
def_norm<cmat>(m);
def_norm<ket>(m);
...
}Copyright (c) 2017 - 2026 softwareQ Inc. All rights reserved.