qpp/pyqpp
Vlad Gheorghiu 94932b9c07
Conditional statements (#178)
* Initial stab at conditionals

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Removed trailing whitespaces in qasm files

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Changed qasm IfStmt to use cond_if

* Conditionals now work. Small changes to execute and QCircuitIterator.

* fix QBaseEngine

* fix to execute_circuit_steps_once_, all unit tests pass.

* made iterator_type a value, not a reference

* formatting

* removed LOGs

* Update qengine.hpp

* Fix to conditionals, added conditionals to pyqpp.

* made measured_d_ a stack in qcircuit.hpp

* formatting

* Update qcircuit.hpp

* Update qcircuit_conditional_step.hpp

* Added WHILE and ENDWHILE, extra exception checks

* minor update

* Update qpp.hpp

* Changes to QCircuitConditionalStep

* while_pos_ to outer_while_pos_

* updated (c) notice

Updated (c) notice

* update

* Added conditional_if/while examples

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Preparing for Version 6.0

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Updated README.md

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Minor update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Fixed typo

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Added Windows CI

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Member var zero-init

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* fixing Windows CI

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* fixing Windows CI

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Finished fixing Windows CI

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Minor stylystic updates to pyqpp

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Spacing

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Minor stylistic update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Updated CODE_OF_CONDUCT.md

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Update

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Fix

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Yet more fixes, all tests pass

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* More fixes

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Preparing v6.0

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* typo

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Preparing for v6.0

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

* Update qbase_engine.hpp

* Version 6.0

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>

---------

Signed-off-by: Vlad Gheorghiu <vsoftco@gmail.com>
Co-authored-by: a3moses <a3moses@uwaterloo.ca>
2025-04-14 16:32:11 -04:00
..
include/pyqpp Conditional statements (#178) 2025-04-14 16:32:11 -04:00
CMakeLists.txt Updates towards 5.1 (#169) 2024-02-14 15:00:59 -05:00
README.md Conditional statements (#178) 2025-04-14 16:32:11 -04:00
qpp_wrapper.cpp Conditional statements (#178) 2025-04-14 16:32:11 -04:00

README.md

Installation instructions

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

Creating python stubs for IDE autocompletion and static type checking

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-packages

In 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.

Overview

pyqpp includes Bit_circuit, Dynamic_bitset, 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))

OpenQASM circuits

Use pyqpp.qasm.read_from_file to obtain the QCircuit representation of an OpenQASM 2.0 file.

Custom Bindings

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);

    ...
}

Template methods

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);

    ...
}