├── .clang-format
├── .clang-tidy
├── .gitattributes
├── .github
└── workflows
│ └── cmake.yml
├── .gitignore
├── CHANGES.md
├── CMakeLists.txt
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DISCREPANCIES.md
├── Doxyfile
├── INSTALL.md
├── LICENSE.txt
├── README.md
├── VERSION.txt
├── cmake
├── examples.cmake
├── pybind11.cmake
├── pyqpp.cmake
├── qppConfig.cmake.in
├── qpp_MATLAB.cmake
├── qpp_dependencies.cmake
├── qpp_eigen3.cmake
└── qpp_uninstall.cmake.in
├── docker
├── Dockerfile
└── README.md
├── examples
├── bb84.cpp
├── bell_inequalities.cpp
├── channels.cpp
├── circuits
│ ├── conditional_if.cpp
│ ├── conditional_while.cpp
│ ├── noisy_teleport_qubit_circuit.cpp
│ ├── post_selection.cpp
│ ├── qpe_circuit.cpp
│ ├── runtime_set_dits.cpp
│ ├── teleport_qubit_circuit.cpp
│ └── teleport_qudit_circuit.cpp
├── dense_coding.cpp
├── entanglement.cpp
├── entropies.cpp
├── exceptions.cpp
├── experimental_average.cpp
├── functor.cpp
├── gates_states.cpp
├── gram_schmidt.cpp
├── graph_states.cpp
├── grover.cpp
├── input_output.cpp
├── layouts.cpp
├── matlab_io.cpp
├── measurements1.cpp
├── measurements2.cpp
├── minimal.cpp
├── noise.cpp
├── qasm
│ ├── bell.qasm
│ ├── coin_flip.qasm
│ ├── qpp_qasm.cpp
│ ├── teleport_minimal.qasm
│ └── teleport_minimal_qasm.cpp
├── qecc.cpp
├── qft.cpp
├── qpe.cpp
├── qram.cpp
├── quantum_operations.cpp
├── randomness.cpp
├── reversible1.cpp
├── reversible2.cpp
├── shor.cpp
├── spectral.cpp
├── standalone
│ ├── CMakeLists.txt
│ └── src
│ │ └── main.cpp
├── statistics.cpp
├── teleport_qubit.cpp
├── teleport_qudit.cpp
├── timing1.cpp
├── timing2.cpp
└── toffoli.cpp
├── include
└── qpp
│ ├── MATLAB
│ └── matlab.hpp
│ ├── classes
│ ├── codes.hpp
│ ├── exception.hpp
│ ├── gates.hpp
│ ├── idisplay.hpp
│ ├── ijson.hpp
│ ├── init.hpp
│ ├── layouts.hpp
│ ├── noise.hpp
│ ├── qbase_engine.hpp
│ ├── qcircuit.hpp
│ ├── qcircuit_traits.hpp
│ ├── qdummy_engine.hpp
│ ├── qengine.hpp
│ ├── qengine_traits.hpp
│ ├── qnoisy_engine.hpp
│ ├── random_devices.hpp
│ ├── reversible.hpp
│ ├── states.hpp
│ └── timer.hpp
│ ├── constants.hpp
│ ├── entanglement.hpp
│ ├── entropies.hpp
│ ├── experimental
│ └── experimental.hpp
│ ├── functions.hpp
│ ├── input_output.hpp
│ ├── instruments.hpp
│ ├── internal
│ ├── classes
│ │ ├── iomanip.hpp
│ │ ├── labelled_vector_proxy.hpp
│ │ ├── qcircuit_gate_step.hpp
│ │ ├── qcircuit_measurement_step.hpp
│ │ ├── qcircuit_nop_step.hpp
│ │ ├── qcircuit_resources.hpp
│ │ ├── qcircuit_runtime_step.hpp
│ │ ├── qengine_state.hpp
│ │ ├── qengine_statistics.hpp
│ │ └── singleton.hpp
│ └── util.hpp
│ ├── number_theory.hpp
│ ├── operations.hpp
│ ├── options.hpp
│ ├── qasm
│ └── qasm.hpp
│ ├── qpp.hpp
│ ├── random.hpp
│ ├── statistics.hpp
│ ├── traits.hpp
│ └── types.hpp
├── prettyprint.sh
├── pyproject.toml
├── pyqpp
├── CMakeLists.txt
├── README.md
├── include
│ └── pyqpp
│ │ ├── classes
│ │ ├── gates_bind.hpp
│ │ ├── qcircuit_bind.hpp
│ │ ├── qdummy_engine_bind.hpp
│ │ ├── qengine_bind.hpp
│ │ ├── qnoisy_engine_bind.hpp
│ │ ├── reversible_bind.hpp
│ │ └── states_bind.hpp
│ │ ├── constants_bind.hpp
│ │ ├── functions_bind.hpp
│ │ ├── instruments_bind.hpp
│ │ ├── pyqpp_common.hpp
│ │ ├── pyqpp_specific_bind.hpp
│ │ ├── qasm
│ │ └── qasm_bind.hpp
│ │ ├── random_bind.hpp
│ │ └── types_bind.hpp
└── qpp_wrapper.cpp
├── qasmtools
├── include
│ └── qasmtools
│ │ ├── ast
│ │ ├── ast.hpp
│ │ ├── base.hpp
│ │ ├── cloneable.hpp
│ │ ├── decl.hpp
│ │ ├── expr.hpp
│ │ ├── program.hpp
│ │ ├── replacer.hpp
│ │ ├── semantic.hpp
│ │ ├── stmt.hpp
│ │ ├── traversal.hpp
│ │ ├── var.hpp
│ │ └── visitor.hpp
│ │ ├── parser
│ │ ├── lexer.hpp
│ │ ├── parser.hpp
│ │ ├── position.hpp
│ │ ├── preprocessor.hpp
│ │ └── token.hpp
│ │ ├── tools
│ │ └── ast_printer.hpp
│ │ └── utils
│ │ ├── angle.hpp
│ │ └── templates.hpp
└── qasm
│ ├── generic
│ ├── W-state.qasm
│ ├── adder.qasm
│ ├── bigadder.qasm
│ ├── inverseqft1.qasm
│ ├── inverseqft2.qasm
│ ├── ipea_3_pi_8.qasm
│ ├── pea_3_pi_8.qasm
│ ├── qec.qasm
│ ├── qelib1.inc
│ ├── qft.qasm
│ ├── qpt.qasm
│ ├── rb.qasm
│ ├── teleport.qasm
│ └── teleportv2.qasm
│ ├── ibmqx2
│ ├── 011_3_qubit_grover_50_.qasm
│ ├── Deutsch_Algorithm.qasm
│ ├── W3test.qasm
│ ├── images
│ │ └── 5qubitQXlabeled.png
│ ├── iswap.qasm
│ ├── qe_qft_3.qasm
│ ├── qe_qft_4.qasm
│ └── qe_qft_5.qasm
│ └── invalid
│ ├── gate_no_found.qasm
│ └── missing_semicolon.qasm
├── setup.py
├── stress_tests
├── .gitignore
├── CMakeLists.txt
├── README.md
├── python
│ ├── ptrace_qutip.py
│ ├── qft_qiskit.py
│ └── qft_qutip.py
├── run.sh
└── src
│ ├── ptrace.cpp
│ ├── qft.cpp
│ └── syspermute.cpp
└── unit_tests
├── CMakeLists.txt
└── tests
├── MATLAB
└── matlab.cpp
├── classes
├── gates.cpp
├── layouts.cpp
├── noise.cpp
├── qcircuit.cpp
├── qdummy_engine.cpp
├── qengine.cpp
├── qnoisy_engine.cpp
├── random_devices.cpp
├── reversible.cpp
├── states.cpp
└── timer.cpp
├── entanglement.cpp
├── entropies.cpp
├── functions.cpp
├── input_output.cpp
├── instruments.cpp
├── issues.cpp
├── main.cpp
├── number_theory.cpp
├── operations.cpp
├── qasm
├── circuits
│ └── units
│ │ ├── builtingates.qasm
│ │ ├── mappedgates.qasm
│ │ ├── nondestrmeas.qasm
│ │ ├── reset.qasm
│ │ ├── scinot.qasm
│ │ └── teleportation.qasm
└── qasm.cpp
├── random.cpp
├── statistics.cpp
└── traits.cpp
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | Language: Cpp
3 | ColumnLimit: 80
4 | Standard: c++17
5 | IndentWidth: 4
6 | TabWidth: 4
7 | UseTab: Never
8 | PointerAlignment: Left
9 | IndentCaseLabels: true
10 | AlwaysBreakTemplateDeclarations: Yes
11 | InsertBraces: true
12 | SortIncludes: true
13 | # system headers come first
14 | IncludeCategories:
15 | - Regex: "^<.*>"
16 | Priority: 1
17 | - Regex: '^".*\.(h|hpp)"'
18 | Priority: 2
19 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.github/workflows/cmake.yml:
--------------------------------------------------------------------------------
1 | name: GitHub actions
2 |
3 | on:
4 | push:
5 | branches: ["**"]
6 | pull_request:
7 | branches: ["**"]
8 |
9 | env:
10 | BUILD_TYPE: Debug
11 |
12 | jobs:
13 | build:
14 | strategy:
15 | matrix:
16 | os: [ubuntu-latest, macos-latest, windows-latest]
17 | runs-on: ${{ matrix.os }}
18 |
19 | steps:
20 | - uses: actions/checkout@v4
21 |
22 | - name: Configure Quantum++
23 | run: cmake -B build
24 |
25 | - name: Install Quantum++
26 | shell: bash
27 | run: |
28 | if [ "$RUNNER_OS" == "Windows" ]; then
29 | cmake --install build
30 | else
31 | sudo cmake --install build
32 | fi
33 |
34 | - name: Configure standalone example
35 | run: cmake -S examples/standalone -B examples/standalone/build
36 |
37 | - name: Build standalone example
38 | run: cmake --build examples/standalone/build --target standalone
39 |
40 | - name: Run standalone example
41 | shell: bash
42 | run: |
43 | if [ "$RUNNER_OS" == "Windows" ]; then
44 | ./examples/standalone/build/${{env.BUILD_TYPE}}/standalone.exe
45 | else
46 | ./examples/standalone/build/standalone
47 | fi
48 |
49 | - name: Build examples
50 | run: cmake --build build --target examples
51 |
52 | - name: Build unit tests
53 | run: cmake --build build/unit_tests --target unit_tests
54 |
55 | - name: Run unit tests
56 | run: ctest --test-dir build -E qpp_Timer
57 |
58 | - name: Uninstall Quantum++
59 | shell: bash
60 | run: |
61 | if [ "$RUNNER_OS" == "Windows" ]; then
62 | cmake --build build --target uninstall
63 | else
64 | sudo cmake --build build --target uninstall
65 | fi
66 |
67 | - name: Install pyqpp
68 | shell: bash
69 | run: |
70 | python3 -mvenv venv
71 | if [ "$RUNNER_OS" == "Windows" ]; then
72 | venv/Scripts/Activate
73 | else
74 | source venv/bin/activate
75 | fi
76 | pip3 install .
77 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
34 | # Vim
35 | *.swp
36 |
37 | # Emacs
38 | \#*\#
39 | *~
40 |
41 | # clangd
42 | .cache/
43 | compile_commands.json
44 |
45 | # MSVC
46 | .vs/
47 | /out*
48 | CMakeSettings.json
49 |
50 | # VS Code
51 | .vscode/
52 |
53 | # CLion
54 | .idea/
55 | build/
56 | cmake-build*/
57 |
58 | # Documentation source files
59 | doc/
60 |
61 | # Misc
62 | .DS_Store
63 | .cmake/
64 | Testing/
65 | mat.txt
66 | examples/_*.cpp
67 | out.tmp
68 | TODO.txt
69 | test
70 |
71 | # pyqpp
72 | Makefile
73 | cmake_install.cmake
74 | CMakeCache.txt
75 | CMakeFiles/
76 | pyqpp.egg-info/
77 | /uv.lock
78 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | If you are interested in contributing to this project, please contact us.
2 | Alternatively, fork the repository, create a custom branch, add your
3 | contribution, then finally create a pull request. If we accept the pull request,
4 | we will merge your custom branch with the latest main/development branch. The
5 | latter will eventually be merged into a future release version. To contribute,
6 | it is preferable to have a solid knowledge of modern C++ (preferably C++17 or
7 | later), including templates and the standard library, a basic knowledge of
8 | quantum computing and linear algebra, and working experience
9 | with [Eigen 3](https://eigen.tuxfamily.org).
10 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/VERSION.txt:
--------------------------------------------------------------------------------
1 | Version 6.0 - 14 April 2025
2 |
--------------------------------------------------------------------------------
/cmake/examples.cmake:
--------------------------------------------------------------------------------
1 | # Examples Source file(s) to be compiled, modify as needed
2 | aux_source_directory(${CMAKE_SOURCE_DIR}/examples EXAMPLE_FILES)
3 | aux_source_directory(${CMAKE_SOURCE_DIR}/examples/circuits EXAMPLE_FILES)
4 | aux_source_directory(${CMAKE_SOURCE_DIR}/examples/qasm EXAMPLE_FILES)
5 |
6 | # Build all examples in ${EXAMPLE_FILES}
7 | add_custom_target(examples COMMENT "Examples")
8 | foreach(file ${EXAMPLE_FILES})
9 | get_filename_component(TARGET_NAME ${file} NAME_WE)
10 | # Do not build "examples/matlab_io.cpp" if there's no MATLAB support
11 | if(${TARGET_NAME} STREQUAL "matlab_io" AND NOT MATLAB_FOUND)
12 | continue()
13 | endif()
14 | add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL ${file})
15 | add_dependencies(examples ${TARGET_NAME})
16 | target_link_libraries(${TARGET_NAME} PUBLIC ${QPP_LINK_DEPS} libqpp)
17 | endforeach()
18 |
--------------------------------------------------------------------------------
/cmake/pybind11.cmake:
--------------------------------------------------------------------------------
1 | message(STATUS "Detecting pybind11...")
2 | find_package(pybind11 CONFIG)
3 | if(NOT pybind11_FOUND)
4 | # Install pybind11 on demand
5 | include(FetchContent)
6 | set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
7 | message(STATUS "pybind11 not detected, fetching pybind11...")
8 | FetchContent_Declare(
9 | pybind11
10 | GIT_REPOSITORY https://github.com/pybind/pybind11
11 | GIT_TAG master
12 | GIT_SHALLOW TRUE
13 | GIT_PROGRESS TRUE)
14 | FetchContent_MakeAvailable(pybind11)
15 | set(PYBIND11_INCLUDE_DIRS ${pybind11_SOURCE_DIR})
16 | endif()
17 | message(STATUS "Detected pybind11 in: ${PYBIND11_INCLUDE_DIRS}")
18 |
--------------------------------------------------------------------------------
/cmake/pyqpp.cmake:
--------------------------------------------------------------------------------
1 | # LSP and CMake support for pyqpp
2 |
3 | # pybind11
4 | include_directories(SYSTEM ${PYBIND11_INCLUDE_DIRS})
5 | target_include_directories(
6 | libqpp INTERFACE $)
7 |
8 | # Python development
9 | target_include_directories(libqpp
10 | INTERFACE $)
11 |
12 | # pyqpp
13 | target_include_directories(
14 | libqpp
15 | INTERFACE $)
16 |
--------------------------------------------------------------------------------
/cmake/qppConfig.cmake.in:
--------------------------------------------------------------------------------
1 | @PACKAGE_INIT@
2 |
3 | set(QPP_INSTALL_DIR "@QPP_INSTALL_DIR@")
4 | # Do not change the order below!
5 | include("${CMAKE_CURRENT_LIST_DIR}/qpp_eigen3.cmake")
6 | include("${CMAKE_CURRENT_LIST_DIR}/qpp_dependencies.cmake")
7 | include("${CMAKE_CURRENT_LIST_DIR}/qpp_MATLAB.cmake")
8 | include("${CMAKE_CURRENT_LIST_DIR}/qpp_targets.cmake")
9 | message(STATUS "Found Quantum++ in @QPP_INSTALL_DIR@")
10 |
--------------------------------------------------------------------------------
/cmake/qpp_MATLAB.cmake:
--------------------------------------------------------------------------------
1 | # MATLAB support, disabled by default
2 | option(QPP_MATLAB "MATLAB support" OFF)
3 | if(${QPP_MATLAB})
4 | message(STATUS "Detecting MATLAB...")
5 | find_package(Matlab REQUIRED COMPONENTS MX_LIBRARY MAT_LIBRARY)
6 | if(MATLAB_FOUND)
7 | include_directories(SYSTEM ${Matlab_INCLUDE_DIRS})
8 | set(QPP_MATLAB_LINK_DEPS Matlab::mat Matlab::mx)
9 | message(STATUS "Detected MATLAB in: ${Matlab_ROOT_DIR}")
10 | else()
11 | message(FATAL_ERROR "Could not detect MATLAB, aborting")
12 | endif()
13 | endif()
14 |
--------------------------------------------------------------------------------
/cmake/qpp_eigen3.cmake:
--------------------------------------------------------------------------------
1 | message(STATUS "Detecting Eigen3...")
2 | find_package(Eigen3 3.0 QUIET NO_MODULE)
3 | if(NOT TARGET Eigen3::Eigen)
4 | # Install Eigen3 on demand
5 | include(FetchContent)
6 | set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
7 | message(STATUS "Eigen3 not detected, fetching Eigen3...")
8 | FetchContent_Declare(
9 | Eigen3
10 | SYSTEM
11 | GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
12 | GIT_TAG 3.4.0 # 3.4.0
13 | GIT_SHALLOW TRUE
14 | # no CMakeLists.txt in cmake, so this turns off configure. Recommend also
15 | # to add `FIND_PACKAGE_ARGS CONFIG` so that FetchContent checks to see if
16 | # Eigen is installed on the system, via the OS, or a package manager
17 | SOURCE_SUBDIR cmake)
18 | FetchContent_MakeAvailable(Eigen3)
19 | endif()
20 |
21 | if(NOT TARGET Eigen3::Eigen)
22 | add_library(Eigen3::Eigen INTERFACE IMPORTED)
23 | set_target_properties(Eigen3::Eigen PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
24 | ${eigen3_SOURCE_DIR})
25 | set(EIGEN3_INCLUDE_DIR ${eigen3_SOURCE_DIR})
26 | endif()
27 |
28 | message(STATUS "Detected Eigen3 in: ${EIGEN3_INCLUDE_DIR}")
29 | set(QPP_EIGEN3_LINK_DEPS Eigen3::Eigen)
30 |
--------------------------------------------------------------------------------
/cmake/qpp_uninstall.cmake.in:
--------------------------------------------------------------------------------
1 | if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
2 | message(
3 | FATAL_ERROR
4 | "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
5 | endif()
6 |
7 | file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
8 | string(REGEX REPLACE "\n" ";" files "${files}")
9 | foreach(file ${files})
10 | message(STATUS "Uninstalling ${file}")
11 | if(IS_SYMLINK "${file}" OR EXISTS "${file}")
12 | execute_process(
13 | COMMAND @CMAKE_COMMAND@ -E rm -f "${file}"
14 | OUTPUT_VARIABLE rm_out
15 | RESULT_VARIABLE rm_retval)
16 | if(${rm_retval})
17 | message(FATAL_ERROR "Problem when removing ${file}")
18 | endif()
19 | else()
20 | message(STATUS "File ${file} does not exist.")
21 | endif()
22 | endforeach()
23 |
24 | if(NOT "@MSVC@")
25 | message(STATUS "Removing @CMAKE_INSTALL_PREFIX@/lib/cmake/@PROJECT_NAME@")
26 | message(STATUS "Removing @QPP_INSTALL_DIR@")
27 | else()
28 | message(STATUS "Removing @CMAKE_INSTALL_PREFIX@")
29 | endif()
30 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:latest
2 | ENV TZ="America/Toronto"
3 | RUN apt-get update && \
4 | apt-get -y update && \
5 | apt-get install -yq tzdata && \
6 | ln -fs /usr/share/zoneinfo/America/Toronto /etc/localtime && \
7 | dpkg-reconfigure -f noninteractive tzdata
8 |
9 | RUN apt-get install -y build-essential python3 python3-pip python3-dev \
10 | libeigen3-dev cmake sudo git vim
11 |
12 | # Install pyqpp
13 | RUN pip3 -q install pip --upgrade
14 | RUN pip3 install jupyter matplotlib numpy
15 | RUN pip3 install git+https://github.com/softwareqinc/qpp
16 |
17 | # Enable a normal user with sudo access
18 | RUN useradd -m -c "softwareQ" sq
19 | RUN echo '%sq ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
20 | USER sq
21 |
22 | # Clone and install Quantum++
23 | WORKDIR /home/sq
24 | RUN git clone --depth 1 --branch main https://github.com/softwareqinc/qpp
25 | WORKDIR /home/sq/qpp
26 | RUN cmake -B build && sudo cmake --build build --target install
27 | USER sq
28 | WORKDIR /home/sq
29 |
30 | # Create a notebook directory for Jupyter
31 | RUN mkdir notebooks
32 |
--------------------------------------------------------------------------------
/docker/README.md:
--------------------------------------------------------------------------------
1 | ## Docker
2 |
3 | A self-explanatory minimalistic Docker file is provided
4 | in [`Dockerfile`](https://github.com/softwareqinc/qpp/tree/main/docker/Dockerfile).
5 |
6 | Build the image by executing
7 |
8 | ```shell
9 | docker build -t softwareq-qpp .
10 | ```
11 |
12 | ---
13 |
14 | Run the Jupyter server in a container by executing
15 |
16 | ```shell
17 | docker run -p8888:8888 -it --workdir=/home/sq/notebooks softwareq-qpp sh -c "jupyter notebook --port=8888 --no-browser --ip=0.0.0.0"
18 | ```
19 |
20 | ---
21 |
22 | In case you want to use the Docker container as a development environment,
23 | mount your directory (in this example the current directory) in a Docker
24 | container with
25 |
26 | ```shell
27 | docker run --rm -it --workdir=/home/sq/hostdir -v ${PWD}:/home/sq/hostdir softwareq-qpp /bin/bash
28 | ```
29 |
--------------------------------------------------------------------------------
/examples/channels.cpp:
--------------------------------------------------------------------------------
1 | // Quantum channels
2 | // Source: ./examples/channels.cpp
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "qpp/qpp.hpp"
9 |
10 | int main() {
11 | using namespace qpp;
12 |
13 | idx D = 3; // dimension
14 | idx nk = 5; // nk Kraus operators on a D-dimensional system
15 | std::cout << ">> Generating a random channel with " << nk
16 | << " Kraus operators on a " << D << " dimensional space\n";
17 | std::vector Ks = randkraus(nk, D);
18 |
19 | cmat rho_in = randrho(D); // random input state
20 | cmat rho_out = qpp::apply(rho_in, Ks); // output state
21 |
22 | std::cout << ">> Computing its Choi matrix...\n";
23 | cmat choim = kraus2choi(Ks);
24 | std::cout << ">> Choi matrix:\n" << disp(choim) << '\n';
25 |
26 | std::cout << ">> The eigenvalues of the Choi matrix are:\n"
27 | << disp(transpose(hevals(choim))) << '\n';
28 |
29 | std::cout << ">> Their sum is: " << sum(hevals(choim)) << '\n';
30 |
31 | std::vector Kperps = choi2kraus(choim);
32 | std::cout << ">> The Kraus rank of the channel is: " << Kperps.size()
33 | << '\n';
34 |
35 | cmat rho_out1 = qpp::apply(rho_in, Kperps);
36 | // verification
37 | std::cout << ">> Norm difference on output states: "
38 | << norm(rho_out1 - rho_out) << '\n';
39 |
40 | std::cout << ">> Superoperator matrix:\n";
41 | cmat smat = kraus2super(Ks);
42 | std::cout << disp(smat) << '\n';
43 |
44 | std::cout << ">> The eigenvalues of the superoperator matrix are:\n";
45 | dyn_col_vect evalsupop = evals(smat);
46 | std::cout << disp(transpose(evalsupop)) << '\n';
47 |
48 | std::cout << ">> Their absolute values are:\n";
49 | for (idx i = 0; i < (idx)evalsupop.size(); ++i) {
50 | std::cout << std::abs(evalsupop(i)) << " ";
51 | }
52 |
53 | // verification
54 | std::cout << "\n>> Norm difference for the superoperator action: ";
55 | cmat rho_out2 =
56 | transpose(reshape(smat * reshape(transpose(rho_in), D * D, 1), D, D));
57 | std::cout << norm(rho_out - rho_out2) << '\n';
58 | }
59 |
--------------------------------------------------------------------------------
/examples/circuits/conditional_if.cpp:
--------------------------------------------------------------------------------
1 | // Conditional IF quantum circuit simulator
2 | // Source: ./examples/circuits/conditional_if.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Conditional IF quantum circuit simulator\n\n";
12 |
13 | // quantum circuit with 2 qubits and 2 classical bits
14 | QCircuit qc{3, 3};
15 | // prepare the first qubit in the |+> state
16 | qc.gate(gt.H, 0);
17 | // measure the first qubit non-destructively
18 | qc.measure(0, 0, false);
19 |
20 | // define a boolean predicate of the required form
21 | // const_proxy_to_engine_dits_t -> bool
22 | auto pred = [](auto dits) {
23 | // returns true when the first dit is 1 at runtime (when run by a
24 | // quantum engine); in our case, this corresponds to the result of the
25 | // measurement result of the first qubit
26 | return dits[0] == 1;
27 | };
28 | // conditional IF statement
29 | // flips the second qubit when the predicate above was true, otherwise
30 | // flips the third qubit
31 | qc.cond_if(pred);
32 | // curly braces are optional, used to force code indenting
33 | {
34 | qc.gate(gt.X, 1); // the final state will be |110>
35 | }
36 | qc.cond_else();
37 | {
38 | qc.gate(gt.X, 2); // the final state will be |001>
39 | }
40 | qc.cond_end();
41 |
42 | // measure the second and third qubits non-destructively
43 | qc.measure(1, 1, false);
44 | qc.measure(2, 2, false);
45 |
46 | // display the quantum circuit and its corresponding resources
47 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
48 |
49 | // initialize the quantum engine with the circuit
50 | QEngine engine{qc};
51 |
52 | // execute the entire circuit once
53 | engine.execute();
54 |
55 | // display the measurement statistics
56 | std::cout << engine << "\n\n";
57 | // display the output quantum state
58 | std::cout << ">> Final state:\n";
59 | std::cout << disp(dirac(engine.get_state())) << '\n';
60 | }
61 |
--------------------------------------------------------------------------------
/examples/circuits/conditional_while.cpp:
--------------------------------------------------------------------------------
1 | // Conditional WHILE quantum circuit simulator
2 | // Source: ./examples/circuits/conditional_while.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Conditional WHILE quantum circuit simulator\n\n";
12 |
13 | // quantum circuit with 2 qubits and 2 classical bits
14 | QCircuit qc{3, 3};
15 |
16 | // define a boolean predicate of the required form
17 | // const_proxy_to_engine_dits_t -> bool
18 | auto pred = [](auto dits) {
19 | // returns true as long as the first two classical dits ARE NOT 1, 1
20 | return !(dits[0] == 1 && dits[1] == 1);
21 | };
22 |
23 | // conditional WHILE statement
24 | // keep preparing the first measuring the first 2 qubits non-destructively
25 | // until we obtain the result 1, 1
26 | qc.cond_while(pred);
27 | // curly braces are optional, used to force code indenting
28 | {
29 | qc.reset({0, 1}); // resets the first two qubits to the |00> state
30 | qc.gate_fan(gt.H, {0, 1}); // next, prepare them in the |++> state
31 | qc.measure({0, 1}, 0, false); // finally, measure them non-destructively
32 | } // keep repeating until both measurement results are 1, 1
33 | qc.cond_end();
34 |
35 | // the WHILE statement finished, flip the state of the third qubit
36 | qc.gate(gt.X, 2); // the final state will be |111>
37 | qc.measure(2, 2, false); // measure the third qubit non-destructively
38 |
39 | // display the quantum circuit and its corresponding resources
40 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
41 |
42 | // initialize the quantum engine with the circuit
43 | QEngine engine{qc};
44 |
45 | // execute the entire circuit once
46 | engine.execute();
47 |
48 | // display the measurement statistics
49 | std::cout << engine << "\n\n";
50 | // display the output quantum state
51 | std::cout << ">> Final state:\n";
52 | std::cout << disp(dirac(engine.get_state())) << '\n';
53 | }
54 |
--------------------------------------------------------------------------------
/examples/circuits/noisy_teleport_qubit_circuit.cpp:
--------------------------------------------------------------------------------
1 | // Qubit noisy teleportation quantum circuit simulator
2 | // Source: ./examples/circuits/noisy_teleport_qubit_circuit.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Qubit noisy teleportation quantum circuit simulation\n\n";
12 |
13 | // quantum circuit with 3 qubits and 2 classical bits
14 | QCircuit qc{3, 2};
15 | // set the qubit 0 to a random state
16 | cmat U = randU(2);
17 | // apply the gate U with name randU to qubit 0
18 | qc.gate(U, 0, "randU");
19 |
20 | // set the MES between qubits 1 and 2
21 | qc.gate(gt.H, 1);
22 | qc.CTRL(gt.X, 1, 2);
23 |
24 | // perform the Bell measurement between qubits 0 and 1
25 | qc.CTRL(gt.X, 0, 1);
26 | qc.gate(gt.H, 0);
27 | qc.measure({0, 1});
28 |
29 | // apply the classical controls
30 | qc.cCTRL(gt.X, 1, 2);
31 | qc.cCTRL(gt.Z, 0, 2);
32 |
33 | // display the quantum circuit and its corresponding resources
34 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
35 |
36 | // initialize the noisy quantum engine with an amplitude damping noise model
37 | // and a quantum circuit
38 | QNoisyEngine noisy_engine{qc, QubitAmplitudeDampingNoise{0.99}};
39 |
40 | // execute the entire circuit
41 | noisy_engine.execute();
42 |
43 | // display the measurement statistics
44 | std::cout << noisy_engine << "\n\n";
45 |
46 | // verify how successful the teleportation was
47 | ket psi_in = U * 0_ket;
48 | ket psi_out = noisy_engine.get_state();
49 | std::cout << ">> Initial state:\n";
50 | std::cout << disp(psi_in) << '\n';
51 | std::cout << ">> Teleported state:\n";
52 | std::cout << disp(psi_out) << '\n';
53 | std::cout << ">> Norm difference: " << norm(psi_out - psi_in) << '\n';
54 | }
55 |
--------------------------------------------------------------------------------
/examples/circuits/post_selection.cpp:
--------------------------------------------------------------------------------
1 | // Qubit post-selection quantum circuit simulator
2 | // Source: ./examples/circuits/post_selection.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Post-selection quantum circuit simulator\n\n";
12 |
13 | // quantum circuit with 2 qubits and 2 classical bits
14 | QCircuit qc{2, 2};
15 | // prepare equal superposition
16 | qc.gate_fan(gt.H);
17 | // post-select non-destructively all qubits on {1, 1}, and write the results
18 | // starting from the classical bit 0
19 | qc.post_select({0, 1}, {1, 1}, 0, false);
20 | // display the quantum circuit and its corresponding resources
21 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
22 |
23 | // initialize the quantum engine with the circuit
24 | QEngine engine{qc};
25 |
26 | // un-comment the line below to enforce post-selection, i.e., repeat
27 | // post-selection steps until success
28 | // engine.set_ensure_post_selection(true);
29 |
30 | // execute the entire circuit a few times
31 | engine.execute(1000); // we expect ~250 successful runs
32 |
33 | // display the measurement statistics
34 | std::cout << engine << "\n\n";
35 | // display the output quantum state
36 | std::cout << ">> Final state:\n";
37 | std::cout << disp(dirac(engine.get_state())) << '\n';
38 | }
39 |
--------------------------------------------------------------------------------
/examples/circuits/qpe_circuit.cpp:
--------------------------------------------------------------------------------
1 | // Quantum phase estimation quantum circuit simulator
2 | // Source: ./examples/circuits/qpe_circuit.cpp
3 | // See also ./examples/qpe.cpp for a low-level API example
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "qpp/qpp.hpp"
11 |
12 | int main() {
13 | using namespace qpp;
14 |
15 | idx nq_c = 4; // number of counting qubits
16 | idx nq_a = 2; // number of ancilla qubits
17 | idx nq = nq_c + nq_a; // total number of qubits
18 |
19 | std::cout << ">> Quantum phase estimation quantum circuit simulation\n";
20 | std::cout << ">> nq_c = " << nq_c << " counting qubits, nq_a = " << nq_a
21 | << " ancilla qubits\n\n";
22 |
23 | realT theta = 0.25; // change if you want, increase nq_c for more precision
24 | cmat U(2, 2); // initialize a unitary operator
25 | U << 1, 0, 0, std::exp(pi * 1_i * theta); // T gate
26 | // we use the T\otimes T gate as an example; we want to estimate its last
27 | // (4-th) eigenvalue; we expect estimated theta = 1/4 (0.25).
28 | U = kron(U, U); // OK, size will re-adjust since U is a dynamic Eigen matrix
29 |
30 | QCircuit qc{nq, nq_c};
31 | std::vector counting_qubits(nq_c);
32 | std::iota(counting_qubits.begin(), counting_qubits.end(), 0);
33 | std::vector ancilla(nq_a);
34 | std::iota(ancilla.begin(), ancilla.end(), nq_c);
35 |
36 | qc.gate_fan(gt.H, counting_qubits);
37 | qc.gate_fan(gt.X, ancilla); // prepare |11>, the fourth eigenvector of U
38 | for (idx i = nq_c; i-- > 0;) {
39 | qc.CTRL(U, i, ancilla);
40 | U = powm(U, 2);
41 | }
42 | qc.TFQ(counting_qubits); // inverse Fourier transform
43 | // measure many qubits at once, store starting with the 0 classical dit
44 | qc.measure(counting_qubits);
45 |
46 | // display the quantum circuit and its corresponding resources
47 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
48 |
49 | std::cout << ">> Running...\n";
50 | QEngine engine{qc};
51 | engine.execute();
52 | // decimal representation of the measurement result
53 | idx decimal = multiidx2n(engine.get_dits(), std::vector(nq_c, 2));
54 | auto theta_e =
55 | static_cast(decimal) / static_cast(std::pow(2, nq_c));
56 |
57 | std::cout << ">> Input theta = " << theta << '\n';
58 | std::cout << ">> Estimated theta = " << theta_e << '\n';
59 | std::cout << ">> Norm difference: " << std::abs(theta_e - theta) << '\n';
60 | }
61 |
--------------------------------------------------------------------------------
/examples/circuits/runtime_set_dits.cpp:
--------------------------------------------------------------------------------
1 | // Overwriting quantum engine dits at runtime quantum circuit simulator
2 | // Source: ./examples/circuits/runtime_set_dits.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Overwriting quantum engine dits at runtime quantum "
12 | "circuit simulator\n\n";
13 |
14 | // quantum circuit with 2 qubits and 2 classical bits
15 | QCircuit qc{1, 1};
16 | // prepare the first qubit in the |+> state
17 | qc.gate(gt.H, 0);
18 | // measure the first qubit non-destructively
19 | qc.measure(0, 0, false);
20 |
21 | // if the measurement result is 1
22 | qc.cond_if([](auto dits) { return dits[0] == 1; });
23 | // curly braces are optional, used to force code indenting
24 | {
25 | // define a functor of the required form proxy_to_engine_dits_t -> void
26 | auto functor = [](auto dits) { dits[0] = 100; };
27 |
28 | // runtime set dit statement
29 | // set the corresponding dit to 100, why not?
30 | qc.set_dits_runtime(functor);
31 | }
32 | qc.cond_end();
33 |
34 | // display the quantum circuit and its corresponding resources
35 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
36 |
37 | // initialize the quantum engine with the circuit
38 | QEngine engine{qc};
39 |
40 | // execute the entire circuit once
41 | engine.execute();
42 |
43 | // display the measurement statistics
44 | std::cout << engine << "\n\n";
45 | // display the output quantum state
46 | std::cout << ">> Final state:\n";
47 | std::cout << disp(dirac(engine.get_state())) << '\n';
48 | }
49 |
--------------------------------------------------------------------------------
/examples/circuits/teleport_qubit_circuit.cpp:
--------------------------------------------------------------------------------
1 | // Qubit teleportation quantum circuit simulator
2 | // Source: ./examples/circuits/teleport_qubit_circuit.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Qubit teleportation quantum circuit simulation\n\n";
12 |
13 | // quantum circuit with 3 qubits and 2 classical bits
14 | QCircuit qc{3, 2};
15 | // set the qubit 0 to a random state
16 | cmat U = randU(2);
17 | // apply the gate U with name randU to qubit 0
18 | qc.gate(U, 0, "randU");
19 |
20 | // set the MES between qubits 1 and 2
21 | qc.gate(gt.H, 1);
22 | qc.CTRL(gt.X, 1, 2);
23 |
24 | // perform the Bell measurement between qubits 0 and 1
25 | qc.CTRL(gt.X, 0, 1);
26 | qc.gate(gt.H, 0);
27 | qc.measure({0, 1});
28 |
29 | // apply the classical controls
30 | qc.cCTRL(gt.X, 1, 2);
31 | qc.cCTRL(gt.Z, 0, 2);
32 |
33 | // initialize the quantum engine with the circuit
34 | QEngine engine{qc};
35 |
36 | // display the quantum circuit and its corresponding resources
37 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
38 |
39 | // execute the entire circuit
40 | engine.execute();
41 |
42 | // display the measurement statistics
43 | std::cout << engine << "\n\n";
44 |
45 | // verify that the teleportation was successful
46 | ket psi_in = U * 0_ket;
47 | ket psi_out = engine.get_state();
48 | std::cout << ">> Teleported state:\n";
49 | std::cout << disp(dirac(psi_out)) << '\n';
50 | std::cout << ">> Norm difference: " << norm(psi_out - psi_in) << '\n';
51 | }
52 |
--------------------------------------------------------------------------------
/examples/circuits/teleport_qudit_circuit.cpp:
--------------------------------------------------------------------------------
1 | // Qudit teleportation quantum circuit simulator
2 | // Source: ./examples/circuits/teleport_qudit_circuit.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | idx d = 5; // qudit dimension
12 | std::cout << ">> Qudit teleportation (d = " << d << ") ";
13 | std::cout << "quantum circuit simulation\n\n";
14 |
15 | // quantum circuit with 3 qudits, 2 classical bits, (optional) dimension
16 | // d = 5 and (optional) name = "qudit teleportation"
17 | QCircuit qc{3, 2, d, "qudit teleportation"};
18 | // set the qubit 0 to a random state
19 | cmat U = randU(d);
20 | // apply the gate U to qubit 0
21 | qc.gate(U, 0);
22 |
23 | // set the MES between qudits 1 and 2
24 | qc.gate(gt.Fd(d), 1);
25 | qc.CTRL(gt.Xd(d), 1, 2);
26 |
27 | // perform the Bell measurement between qudits 0 and 1
28 | qc.CTRL(adjoint(gt.Xd(d)), 0, 1);
29 | qc.gate(adjoint(gt.Fd(d)), 0);
30 | qc.measure({0, 1});
31 |
32 | // apply the classical controls
33 | qc.cCTRL(adjoint(gt.Xd(d)), 1, 2);
34 | qc.cCTRL(gt.Zd(d), 0, 2);
35 |
36 | // display the quantum circuit and its corresponding resources
37 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
38 |
39 | // initialize the quantum engine with the circuit
40 | QEngine engine{qc};
41 |
42 | // execute the entire circuit
43 | engine.execute();
44 |
45 | // display the measurement statistics
46 | std::cout << engine << "\n\n";
47 |
48 | // verify that the teleportation was successful
49 | ket psi_in = U * mket({0}, d);
50 | ket psi_out = engine.get_state();
51 | std::cout << ">> Teleported state:\n";
52 | std::cout << disp(dirac(psi_out, d)) << '\n';
53 | std::cout << ">> Norm difference: " << norm(psi_out - psi_in) << '\n';
54 | }
55 |
--------------------------------------------------------------------------------
/examples/dense_coding.cpp:
--------------------------------------------------------------------------------
1 | // Qudit dense coding
2 | // Source: ./examples/dense_coding.cpp
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "qpp/qpp.hpp"
9 |
10 | int main() {
11 | using namespace qpp;
12 |
13 | idx d = 3; // size of the system
14 | std::cout << ">> Qudit dense coding, d = " << d << '\n';
15 |
16 | ket mes_AB = st.mes(d); // maximally entangled state resource
17 |
18 | // circuit that measures in the qudit Bell basis
19 | cmat Bell_AB =
20 | adjoint(gt.CTRL(gt.Xd(d), {0}, {1}, 2, d) * kron(gt.Fd(d), gt.Id(d)));
21 |
22 | // equal probabilities of choosing a message
23 | idx m_A = randidx(0, d * d - 1);
24 | std::vector midx = n2multiidx(m_A, {d, d});
25 | std::cout << ">> Alice sent: " << m_A << " -> ";
26 | std::cout << disp(midx, IOManipContainerOpts{}.set_sep(" ")) << '\n';
27 |
28 | // Alice's operation
29 | cmat U_A = powm(gt.Zd(d), midx[0]) * powm(adjoint(gt.Xd(d)), midx[1]);
30 |
31 | // Alice encodes the message
32 | ket psi_AB = apply(mes_AB, U_A, {0}, d);
33 |
34 | // Bob measures the joint system in the qudit Bell basis
35 | psi_AB = apply(psi_AB, Bell_AB, {0, 1}, d);
36 |
37 | auto measured = measure(psi_AB, gt.Id(d * d));
38 | std::cout << ">> Bob's measurement probabilities: ";
39 | std::cout << disp(std::get(measured),
40 | IOManipContainerOpts{}.set_sep(", "))
41 | << '\n';
42 |
43 | // Bob samples according to the measurement probabilities
44 | idx m_B = std::get(measured);
45 | std::cout << ">> Bob received: ";
46 | std::cout << m_B << " -> "
47 | << disp(n2multiidx(m_B, {d, d}),
48 | IOManipContainerOpts{}.set_sep(" "))
49 | << '\n';
50 | }
51 |
--------------------------------------------------------------------------------
/examples/entanglement.cpp:
--------------------------------------------------------------------------------
1 | // Entanglement
2 | // Source: ./examples/entanglement.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | cmat rho = 0.2 * st.pb00 + 0.8 * st.pb11;
12 | std::cout << ">> State rho:\n";
13 | std::cout << disp(rho) << '\n';
14 |
15 | std::cout << ">> Concurrence of rho: " << concurrence(rho) << '\n';
16 | std::cout << ">> Negativity of rho: " << negativity(rho, {2, 2}) << '\n';
17 | std::cout << ">> Logarithmic negativity of rho: "
18 | << lognegativity(rho, {2, 2}) << '\n';
19 |
20 | ket psi = 0.8 * 00_ket + 0.6 * 11_ket;
21 |
22 | // apply some local random unitaries
23 | psi = kron(randU(), randU()) * psi;
24 |
25 | std::cout << ">> State psi:\n";
26 | std::cout << disp(psi) << '\n';
27 |
28 | std::cout << ">> Entanglement of psi: " << entanglement(psi, {2, 2})
29 | << '\n';
30 | std::cout << ">> Concurrence of psi: " << concurrence(prj(psi)) << '\n';
31 | std::cout << ">> G-Concurrence of psi: " << gconcurrence(psi) << '\n';
32 |
33 | std::cout << ">> Schmidt coefficients of psi:\n";
34 | std::cout << disp(schmidtcoeffs(psi, {2, 2})) << '\n';
35 |
36 | std::cout << ">> Schmidt probabilities of psi:\n";
37 | std::cout << disp(schmidtprobs(psi, {2, 2}),
38 | IOManipContainerOpts{}.set_sep(", "))
39 | << '\n';
40 |
41 | cmat UA = schmidtA(psi, {2, 2});
42 | cmat UB = schmidtB(psi, {2, 2});
43 |
44 | std::cout << ">> Schmidt vectors on Alice's side:\n";
45 | std::cout << disp(UA) << '\n';
46 |
47 | std::cout << ">> Schmidt vectors on Bob's side:\n";
48 | std::cout << disp(UB) << '\n';
49 |
50 | std::cout << ">> State psi in the Schmidt basis:\n";
51 | std::cout << disp(adjoint(kron(UA, UB)) * psi) << '\n';
52 |
53 | // reconstructed state
54 | ket psi_from_schmidt =
55 | schmidtcoeffs(psi, {2, 2})(0) * kron(UA.col(0), UB.col(0)) +
56 | schmidtcoeffs(psi, {2, 2})(1) * kron(UA.col(1), UB.col(1));
57 | std::cout << ">> State psi reconstructed from the Schmidt decomposition:\n";
58 | std::cout << disp(psi_from_schmidt) << '\n';
59 |
60 | // verification
61 | std::cout << ">> Norm difference: " << norm(psi - psi_from_schmidt) << '\n';
62 | }
63 |
--------------------------------------------------------------------------------
/examples/entropies.cpp:
--------------------------------------------------------------------------------
1 | // Entropies
2 | // Source: ./examples/entropies.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | cmat rho = st.pb00;
12 | cmat rhoA = ptrace(rho, {1});
13 | std::cout << ">> State:\n" << disp(rho) << '\n';
14 | std::cout << ">> Partial trace over B:\n" << disp(rhoA) << '\n';
15 | std::cout << ">> von-Neumann entropy: " << entropy(rhoA) << '\n';
16 | std::cout << ">> Renyi-0 (Hmax) entropy: " << renyi(rhoA, 0) << '\n';
17 | std::cout << ">> Renyi-1 entropy: " << renyi(rhoA, 1) << '\n';
18 | std::cout << ">> Renyi-2 entropy: " << renyi(rhoA, 2) << '\n';
19 | std::cout << ">> Renyi-inf (Hmin) entropy: " << renyi(rhoA, infty) << '\n';
20 | std::cout << ">> Tsallis-1 entropy: " << tsallis(rhoA, 1) << '\n';
21 | std::cout << ">> Tsallis-2 entropy: " << tsallis(rhoA, 2) << '\n';
22 | std::cout << ">> Quantum mutual information between A and B: "
23 | << qmutualinfo(rho, {0}, {1}) << '\n';
24 | std::cout << ">> Quantum mutual information between A and A: "
25 | << qmutualinfo(rho, {0}, {0}) << '\n';
26 | std::cout << ">> Quantum mutual information between B and B: "
27 | << qmutualinfo(rho, {1}, {1}) << '\n';
28 | }
29 |
--------------------------------------------------------------------------------
/examples/exceptions.cpp:
--------------------------------------------------------------------------------
1 | // Exceptions
2 | // Source: ./examples/exceptions.cpp
3 |
4 | #include
5 | #include
6 |
7 | #include "qpp/qpp.hpp"
8 |
9 | int main() {
10 | using namespace qpp;
11 |
12 | cmat rho = randrho(16); // 4 qubits (subsystems)
13 | try {
14 | // the line below throws qpp::exception::SubsysMismatchDims
15 | realT mInfo = qmutualinfo(rho, {0}, {4});
16 | std::cout << ">> Mutual information between first and last subsystem: ";
17 | std::cout << mInfo << '\n';
18 | } catch (const std::exception& e) {
19 | std::cout << ">> Exception caught: " << e.what() << '\n';
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/examples/experimental_average.cpp:
--------------------------------------------------------------------------------
1 | // Experimental average
2 | // Source: ./examples/experimental_average.cpp
3 |
4 | #include
5 | #include
6 |
7 | #include "qpp/qpp.hpp"
8 |
9 | int main() {
10 | using namespace qpp;
11 |
12 | ket psi = 0_ket; // same as st.z0;
13 | cmat X = gt.X;
14 | dyn_col_vect evals = hevals(X);
15 | cmat evects = hevects(X);
16 |
17 | long res = 0;
18 | idx N = 10000; // number of "measurement experiments"
19 | for (idx i = 0; i < N; ++i) {
20 | auto measured = measure(psi, evects);
21 | idx m = std::get(measured); // measurement result
22 | if (evals[m] < 0) {
23 | --res; // -1
24 | } else {
25 | ++res; // +1
26 | }
27 | }
28 | std::cout << ">> N = " << N << " measurements\n";
29 | std::cout << ">> The experimental average of the observable X\n";
30 | std::cout << disp(X) << '\n';
31 | std::cout << "on the state psi\n";
32 | std::cout << disp(psi) << '\n';
33 | std::cout << "is: " << static_cast(res) / static_cast(N)
34 | << '\n';
35 | std::cout << ">> Theoretical average = ";
36 | std::cout << disp((adjoint(psi) * X * psi).value()) << '\n';
37 | }
38 |
--------------------------------------------------------------------------------
/examples/functor.cpp:
--------------------------------------------------------------------------------
1 | // Functor
2 | // Source: ./examples/functor.cpp
3 |
4 | #include
5 | #include
6 |
7 | #include "qpp/qpp.hpp"
8 |
9 | // test function used by qpp::cwise()
10 | qpp::cplx pow3(qpp::cplx z) { return static_cast(std::pow(z, 3)); }
11 |
12 | int main() {
13 | using namespace qpp;
14 |
15 | // functor test
16 | std::cout << ">> Functor z^3 acting component-wise on:\n";
17 | cmat A(2, 2);
18 | A << 1, 2, 3, 4;
19 | std::cout << disp(A) << '\n';
20 |
21 | std::cout << ">> Result (with lambda):\n";
22 | auto lambda = [](cplx z) -> cplx { return z * z * z; };
23 | // functor z^3 component-wise, you must specify both template arguments
24 | // OutputScalar and Derived (Eigen expression input type) for lambdas passed
25 | // to qpp::cwise()
26 | std::cout << disp(cwise(A, lambda)) << '\n';
27 |
28 | std::cout << ">> Result (with genuine function):\n";
29 | // automatic type deduction for proper functions
30 | std::cout << disp(cwise(A, &pow3)) << '\n';
31 | }
32 |
--------------------------------------------------------------------------------
/examples/gates_states.cpp:
--------------------------------------------------------------------------------
1 | // Gates and states
2 | // Source: ./examples/gates_states.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | ket psi = 0_ket; // |0> state
12 | cmat U = gt.X;
13 | ket result = U * psi;
14 |
15 | std::cout << ">> The result of applying the bit-flip gate X on |0> is:\n";
16 | std::cout << disp(result) << '\n';
17 |
18 | psi = 10_ket; // |10> state
19 | U = gt.CNOT; // Controlled-NOT
20 | result = U * psi;
21 |
22 | std::cout << ">> The result of applying the gate CNOT on |10> is:\n";
23 | std::cout << disp(result) << '\n';
24 |
25 | U = randU();
26 | std::cout << ">> Generating a random one-qubit gate U:\n";
27 | std::cout << disp(U) << '\n';
28 |
29 | result = applyCTRL(psi, U, {0}, {1}); // Controlled-U
30 | std::cout << ">> The result of applying the CTRL-U gate on |10> is:\n";
31 | std::cout << disp(result) << '\n';
32 | }
33 |
--------------------------------------------------------------------------------
/examples/gram_schmidt.cpp:
--------------------------------------------------------------------------------
1 | // Gram-Schmidt orthogonalization
2 | // Source: ./examples/gram_schmidt.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | cmat A(3, 3);
12 | A << 1, 1, 0, 0, 2, 0, 0, 0, 0;
13 | std::cout << ">> Input matrix:\n" << disp(A) << '\n';
14 |
15 | cmat Ags = grams(A);
16 | std::cout << ">> Result:\n" << disp(Ags) << '\n';
17 |
18 | std::cout << ">> Projector onto G.S. vectors:\n";
19 | std::cout << disp(Ags * adjoint(Ags)) << '\n';
20 | }
21 |
--------------------------------------------------------------------------------
/examples/graph_states.cpp:
--------------------------------------------------------------------------------
1 | // Graph states
2 | // Source: ./examples/graph_states.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | // adjacency matrix, triangle graph (LU equivalent to a GHZ state)
12 | idx Gamma[3][3] = {{0, 1, 1}, {1, 0, 1}, {1, 1, 0}};
13 |
14 | // start with 2 states in |000>
15 | ket G0 = 000_ket;
16 | ket G1 = 000_ket;
17 |
18 | // and their density matrices
19 | cmat rhoG0 = prj(G0);
20 | cmat rhoG1 = prj(G1);
21 |
22 | // then construct the graph state via 2 methods:
23 | // qpp::apply() and qpp::applyCTRL()
24 | // result should be the same, we check later
25 | cmat H3 = kronpow(gt.H, 3); // all |+>
26 | G0 = (H3 * G0).eval();
27 | G1 = G0;
28 | rhoG0 = (H3 * rhoG0 * adjoint(H3)).eval();
29 | rhoG1 = rhoG0;
30 | // apply pairwise Control-Phases
31 | for (idx i = 0; i < 3; ++i) {
32 | for (idx j = i + 1; j < 3; ++j) {
33 | if (Gamma[i][j]) {
34 | G0 = apply(G0, gt.CZ, {i, j});
35 | G1 = applyCTRL(G1, gt.Z, {i}, {j});
36 | rhoG0 = apply(rhoG0, gt.CZ, {i, j});
37 | rhoG1 = applyCTRL(rhoG1, gt.Z, {i}, {j});
38 | }
39 | }
40 | }
41 | // end construction
42 |
43 | std::cout << ">> Resulting graph states:\n";
44 | std::cout << disp(G0) << "\n\n";
45 | std::cout << disp(G1) << '\n';
46 | // verification
47 | std::cout << ">> Norm difference: " << norm(G0 - G1) << '\n';
48 |
49 | // check the corresponding density matrices
50 | std::cout << ">> Resulting density matrices:\n";
51 | std::cout << disp(rhoG0) << "\n\n";
52 | std::cout << disp(rhoG1) << '\n';
53 | std::cout << ">> Norm difference: " << norm(rhoG0 - rhoG1) << '\n';
54 |
55 | // check the X-Z rule
56 | // applying X to a vertex is equivalent to applying Z to its neighbors
57 | ket G0X0 = apply(G0, gt.X, {0});
58 | cmat rhoG0X0 = apply(rhoG0, gt.X, {0});
59 | ket G0Z1Z2 = apply(G0, kron(gt.Z, gt.Z), {1, 2});
60 | cmat rhoG0Z1Z2 = apply(rhoG0, kron(gt.Z, gt.Z), {1, 2});
61 |
62 | // verification
63 | std::cout << ">> Checking the X-Z rule\n";
64 | std::cout << ">> X-Z rule. Norm difference for the kets: ";
65 | std::cout << norm(G0X0 - G0Z1Z2) << '\n';
66 | std::cout << ">> X-Z rule. Norm difference for the corresponding "
67 | << "density matrices: ";
68 | std::cout << norm(rhoG0X0 - rhoG0Z1Z2) << '\n';
69 | }
70 |
--------------------------------------------------------------------------------
/examples/grover.cpp:
--------------------------------------------------------------------------------
1 | // Grover's searching
2 | // Source: ./examples/grover.cpp
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "qpp/qpp.hpp"
11 |
12 | int main() {
13 | using namespace qpp;
14 |
15 | idx n = 10; // number of qubits
16 | std::cout << ">> Grover on n = " << n << " qubits\n";
17 |
18 | std::vector dims(n, 2); // local dimensions
19 | std::vector subsys(n); // ordered subsystems
20 | std::iota(std::begin(subsys), std::end(subsys), 0);
21 |
22 | // number of elements in the database
23 | auto N = static_cast(std::llround(std::pow(2, n)));
24 | std::cout << ">> Database size: " << N << '\n';
25 |
26 | // mark an element randomly
27 | idx marked = randidx(0, N - 1);
28 | std::cout << ">> Marked state: " << marked << " -> ";
29 | std::cout << disp(n2multiidx(marked, dims),
30 | IOManipContainerOpts{}.set_sep(" "))
31 | << '\n';
32 |
33 | ket psi = mket(std::vector(n, 0)); // computational |0>^\otimes n
34 |
35 | // apply H^\otimes n, no aliasing
36 | psi = (kronpow(gt.H, n) * psi).eval();
37 |
38 | cmat G = 2 * prj(psi) - gt.Id(N); // Diffusion operator
39 |
40 | Timer<> t;
41 |
42 | // number of queries
43 | auto nqueries = static_cast(std::ceil(pi / 4 * std::sqrt(N)));
44 | std::cout << ">> We run " << nqueries << " queries\n";
45 | for (idx i = 0; i < nqueries; ++i) {
46 | psi(marked) = -psi(marked); // apply the oracle first, no aliasing
47 | psi = (G * psi).eval(); // then the diffusion operator, no aliasing
48 | }
49 |
50 | // we now measure the state in the computational basis, destructively
51 | auto measured = measure_seq(psi, subsys, dims);
52 | std::cout << ">> Probability of the marked state: "
53 | << prod(std::get(measured)) << '\n';
54 |
55 | // sample
56 | std::cout << ">> Let's sample...\n";
57 | auto result = std::get(measured);
58 | if (result == n2multiidx(marked, dims)) {
59 | std::cout << ">> Hooray, we obtained the correct result: ";
60 | } else {
61 | std::cout << ">> Not there yet... we obtained: ";
62 | }
63 | std::cout << multiidx2n(result, dims) << " -> ";
64 | std::cout << disp(result, IOManipContainerOpts{}.set_sep(" ")) << '\n';
65 |
66 | std::cout << ">> Run time: " << t.toc() << " seconds\n";
67 | }
68 |
--------------------------------------------------------------------------------
/examples/input_output.cpp:
--------------------------------------------------------------------------------
1 | // Input/output
2 | // Source: ./examples/input_output.cpp
3 |
4 | #include
5 | #include
6 |
7 | #include "qpp/qpp.hpp"
8 |
9 | int main() {
10 | using namespace qpp;
11 |
12 | // Quantum++ input/output
13 | cmat rho = randrho(256); // an 8 qubit density operator
14 | {
15 | std::ofstream fout("rho.txt");
16 | save(rho, fout); // save it
17 | }
18 | std::ifstream fin("rho.txt");
19 | cmat loaded_rho = load(fin); // load it back
20 | // display the difference in norm, should be 0
21 | std::cout << ">> Norm difference load/save: ";
22 | std::cout << norm(loaded_rho - rho) << '\n';
23 | }
24 |
--------------------------------------------------------------------------------
/examples/layouts.cpp:
--------------------------------------------------------------------------------
1 | // Various physical layouts
2 | // Source: ./examples/layouts.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Various physical qudit layouts\n";
12 |
13 | // a 2 x 2 x 2 orthogonal lattice
14 | auto lattice = Lattice{2, 2, 2};
15 | // a 2 x 2 x 2 periodic boundary orthogonal lattice
16 | auto periodic_boundary_lattice = PeriodicBoundaryLattice{2, 2, 2};
17 |
18 | std::cout << ">> The (1, 1, 1) coordinate in an orthogonal lattice of "
19 | "dimensions ";
20 | std::cout << disp(lattice.get_dims(), IOManipContainerOpts{}.set_sep(", "))
21 | << " is:\n";
22 | std::cout << lattice(1, 1, 1) << '\n';
23 |
24 | std::cout << ">> The index " << lattice(1, 1, 1)
25 | << " in an orthogonal lattice of dimensions ";
26 | std::cout << disp(lattice.get_dims(), IOManipContainerOpts{}.set_sep(", "))
27 | << " maps to:\n";
28 | std::cout
29 | << disp(lattice.to_coordinates(lattice(1, 1, 1)),
30 | IOManipContainerOpts{}.set_sep(", ").set_left("(").set_right(
31 | ")"))
32 | << '\n';
33 |
34 | std::cout << ">> The (2, 2, 3) coordinate in a periodic boundary "
35 | "orthogonal lattice of dimensions ";
36 | std::cout << disp(periodic_boundary_lattice.get_dims(),
37 | IOManipContainerOpts{}.set_sep(", "))
38 | << " is:\n";
39 | std::cout << periodic_boundary_lattice(3, 3, 4) << '\n';
40 | }
41 |
--------------------------------------------------------------------------------
/examples/matlab_io.cpp:
--------------------------------------------------------------------------------
1 | // MATLAB input/output
2 | // Source: ./examples/matlab_io.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | #include "qpp/MATLAB/matlab.hpp" // must be explicitly included
9 |
10 | int main() {
11 | using namespace qpp;
12 |
13 | // interfacing with MATLAB
14 | cmat rho = randrho(256); // an 8 qubit density operator
15 | save_MATLAB(rho, "rho.mat", "rho", "w");
16 | cmat loaded_rho = load_MATLAB("rho.mat", "rho");
17 | // display the difference in norm, should be 0
18 | std::cout << ">> Norm difference MATLAB load/save: ";
19 | std::cout << norm(loaded_rho - rho) << '\n';
20 | }
21 |
--------------------------------------------------------------------------------
/examples/measurements1.cpp:
--------------------------------------------------------------------------------
1 | // Measurements
2 | // Source: ./examples/measurements1.cpp
3 |
4 | #include
5 | #include
6 |
7 | #include "qpp/qpp.hpp"
8 |
9 | int main() {
10 | using namespace qpp;
11 |
12 | ket psi = 00_ket;
13 | cmat U = gt.CNOT * kron(gt.H, gt.Id2);
14 | ket result = U * psi; // we have the Bell state (|00> + |11>) / sqrt(2)
15 |
16 | std::cout << ">> We just produced the Bell state:\n";
17 | std::cout << disp(result) << '\n';
18 |
19 | // apply a bit flip on the second qubit
20 | result = apply(result, gt.X, {1}); // we produced (|01> + |10>) / sqrt(2)
21 | std::cout << ">> We produced the Bell state:\n";
22 | std::cout << disp(result) << '\n';
23 |
24 | // measure the first qubit in the X basis
25 | auto [m, probs, states] = measure(result, gt.H, {0});
26 | std::cout << ">> Measurement result: " << m << '\n';
27 | std::cout << ">> Probabilities: ";
28 | std::cout << disp(probs, IOManipContainerOpts{}.set_sep(", ")) << '\n';
29 | std::cout << ">> Resulting states:\n";
30 | for (auto&& elem : states) {
31 | std::cout << disp(elem) << "\n\n";
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/examples/minimal.cpp:
--------------------------------------------------------------------------------
1 | // Minimal example
2 | // Source: ./examples/minimal.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << "Hello Quantum++!\nThis is the |0> state:\n";
12 | std::cout << disp(0_ket) << '\n';
13 |
14 | std::cout << "This is some random ket in Dirac notation\n";
15 | std::cout << disp(dirac(randket(2)), IOManipDiracOpts{}.set_plus_op(" + "));
16 | std::cout << std::endl;
17 | }
18 |
--------------------------------------------------------------------------------
/examples/noise.cpp:
--------------------------------------------------------------------------------
1 | // Quantum noise
2 | // Source: ./examples/noise.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Depolarizing qubit noise acting on a random state\n";
12 | realT p = 0.75; // depolarizing probability (fully depolarizing)
13 | idx N = 10000; // number of trials
14 | ket psi = randket(); // initial state
15 | cmat rho = cmat::Zero(2, 2); // final density matrix
16 | QubitDepolarizingNoise noise{0.75}; // constructs a noise instance
17 | // compute the noise action; see qpp::NoiseBase::operator() for other
18 | // overloads for multi-partite states
19 | for (idx i = 0; i < N; ++i) {
20 | // apply the noise
21 | rho += prj(noise(psi));
22 | }
23 | rho /= static_cast(N); // normalize the resulting density matrix
24 | std::cout << ">> Resulting state after " << N
25 | << " actions of depolarizing noise with p = " << p << ":\n";
26 | std::cout << disp(rho) << '\n';
27 | }
28 |
--------------------------------------------------------------------------------
/examples/qasm/bell.qasm:
--------------------------------------------------------------------------------
1 | // measuring the (|00>+|11>)/sqrt(2) Bell state, run it, e.g., with
2 | // 'qpp_qasm < bell.qasm 1000'
3 | OPENQASM 2.0;
4 | include "qelib1.inc";
5 |
6 | qreg q[2];
7 | creg c[2];
8 |
9 | h q[0];
10 | cx q[0],q[1];
11 |
12 | measure q[0] -> c[0];
13 | measure q[1] -> c[1];
14 |
--------------------------------------------------------------------------------
/examples/qasm/coin_flip.qasm:
--------------------------------------------------------------------------------
1 | // simple coin flipping, run it, e.g., with 'qpp_qasm < coin_flip.qasm 1000'
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 |
5 | qreg q[1];
6 | creg c[1];
7 |
8 | h q[0];
9 | measure q[0] -> c[0];
10 |
--------------------------------------------------------------------------------
/examples/qasm/qpp_qasm.cpp:
--------------------------------------------------------------------------------
1 | // Executes an OpenQASM program read from the input stream, repeatedly if the
2 | // number of repetitions is passed as the first argument. If there is a second
3 | // argument (i.e., argc == 3), then the final quantum state is displayed. If
4 | // there are three or more arguments (i.e., argc > 3), then the projector onto
5 | // the final state is displayed.
6 | // Source: ./examples/qasm/qpp_qasm.cpp
7 |
8 | #include
9 |
10 | #include "qpp/qpp.hpp"
11 |
12 | int main(int argc, char** argv) {
13 | using namespace qpp;
14 |
15 | // read the circuit from the input stream
16 | QCircuit qc = qasm::read(std::cin);
17 |
18 | // initialize the quantum engine with the circuit
19 | QEngine q_engine{qc};
20 |
21 | // display the quantum circuit and its corresponding resources
22 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
23 |
24 | // execute the quantum circuit
25 | idx reps = argc > 1 ? std::stoi(argv[1]) : 1; // repetitions
26 | q_engine.execute(reps);
27 |
28 | // display the measurement statistics
29 | std::cout << q_engine << '\n';
30 |
31 | // display the final state on demand
32 | if (argc == 3) {
33 | std::cout << ">> Final state:\n";
34 | std::cout << disp(dirac(q_engine.get_state())) << '\n';
35 | } else if (argc > 3) {
36 | std::cout << ">> Final density operator:\n";
37 | std::cout << disp(dirac(prj(q_engine.get_state()))) << '\n';
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/qasm/teleport_minimal.qasm:
--------------------------------------------------------------------------------
1 | // quantum teleportation minimal example
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 |
5 | // declarations, 3 qubits, 2 classical bits
6 | qreg q[3];
7 | creg c0[1];
8 | creg c1[1];
9 |
10 | // initial state
11 | u3(0.3,0.2,0.1) q[0];
12 |
13 | // teleportation circuit
14 | h q[1];
15 | cx q[1],q[2];
16 | barrier q;
17 | cx q[0],q[1];
18 | h q[0];
19 |
20 | // measurements (non-destructive)
21 | measure q[0] -> c0[0];
22 | measure q[1] -> c1[0];
23 |
24 | // classically controlled corrections
25 | if(c1==1) x q[2];
26 | if(c0==1) z q[2];
27 |
28 | // u3 adjoint, final expected state should be |0>
29 | // u3^\dagger(a,b,c) = u3(-a,-c,-b)
30 | u3(-0.3,-0.1,-0.2) q[2]
31 |
--------------------------------------------------------------------------------
/examples/qasm/teleport_minimal_qasm.cpp:
--------------------------------------------------------------------------------
1 | // Minimal teleportation OpenQASM example
2 | // Source: ./examples/qasm/teleport_minimal_qasm.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | // create a qpp::QCircuit from a QASM file
12 | QCircuit qc = qasm::read_from_file(PROJECT_ROOT_DIR
13 | "/examples/qasm/teleport_minimal.qasm");
14 |
15 | // we could have also used a C++ standard stream from , like below
16 | // std::ifstream ifs{PROJECT_ROOT_DIR
17 | // "/examples/qasm/teleport_minimal.qasm"};
18 | // QCircuit qc = qasm::read(ifs);
19 |
20 | // note that QASM measurements are non-destructive, so the final state after
21 | // this step when executed on an engine will be a state of 3 qubits; this is
22 | // why we discard the first two qubits in the next line
23 | qc.discard({0, 1});
24 |
25 | // display the quantum circuit and its corresponding resources
26 | // use qc.to_JSON() for JSON output
27 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
28 |
29 | QEngine q_engine{qc}; // create an engine out of a quantum circuit
30 |
31 | // execute the quantum circuit
32 | q_engine.execute();
33 |
34 | // display the measurement statistics
35 | // use q_engine.to_JSON() for JSON output
36 | std::cout << q_engine << '\n';
37 |
38 | // displays the final output state
39 | std::cout << ">> Final state:\n";
40 | std::cout << disp(q_engine.get_state()) << '\n';
41 | }
42 |
--------------------------------------------------------------------------------
/examples/qecc.cpp:
--------------------------------------------------------------------------------
1 | // Quantum error correcting codes
2 | // Source: ./examples/qecc.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | ket a0 = Codes::codeword(Codes::Type::FIVE_QUBIT, 0);
12 | ket a1 = Codes::codeword(Codes::Type::FIVE_QUBIT, 1);
13 |
14 | ket b0 = Codes::codeword(Codes::Type::STEANE_SEVEN_QUBIT, 0);
15 | ket b1 = Codes::codeword(Codes::Type::STEANE_SEVEN_QUBIT, 1);
16 |
17 | ket c0 = Codes::codeword(Codes::Type::SHOR_NINE_QUBIT, 0);
18 | ket c1 = Codes::codeword(Codes::Type::SHOR_NINE_QUBIT, 1);
19 |
20 | std::cout << ">> [[5, 1, 3]] Five qubit code.\n";
21 | std::cout << ">> Checking codeword orthogonality.\n";
22 | std::cout << ">> |<0L|1L>| = ";
23 | std::cout << disp(adjoint(a0) * a1) << '\n';
24 |
25 | std::cout << ">> [[7, 1, 3]] Seven qubit Steane code.\n";
26 | std::cout << ">> Checking codeword orthogonality.\n";
27 | std::cout << ">> |<0L|1L>| = ";
28 | std::cout << disp(adjoint(b0) * b1) << '\n';
29 |
30 | std::cout << ">> [[9, 1, 3]] Nine qubit Shor code.\n";
31 | std::cout << ">> Checking codeword orthogonality.\n";
32 | std::cout << ">> |<0L|1L>| = ";
33 | std::cout << disp(adjoint(c0) * c1) << '\n';
34 | }
35 |
--------------------------------------------------------------------------------
/examples/qft.cpp:
--------------------------------------------------------------------------------
1 | // Quantum Fourier transform
2 | // Source: ./examples/qft.cpp
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "qpp/qpp.hpp"
9 |
10 | int main() {
11 | using namespace qpp;
12 |
13 | std::vector qubits{1, 0, 1, 1, 0}; // initial state
14 | ket psi = mket(qubits);
15 | ket result = psi;
16 |
17 | idx n = qubits.size(); // number of qubits
18 | auto D = static_cast(std::llround(std::pow(2, n))); // dimension 2^n
19 | std::cout << ">> QFT on n = " << n << " qubits. ";
20 |
21 | std::cout << "The sequence of applied gates is:\n";
22 | for (idx i = 0; i < n; ++i) {
23 | std::cout << "H" << i << " ";
24 | result = apply(result, gt.H, {i}); // apply Hadamard on qubit 'i'
25 | // apply controlled rotations
26 | for (idx j = 2; j <= n - i; ++j) {
27 | cmat Rj(2, 2);
28 | auto pow_j = static_cast(std::llround(std::pow(2, j)));
29 | Rj << 1, 0, 0, omega(pow_j);
30 | result = applyCTRL(result, Rj, {static_cast(i + j - 1)},
31 | {static_cast(i)});
32 | std::cout << "R" << j << "(" << i + j - 1 << ", " << i << ") ";
33 | }
34 | std::cout << '\n';
35 | }
36 |
37 | // we have the qubits in reversed order, we must swap them
38 | for (idx i = 0; i < n / 2; ++i) {
39 | std::cout << "SWAP(" << i << ", " << n - i - 1 << ")\n";
40 | result = apply(result, gt.SWAP, {i, static_cast(n - i - 1)});
41 | }
42 |
43 | // check that we got the Fourier transform, compute the norm difference
44 | if (n < 14) { // otherwise, not enough memory for computing gt.Fd(D) * psi
45 | std::cout << ">> Norm difference: " << norm(result - gt.Fd(D) * psi)
46 | << '\n';
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/examples/qpe.cpp:
--------------------------------------------------------------------------------
1 | // Quantum phase estimation
2 | // Source: ./examples/qpe.cpp
3 | // See also ./examples/circuits/qpe_circuit.cpp for a high-level API example
4 | // (with a 2-qubit target unitary!)
5 |
6 | /*
7 | A program to construct the following quantum phase estimator circuit and
8 | execute simulation on the phase of U = diag(1, e^{2*pi*i*theta}).
9 |
10 | |0> ----H--------------@----x-------------------R3+--R2+--H----|D---- [q0]
11 | | | | |
12 | |0> ----H---------@----+----+---------R2+--H----+----@---------|D---- [q1]
13 | | | | | |
14 | |0> ----H----@----+----+----x----H----@---------@--------------|D---- [q2]
15 | | | |
16 | |0> ----X----U----U^2--U^4------------------------------------------- [q3]
17 |
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include "qpp/qpp.hpp"
27 |
28 | int main() {
29 | using namespace qpp;
30 |
31 | idx nq_c = 3; // number of counting qubits
32 | idx nq_a = 1; // number of ancilla qubits
33 | idx nq = nq_c + nq_a; // total number of qubits
34 | ket psi = mket(std::vector(nq, 0)); // |0>^\otimes n
35 |
36 | cmat U(2, 2); // initialize a unitary operator
37 | // we use the T gate as an example; we expect estimated theta = 1/8 (0.125).
38 | realT theta = 0.125; // change if you want, increase n for more precision
39 | U << 1, 0, 0, std::exp(2 * pi * 1_i * theta);
40 |
41 | ket result = psi;
42 | std::vector counting_qubits(nq_c);
43 | std::iota(counting_qubits.begin(), counting_qubits.end(), 0);
44 | std::vector ancilla(nq_a);
45 | std::iota(ancilla.begin(), ancilla.end(), nq_c);
46 |
47 | std::cout << ">> QPE on nq_c = " << nq_c
48 | << " counting qubits, nq_a = " << nq_a << " ancilla qubits\n";
49 |
50 | std::cout << ">> The sequence of applied gates is:\n";
51 | for (idx i = 0; i < static_cast(counting_qubits.size()); ++i) {
52 | // apply Hadamard on counting qubits
53 | result = apply(result, gt.H, {i});
54 | std::cout << "H" << i << " ";
55 | }
56 | // prepare |1>, the second eigenvector of U
57 | result = apply(result, gt.X, ancilla);
58 | std::cout << "X" << disp(ancilla, IOManipContainerOpts{}.set_sep(","))
59 | << '\n';
60 |
61 | // apply controlled unitary operations
62 | idx powerU = 1;
63 | for (idx i = 0; i < nq_c; ++i) {
64 | std::cout << "CU(" << nq_c - i - 1 << ", "
65 | << disp(ancilla, IOManipContainerOpts{}.set_sep(", ")) << ")^"
66 | << powerU << '\n';
67 | result =
68 | applyCTRL(result, U, {static_cast(nq_c - i - 1)}, ancilla);
69 | U = powm(U, 2);
70 | powerU *= 2;
71 | }
72 |
73 | // apply inverse quantum Fourier transform to convert state of the counting
74 | // register
75 | result = applyTFQ(result, counting_qubits);
76 | std::cout
77 | << "QFT^{-1}"
78 | << disp(counting_qubits,
79 | IOManipContainerOpts{}.set_sep(", ").set_left("(").set_right(
80 | ")"))
81 | << '\n';
82 |
83 | // measure the counting register and readout probabilities
84 | auto measured = measure_seq(result, {counting_qubits});
85 | auto res = std::get(measured);
86 | std::cout << ">> Measurement result [q0 q1 ... ]: "
87 | << disp(res, IOManipContainerOpts{}.set_sep(" "));
88 | std::cout << '\n';
89 |
90 | // decimal representation of the measurement result
91 | idx decimal = multiidx2n(res, std::vector(counting_qubits.size(), 2));
92 |
93 | // readout phase estimate
94 | auto theta_e =
95 | static_cast(decimal) / static_cast(std::pow(2, nq_c));
96 | std::cout << ">> Input theta = " << theta << '\n';
97 | std::cout << ">> Estimated theta = " << theta_e << '\n';
98 | std::cout << ">> Norm difference: " << std::abs(theta_e - theta) << '\n';
99 | }
100 |
--------------------------------------------------------------------------------
/examples/qram.cpp:
--------------------------------------------------------------------------------
1 | // Quantumly-accessible Random Access Memory over classical data
2 | // Source: ./examples/qram.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> qRAM over classical data\n";
12 |
13 | ket in = st.x0; // |+> input state
14 | qram data{0, 1}; // qRAM data
15 | std::cout << ">> qRAM input:\n" << disp(in) << '\n';
16 | std::cout << ">> Classical data:\n"
17 | << disp(data, IOManipContainerOpts{}.set_sep(", ")) << '\n';
18 | ket out = qRAM(in, data); // qRAM output, automatically sets the dimension
19 | // of the qRAM subsystem to 2
20 | std::cout << ">> qRAM output:\n" << disp(out) << '\n';
21 | }
22 |
--------------------------------------------------------------------------------
/examples/quantum_operations.cpp:
--------------------------------------------------------------------------------
1 | // Quantum operations
2 | // Source: ./examples/quantum_operations.cpp
3 |
4 | #include
5 | #include
6 |
7 | #include "qpp/qpp.hpp"
8 |
9 | int main() {
10 | using namespace qpp;
11 |
12 | cmat rho = st.pb00; // projector onto the Bell state (|00> + |11>) / sqrt(2)
13 | std::cout << ">> Initial state:\n";
14 | std::cout << disp(rho) << '\n';
15 |
16 | // partial transpose of first subsystem
17 | cmat rhoTA = ptranspose(rho, {0});
18 | std::cout << ">> Eigenvalues of the partial transpose "
19 | << "of Bell-0 state are:\n";
20 | std::cout << disp(transpose(hevals(rhoTA))) << '\n';
21 |
22 | std::cout << ">> Measurement channel with 2 Kraus operators:\n";
23 | std::vector Ks{st.pz0, st.pz1}; // 2 Kraus operators
24 | std::cout << disp(Ks[0]) << "\nand\n" << disp(Ks[1]) << '\n';
25 |
26 | std::cout << ">> Superoperator matrix of the channel:\n";
27 | std::cout << disp(kraus2super(Ks)) << '\n';
28 |
29 | std::cout << ">> Choi matrix of the channel:\n";
30 | std::cout << disp(kraus2choi(Ks)) << '\n';
31 |
32 | // apply the channel onto the first subsystem
33 | cmat rhoOut = apply(rho, Ks, {0});
34 | std::cout << ">> After applying the measurement channel "
35 | << "on the first qubit:\n";
36 | std::cout << disp(rhoOut) << '\n';
37 |
38 | // take the partial trace over the second subsystem
39 | cmat rhoA = ptrace(rhoOut, {1});
40 | std::cout << ">> After partially tracing down the second subsystem:\n";
41 | std::cout << disp(rhoA) << '\n';
42 |
43 | // compute the von-Neumann entropy
44 | realT ent = entropy(rhoA);
45 | std::cout << ">> Entropy: " << ent << '\n';
46 | }
47 |
--------------------------------------------------------------------------------
/examples/randomness.cpp:
--------------------------------------------------------------------------------
1 | // Randomness
2 | // Source: ./examples/randomness.cpp
3 |
4 | #include
5 | #include
6 |
7 | #include "qpp/qpp.hpp"
8 |
9 | int main() {
10 | using namespace qpp;
11 |
12 | std::cout << ">> Generating a random ket on D = 5\n";
13 | ket rket = randket(5);
14 | std::cout << disp(rket) << '\n';
15 |
16 | std::vector probs = abssq(rket);
17 | std::cout << ">> Probabilities: "
18 | << disp(probs, IOManipContainerOpts{}.set_sep(", ")) << '\n';
19 |
20 | std::cout << ">> Sum of the probabilities: ";
21 | std::cout << sum(probs.begin(), probs.end()) << '\n';
22 | }
23 |
--------------------------------------------------------------------------------
/examples/reversible1.cpp:
--------------------------------------------------------------------------------
1 | // Classical reversible circuits
2 | // Source: ./examples/reversible1.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Classical reversible circuits (1)\n";
12 |
13 | Dynamic_bitset bits{4}; // 4 classical bits
14 | std::cout << ">> Initial bitset: " << bits << '\n'; // display them
15 |
16 | bits.rand(); // randomize the bits
17 | std::cout << ">> After randomization: " << bits << '\n'; // display them
18 |
19 | Bit_circuit bc{bits}; // construct a bit circuit out of a bit set
20 | std::cout << ">> Bit circuit (constructed from the above bitset):\n"
21 | << bc << '\n';
22 |
23 | std::cout << ">> Apply X_0, followed by CNOT_02, CNOT_13 and TOF_013\n";
24 | bc.X(0); // apply a NOT gate on the first bit
25 | bc.CNOT(0, 2).CNOT(1, 3).TOF(0, 1, 3); // sequence operations
26 |
27 | std::cout << ">> Final bit circuit:\n" << bc << '\n';
28 | std::cout << ">> 3rd bit: " << bc.get(2) << '\n';
29 | std::cout << ">> CNOT count: " << bc.get_gate_count("CNOT") << '\n';
30 | std::cout << ">> CNOT depth: " << bc.get_gate_depth("CNOT") << '\n';
31 | }
32 |
--------------------------------------------------------------------------------
/examples/reversible2.cpp:
--------------------------------------------------------------------------------
1 | // Classical reversible circuits
2 | // Source: ./examples/reversible2.cpp
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "qpp/qpp.hpp"
10 |
11 | int main() {
12 | using namespace qpp;
13 |
14 | std::cout << ">> Classical reversible circuits (2)\n";
15 |
16 | idx n = 32; // number of bits
17 | idx num_trials = 10; // number of trials
18 | Bit_circuit bc{n};
19 | bc.rand(); // randomize the vector
20 | Bit_circuit bc_initial = bc;
21 |
22 | std::cout << ">> Initial randomized bit circuit state\n"
23 | << bc_initial.to_string() << '\n';
24 |
25 | // randomize the indices where Toffoli will be applied
26 | std::random_device rd;
27 | std::mt19937 gen{rd()};
28 | std::vector> indices(num_trials);
29 |
30 | // generate the indices
31 | for (idx i = 0; i < num_trials; ++i) {
32 | std::vector v(n);
33 | std::iota(v.begin(), v.end(), 0);
34 | std::shuffle(v.begin(), v.end(), gen);
35 | std::vector tof(v.data(), v.data() + 3);
36 | indices[i] = tof;
37 | }
38 |
39 | // apply the Toffoli gate to random places
40 | std::cout << ">> Applying Toffoli gates to bits\n";
41 | for (idx i = 0; i < num_trials; ++i) {
42 | for (auto&& elem : indices[i]) {
43 | std::cout << '\t' << elem << " ";
44 | }
45 | std::cout << '\n';
46 | bc.TOF(indices[i][0], indices[i][1], indices[i][2]);
47 | }
48 | std::cout << ">> Intermediate bit circuit state\n";
49 | std::cout << bc.to_string() << '\n';
50 | std::cout << ">> Hamming distance (from the initial circuit): "
51 | << bc_initial - bc << '\n';
52 | std::cout << ">> NOT count (intermediate circuit, should be zero): "
53 | << bc.get_gate_count("NOT") << '\n';
54 | std::cout << ">> X count (should be same as NOT count, i.e., zero): "
55 | << bc.get_gate_count("X") << '\n';
56 | std::cout << ">> Toffoli count (intermediate circuit): "
57 | << bc.get_gate_count("TOF") << '\n';
58 |
59 | // apply again the same Toffoli gates in reverse order
60 | std::cout << ">> Applying again Toffoli gates to bits\n";
61 | for (idx i = num_trials; i-- > 0;) {
62 | for (auto&& elem : indices[i]) {
63 | std::cout << '\t' << elem << " ";
64 | }
65 | std::cout << '\n';
66 | bc.TOF(indices[i][0], indices[i][1], indices[i][2]);
67 | }
68 |
69 | std::cout << ">> Final bit circuit state\n" << bc.to_string() << '\n';
70 | std::cout << ">> Are the initial and final circuits equal? "
71 | << std::boolalpha << (bc_initial == bc) << std::noboolalpha
72 | << '\n';
73 |
74 | std::cout << ">> Changing the string representation of the bits\n";
75 | std::cout << bc.to_string('o', 'i') << '\n';
76 | }
77 |
--------------------------------------------------------------------------------
/examples/spectral.cpp:
--------------------------------------------------------------------------------
1 | // Spectral decomposition
2 | // Source: ./examples/spectral.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | idx D = 4;
12 | cmat rH = randH(D); // random Hermitian matrix
13 | std::cout << ">> Original matrix:\n" << disp(rH) << '\n';
14 |
15 | // spectral decomposition here
16 | dyn_col_vect evalsH = hevals(rH);
17 | cmat evectsH = hevects(rH);
18 | cmat spec = cmat::Zero(D, D);
19 | // reconstruct the matrix
20 | for (idx i = 0; i < D; ++i) {
21 | spec += evalsH(i) * prj(evectsH.col(i));
22 | }
23 |
24 | std::cout << ">> Reconstructed from spectral decomposition:\n";
25 | std::cout << disp(spec) << '\n';
26 |
27 | // verification
28 | std::cout << ">> Norm difference: " << norm(spec - rH) << '\n';
29 | }
30 |
--------------------------------------------------------------------------------
/examples/standalone/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | project(standalone)
3 | set(CMAKE_CXX_STANDARD 17)
4 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
5 |
6 | # If Quantum++'s installation path was non-standard, i.e., specified by
7 | #
8 | # cmake -B build -DCMAKE_INSTALL_PREFIX=/path/to/installed/qpp
9 | #
10 | # uncomment the following line and replace the installation path with yours
11 |
12 | # set(CMAKE_PREFIX_PATH "/path/to/installed/qpp")
13 |
14 | find_package(qpp REQUIRED)
15 | add_executable(standalone src/main.cpp)
16 | target_link_libraries(standalone PUBLIC ${QPP_LINK_DEPS} libqpp)
17 |
--------------------------------------------------------------------------------
/examples/standalone/src/main.cpp:
--------------------------------------------------------------------------------
1 | // Standalone example, assumes quantum++ is installed in a system-wide visible
2 | // directory
3 |
4 | #include
5 |
6 | #include
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | QCircuit qc{1, 1, 2, "coin flip"};
12 | qc.gate(gt.H, 0);
13 | qc.measure_all();
14 | std::cout << qc << "\n\n" << qc.get_resources() << "\n\n";
15 |
16 | QEngine qe{qc};
17 | std::cout << qe.execute(100) << '\n';
18 | }
19 |
--------------------------------------------------------------------------------
/examples/statistics.cpp:
--------------------------------------------------------------------------------
1 | // Statistics
2 | // Source: ./examples/statistics.cpp
3 |
4 | #include
5 | #include
6 |
7 | #include "qpp/qpp.hpp"
8 |
9 | int main() {
10 | using namespace qpp;
11 |
12 | // random variables
13 | std::vector X{1, 2};
14 | std::vector Y{1, 2, 3};
15 |
16 | // joint probability distribution
17 | rmat probXY(2, 3);
18 | probXY << 0.25, 0.25, 0, 0, 0.25, 0.25;
19 | std::vector probX = marginalX(probXY);
20 | std::vector probY = marginalY(probXY);
21 |
22 | std::cout << ">> ProbX: "
23 | << disp(marginalX(probXY), IOManipContainerOpts{}.set_sep(", "))
24 | << '\n';
25 | std::cout << ">> ProbY: "
26 | << disp(marginalY(probXY), IOManipContainerOpts{}.set_sep(", "))
27 | << '\n';
28 |
29 | std::cout << "Mean (X/Y): " << avg(probX, X) << " " << avg(probY, Y)
30 | << '\n';
31 | std::cout << "Standard deviation (X/Y): " << sigma(probX, X) << " "
32 | << sigma(probY, Y) << '\n';
33 | std::cout << "Variance (X/Y): " << var(probX, X) << " " << var(probY, Y)
34 | << '\n';
35 | std::cout << "Covariance: " << cov(probXY, X, Y) << '\n';
36 |
37 | // display a uniform probability distribution
38 | std::cout << "Uniform(5): "
39 | << disp(uniform(5), IOManipContainerOpts{}.set_sep(", ")) << '\n';
40 | }
41 |
--------------------------------------------------------------------------------
/examples/teleport_qubit.cpp:
--------------------------------------------------------------------------------
1 | // Qubit teleportation
2 | // Source: ./examples/teleport_qubit.cpp
3 | // See also: ./examples/teleport_qudit.cpp
4 |
5 | #include
6 | #include
7 |
8 | #include "qpp/qpp.hpp"
9 |
10 | int main() {
11 | using namespace qpp;
12 |
13 | // input state
14 | ket psi_a = randket();
15 |
16 | std::cout << ">> Qubit teleportation\n";
17 | std::cout << ">> Initial state:\n" << disp(psi_a) << '\n';
18 |
19 | // the entangled resource
20 | ket phi_AB = st.b00;
21 |
22 | // global input state
23 | ket input_aAB = kron(psi_a, phi_AB);
24 |
25 | // apply a CNOT on qubits 'AB' followed by an H on qubit 'a'
26 | input_aAB = applyCTRL(input_aAB, gt.X, {0}, {1});
27 | input_aAB = apply(input_aAB, gt.H, {0});
28 |
29 | // measure the aA part
30 | auto [ms_aA, probs_aA, psi_B] = measure_seq(input_aAB, {0, 1});
31 |
32 | // measurement results
33 | idx z = ms_aA[0];
34 | idx x = ms_aA[1];
35 | std::cout << ">> Alice's measurement result: ";
36 | std::cout << "x = " << x << " and z = " << z;
37 |
38 | // probability of obtaining the measurement results x and z
39 | realT p = prod(probs_aA);
40 | std::cout << ", obtained with probability: " << p << '\n';
41 |
42 | // the output state (before correction)
43 | std::cout << ">> Bob's state (before correction):\n";
44 | std::cout << disp(psi_B) << '\n';
45 |
46 | // perform the correction on B
47 | psi_B = powm(gt.Z, z) * powm(gt.X, x) * psi_B;
48 | std::cout << ">> Bob must apply the correction operator Z^" << z << " X^"
49 | << x << '\n';
50 |
51 | // display the output
52 | std::cout << ">> Bob's final state (after correction):\n";
53 | std::cout << disp(psi_B) << '\n';
54 |
55 | // verification
56 | std::cout << ">> Norm difference: " << norm(psi_B - psi_a) << '\n';
57 | }
58 |
--------------------------------------------------------------------------------
/examples/teleport_qudit.cpp:
--------------------------------------------------------------------------------
1 | // Qudit teleportation
2 | // Source: ./examples/teleport_qudit.cpp
3 | // See also: ./examples/teleport_qubit.cpp
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "qpp/qpp.hpp"
10 |
11 | int main() {
12 | using namespace qpp;
13 |
14 | idx d = 3; // size of the system
15 | std::cout << ">> Qudit teleportation, d = " << d << '\n';
16 |
17 | ket mes_AB = st.mes(d); // maximally entangled state resource
18 |
19 | // circuit used to measure in the qudit Bell basis
20 | cmat Bell_aA = kron(adjoint(gt.Fd(d)), gt.Id(d)) *
21 | gt.CTRL(adjoint(gt.Xd(d)), {0}, {1}, 2, d);
22 |
23 | ket psi_a = randket(d); // random qudit state
24 | std::cout << ">> Initial state:\n";
25 | std::cout << disp(psi_a) << '\n';
26 |
27 | ket input_aAB = kron(psi_a, mes_AB); // joint input state aAB
28 | // output before measurement
29 | ket output_aAB = apply(input_aAB, Bell_aA, {0, 1}, d);
30 |
31 | // measure on aA
32 | auto [m_aA, probs_aA, states_B] =
33 | measure(output_aAB, gt.Id(d * d), {0, 1}, d);
34 |
35 | std::vector midx = n2multiidx(m_aA, {d, d});
36 | std::cout << ">> Alice's measurement result: ";
37 | std::cout << m_aA << " -> "
38 | << disp(midx, IOManipContainerOpts{}.set_sep(" ")) << '\n';
39 | std::cout << ">> Alice's measurement probabilities: ";
40 | std::cout << disp(probs_aA, IOManipContainerOpts{}.set_sep(", ")) << '\n';
41 |
42 | // conditional result on B before correction
43 | ket output_B = states_B[m_aA];
44 |
45 | // perform the correction on B
46 | cmat correction_B =
47 | powm(gt.Zd(d), midx[0]) * powm(adjoint(gt.Xd(d)), midx[1]);
48 | std::cout << ">> Bob must apply the correction operator Z^" << midx[0]
49 | << " X^" << (d - midx[1]) % d << '\n';
50 | ket psi_B = correction_B * output_B;
51 |
52 | // display the output
53 | std::cout << ">> Bob's final state (after correction):\n";
54 | std::cout << disp(psi_B) << '\n';
55 |
56 | // verification
57 | std::cout << ">> Norm difference: " << norm(psi_B - psi_a) << '\n';
58 | }
59 |
--------------------------------------------------------------------------------
/examples/timing1.cpp:
--------------------------------------------------------------------------------
1 | // Timing
2 | // Source: ./examples/timing1.cpp
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "qpp/qpp.hpp"
9 |
10 | int main() {
11 | using namespace qpp;
12 |
13 | std::cout << std::setprecision(8); // increase the default output precision
14 |
15 | // get the first codeword from Shor's [[9,1,3]] code
16 | ket c0 = codes.codeword(Codes::Type::SHOR_NINE_QUBIT, 0);
17 |
18 | Timer<> t; // declare and start a timer
19 | std::vector perm = randperm(9); // declare a random permutation
20 | ket c0perm = syspermute(c0, perm); // permute the system
21 | t.toc(); // stop the timer
22 | std::cout << ">> Permuting subsystems according to "
23 | << disp(perm, IOManipContainerOpts{}.set_sep(", "));
24 | std::cout << "\n>> It took " << t << " seconds to permute the subsytems.\n";
25 |
26 | t.tic(); // restart the timer
27 | std::cout << ">> Inverse permutation: ";
28 | std::cout << disp(invperm(perm), IOManipContainerOpts{}.set_sep(", "))
29 | << '\n';
30 | ket c0invperm = syspermute(c0perm, invperm(perm)); // permute again
31 | std::cout << ">> It took " << t.toc();
32 | std::cout << " seconds to un-permute the subsystems.\n";
33 |
34 | std::cout << ">> Norm difference: " << norm(c0invperm - c0) << '\n';
35 | }
36 |
--------------------------------------------------------------------------------
/examples/timing2.cpp:
--------------------------------------------------------------------------------
1 | // Timing
2 | // Source: ./examples/timing2.cpp
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "qpp/qpp.hpp"
10 |
11 | int main() {
12 | using namespace qpp;
13 |
14 | idx n = 10; // number of qubits
15 | auto D = static_cast(std::llround(std::pow(2, n))); // dimension 2^n
16 | std::cout << ">> n = " << n << " qubits, matrix size " << D << " x " << D
17 | << ".\n\n";
18 | cmat randcmat = cmat::Random(D, D);
19 |
20 | // qpp::ptrace()
21 | std::cout << "**** qpp::ptrace() timing ****\n";
22 | std::vector subsys_ptrace = {0};
23 | std::cout << ">> Subsytem(s): ";
24 | std::cout << disp(subsys_ptrace, IOManipContainerOpts{}.set_sep(", "))
25 | << '\n';
26 | Timer<> t;
27 | ptrace(randcmat, subsys_ptrace);
28 | std::cout << ">> It took " << t.toc() << " seconds.\n\n";
29 |
30 | // qpp::ptranspose()
31 | std::cout << "**** qpp::ptranspose() timing ****\n";
32 | // partially transpose n-1 subsystems
33 | std::vector subsys_ptranspose(n - 1);
34 | std::iota(std::begin(subsys_ptranspose), std::end(subsys_ptranspose), 0);
35 | std::cout << ">> Subsytem(s): ";
36 | std::cout << disp(subsys_ptranspose, IOManipContainerOpts{}.set_sep(", "))
37 | << '\n';
38 | t.tic();
39 | ptranspose(randcmat, subsys_ptranspose);
40 | std::cout << ">> It took " << t.toc() << " seconds.\n\n";
41 |
42 | // qpp::syspermute()
43 | std::cout << "**** qpp::syspermute() timing ****\n";
44 | std::vector perm(n); // left-shift all subsystems by 1
45 | for (idx i = 0; i < n; ++i) {
46 | perm[i] = (i + 1) % n;
47 | }
48 | std::cout << ">> Subsytem(s): ";
49 | std::cout << disp(perm, IOManipContainerOpts{}.set_sep(", ")) << '\n';
50 | t.tic();
51 | syspermute(randcmat, perm);
52 | std::cout << ">> It took " << t.toc() << " seconds.\n";
53 | }
54 |
--------------------------------------------------------------------------------
/examples/toffoli.cpp:
--------------------------------------------------------------------------------
1 | // Toffoli gate simulation
2 | // Source: ./examples/toffoli.cpp
3 |
4 | #include
5 |
6 | #include "qpp/qpp.hpp"
7 |
8 | int main() {
9 | using namespace qpp;
10 |
11 | std::cout << ">> Toffoli gate simulation\n\n";
12 |
13 | ket psi_in = randket(8);
14 | std::cout << ">> Input state:\n";
15 | std::cout << disp(dirac(psi_in)) << "\n\n";
16 |
17 | /**
18 | * Toffoli gate (control control not)
19 | *
20 | * ---+---
21 | * |
22 | * ---+---
23 | * |
24 | * ---X---
25 | */
26 | ket result_qpp = apply(psi_in, gt.TOF, {0, 1, 2});
27 | std::cout << ">> Toffoli gate output state:\n";
28 | std::cout << disp(dirac(result_qpp)) << "\n\n";
29 |
30 | /**
31 | * Toffoli with T and CNOT
32 | *
33 | * -------------+-------------+-----+---T---+--
34 | * | | | |
35 | * -----+-------------+----------T--X--T_d--X--
36 | * | | | |
37 | * --H--X--T_d--X--T--X--T_d--X--T--H----------
38 | */
39 | ket result = apply(psi_in, gt.H, {2});
40 | result = applyCTRL(result, gt.X, {1}, {2});
41 | result = apply(result, adjoint(gt.T), {2});
42 | result = applyCTRL(result, gt.X, {0}, {2});
43 | result = apply(result, gt.T, {2});
44 | result = applyCTRL(result, gt.X, {1}, {2});
45 | result = apply(result, adjoint(gt.T), {2});
46 | result = applyCTRL(result, gt.X, {0}, {2});
47 | result = apply(result, gt.T, {1});
48 | result = apply(result, gt.T, {2});
49 | result = applyCTRL(result, gt.X, {0}, {1});
50 | result = apply(result, gt.T, {0});
51 | result = apply(result, adjoint(gt.T), {1});
52 | result = apply(result, gt.H, {2});
53 | result = applyCTRL(result, gt.X, {0}, {1});
54 | std::cout << ">> Toffoli with T and CNOT output state:\n";
55 | std::cout << disp(dirac(result)) << '\n';
56 | std::cout << ">> Norm difference: " << norm(result - result_qpp) << "\n\n";
57 |
58 | /**
59 | * https://arxiv.org/abs/quant-ph/9503016 construction
60 | *
61 | * V * V = X
62 | *
63 | * -----+-------+---+---
64 | * | | |
65 | * --+--X---+---X-------
66 | * | | |
67 | * --V-----V_d------V---
68 | */
69 | cmat sqrtx{cmat::Zero(2, 2)};
70 | sqrtx << 0.5 + 0.5 * 1_i, 0.5 - 0.5 * 1_i, 0.5 - 0.5 * 1_i, 0.5 + 0.5 * 1_i;
71 | result = applyCTRL(psi_in, sqrtx, {1}, {2});
72 | result = applyCTRL(result, gt.X, {0}, {1});
73 | result = applyCTRL(result, adjoint(sqrtx), {1}, {2});
74 | result = applyCTRL(result, gt.X, {0}, {1});
75 | result = applyCTRL(result, sqrtx, {0}, {2});
76 | std::cout
77 | << ">> Barenco et. al. [quant-ph/9503016] construction output state:\n";
78 | std::cout << disp(dirac(result)) << '\n';
79 | std::cout << ">> Norm difference: " << norm(result - result_qpp) << '\n';
80 | }
81 |
--------------------------------------------------------------------------------
/include/qpp/classes/ijson.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Quantum++.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qpp/classes/ijson.hpp
29 | * \brief Basic JSON serialization
30 | */
31 |
32 | #ifndef QPP_CLASSES_IJSON_HPP_
33 | #define QPP_CLASSES_IJSON_HPP_
34 |
35 | #include
36 |
37 | namespace qpp {
38 | /**
39 | * \class qpp::IJSON
40 | * \brief Abstract class (interface) that mandates the definition of
41 | * very basic JSON serialization support
42 | */
43 | class IJSON {
44 | public:
45 | /**
46 | * \brief Default virtual destructor
47 | */
48 | virtual ~IJSON() = default;
49 |
50 | /**
51 | * \brief JSON representation of the derived instance, must be overridden by
52 | * all derived classes
53 | *
54 | * \param enclosed_in_curly_brackets If true, encloses the result in curly
55 | * brackets
56 | */
57 | virtual std::string
58 | to_JSON(bool enclosed_in_curly_brackets = true) const = 0;
59 | }; /* class IJSON */
60 |
61 | } /* namespace qpp */
62 |
63 | #endif /* QPP_CLASSES_IJSON_HPP_ */
64 |
--------------------------------------------------------------------------------
/include/qpp/classes/init.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Quantum++.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qpp/classes/init.hpp
29 | * \brief Initialization
30 | */
31 |
32 | #ifndef QPP_CLASSES_INIT_HPP_
33 | #define QPP_CLASSES_INIT_HPP_
34 |
35 | #include "qpp/internal/classes/singleton.hpp"
36 |
37 | namespace qpp {
38 | /**
39 | * \class qpp::Init
40 | * \brief const Singleton class that performs
41 | * additional initializations/cleanups
42 | */
43 | class Init final : public internal::Singleton // const Singleton
44 | {
45 | friend class internal::Singleton;
46 |
47 | private:
48 | /**
49 | * \brief Additional initializations
50 | */
51 | Init() = default; // modify this for custom initialization stuff
52 |
53 | /**
54 | * \brief Cleanups
55 | */
56 | ~Init() override = default;
57 | // {}
58 | }; /* class Init */
59 |
60 | } /* namespace qpp */
61 |
62 | #endif /* QPP_CLASSES_INIT_HPP_ */
63 |
--------------------------------------------------------------------------------
/include/qpp/classes/qcircuit_traits.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Quantum++.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qpp/classes/qcircuit_traits.hpp
29 | * \brief Quantum circuit traits (compile-time)
30 | */
31 |
32 | #ifndef QPP_CLASSES_QCIRCUIT_TRAITS_HPP_
33 | #define QPP_CLASSES_QCIRCUIT_TRAITS_HPP_
34 |
35 | namespace qpp {
36 | /**
37 | * \class qpp::QCircuitTraits
38 | * \brief Generic type traits for quantum circuits, resolved at compile-time
39 | * \note All quantum circuit description classes should specialize this trait
40 | */
41 | template
42 | struct QCircuitTraits;
43 | } /* namespace qpp */
44 |
45 | #endif /* QPP_CLASSES_QCIRCUIT_TRAITS_HPP_ */
46 |
--------------------------------------------------------------------------------
/include/qpp/classes/qdummy_engine.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Quantum++.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qpp/classes/qdummy_engine.hpp
29 | * \brief No-op (dummy) quantum engines
30 | */
31 |
32 | #ifndef QPP_CLASSES_QDUMMY_ENGINE_HPP_
33 | #define QPP_CLASSES_QDUMMY_ENGINE_HPP_
34 |
35 | #include
36 | #include
37 |
38 | #include "qpp/types.hpp"
39 |
40 | #include "qpp/classes/qbase_engine.hpp"
41 | #include "qpp/classes/qcircuit.hpp"
42 |
43 | namespace qpp {
44 |
45 | /**
46 | * \class qpp::QDummyEngine
47 | * \brief No-op (dummy) quantum engine
48 | * \see qpp::QBaseEngine
49 | *
50 | * \tparam T Engine's state underlying type
51 | * \tparam QCT Circuit underlying type
52 | */
53 | template
54 | struct QDummyEngine : public QBaseEngine {
55 | using QBaseEngine::QBaseEngine;
56 | // traits
57 | /**
58 | * \brief qpp::IQEngineTraits::traits_get_name() override
59 | */
60 | std::string traits_get_name() const override { return "QDummyEngine"; }
61 |
62 | /**
63 | * \brief qpp::IQEngineTraits::traits_is_noisy() override
64 | */
65 | bool traits_is_noisy() const override { return false; }
66 |
67 | /**
68 | * \brief qpp::IQEngineTraits::traits_is_pure() override
69 | */
70 | bool traits_is_pure() const override {
71 | if (std::is_same_v) {
72 | return false;
73 | } else if (std::is_same_v) {
74 | return true;
75 | }
76 | // default, we assume pure states
77 | return true;
78 | }
79 | // end traits
80 | }; /* struct QDummyEngine */
81 |
82 | /**
83 | * \class qpp::QKetDummyEngine
84 | * \brief Pure state no-op (dummy) quantum engine for qpp::QCircuit
85 | * \see qpp::QDummyEngine
86 | */
87 | struct QKetDummyEngine : public QDummyEngine {
88 | using QDummyEngine::QDummyEngine;
89 | // traits
90 | std::string traits_get_name() const override { return "QKetDummyEngine"; }
91 | // end traits
92 | };
93 |
94 | /**
95 | * \class qpp::QDensityDummyEngine
96 | * \brief Mixed state no-op (dummy) quantum engine for qpp::QCircuit
97 | * \see qpp::QDummyEngine
98 | */
99 | struct QDensityDummyEngine : public QDummyEngine {
100 | using QDummyEngine::QDummyEngine;
101 | // traits
102 | std::string traits_get_name() const override {
103 | return "QDensityDummyEngine";
104 | }
105 | // end traits
106 | };
107 | } /* namespace qpp */
108 |
109 | #endif /* QPP_CLASSES_QDUMMY_ENGINE_HPP_ */
110 |
--------------------------------------------------------------------------------
/include/qpp/classes/qengine_traits.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Quantum++.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qpp/classes/qengine_traits.hpp
29 | * \brief Quantum engine traits (run-time)
30 | */
31 |
32 | #ifndef QPP_CLASSES_QENGINE_TRAITS_HPP_
33 | #define QPP_CLASSES_QENGINE_TRAITS_HPP_
34 |
35 | #include
36 |
37 | namespace qpp {
38 | /**
39 | * \class qpp::IQEngineTraits
40 | * \brief Traits for quantum engines, resolved at run-time
41 | * \note All engines must implement this trait (i.e., inherit from it)
42 | */
43 | struct IQEngineTraits {
44 | /**
45 | * \brief Engine name
46 | *
47 | * \return Engine name
48 | */
49 | virtual std::string traits_get_name() const = 0;
50 |
51 | /**
52 | * \brief Determines if the engine is noisy
53 | *
54 | * \return True if the engine simulates noisy execution, false if not
55 | */
56 |
57 | virtual bool traits_is_noisy() const = 0;
58 | /**
59 | * \brief Determines if the engine operates on pure states
60 | *
61 | * \return True if the engine operates on pure states, false otherwise
62 | */
63 | virtual bool traits_is_pure() const = 0;
64 |
65 | /**
66 | * \brief Default virtual destructor
67 | */
68 | virtual ~IQEngineTraits() = default;
69 | };
70 | } /* namespace qpp */
71 |
72 | #endif /* QPP_CLASSES_QENGINE_TRAITS_HPP_ */
73 |
--------------------------------------------------------------------------------
/include/qpp/classes/random_devices.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Quantum++.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qpp/classes/random_devices.hpp
29 | * \brief Random devices
30 | */
31 |
32 | #ifndef QPP_CLASSES_RANDOM_DEVICES_HPP_
33 | #define QPP_CLASSES_RANDOM_DEVICES_HPP_
34 |
35 | #include
36 | #include
37 | #include
38 |
39 | #include "qpp/internal/classes/singleton.hpp"
40 |
41 | namespace qpp {
42 | /**
43 | * \class qpp::RandomDevices
44 | * \brief Singleton class that manages the source of randomness in the library
45 | *
46 | * Consists of a wrapper around an std::mt19937 Mersenne twister random number
47 | * generator engine and an std::random_device engine. The latter is used to seed
48 | * the Mersenne twister.
49 | *
50 | * \warning This class DOES NOT seed the standard C number generator used by
51 | * Eigen::Matrix::Random(), since it is not thread safe. Do not use
52 | * Eigen::Matrix::Random() or functions that depend on the C style random number
53 | * engine, but use qpp::rand() instead!
54 | */
55 | class RandomDevices final : public internal::Singleton {
56 | friend class internal::Singleton;
57 |
58 | std::random_device rd_; ///< used to seed std::mt19937 prng_
59 | std::mt19937 prng_; ///< Mersenne twister random number generator
60 | public:
61 | /**
62 | * \brief Returns a reference to the internal PRNG object
63 | * \return Reference to the internal PRNG object
64 | */
65 | std::mt19937& get_prng() { return prng_; }
66 |
67 | /**
68 | * \brief Loads the state of the PRNG from an input stream
69 | * \param is Input stream
70 | * \return Input stream
71 | */
72 | std::istream& load(std::istream& is) { return is >> prng_; }
73 |
74 | /**
75 | * \brief Saves the state of the PRNG to an output stream
76 | * \param os Output stream passed by reference
77 | * \return Reference to the output stream
78 | */
79 | std::ostream& save(std::ostream& os) const { return os << prng_; }
80 |
81 | private:
82 | /**
83 | * \brief Initializes and seeds the random number generators
84 | */
85 | RandomDevices() : rd_{}, prng_{rd_()} {}
86 |
87 | /**
88 | * \brief Default destructor
89 | */
90 | ~RandomDevices() override = default;
91 | }; /* class RandomDevices */
92 |
93 | } /* namespace qpp */
94 |
95 | #endif /* QPP_CLASSES_RANDOM_DEVICES_HPP_ */
96 |
--------------------------------------------------------------------------------
/include/qpp/internal/classes/qcircuit_nop_step.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of Quantum++.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qpp/internal/classes/qcircuit_nop_step.hpp
29 | * \brief qpp::internal::QCircuitNOPStep
30 | */
31 |
32 | #ifndef QPP_INTERNAL_CLASSES_QCIRCUIT_NOP_STEP_HPP_
33 | #define QPP_INTERNAL_CLASSES_QCIRCUIT_NOP_STEP_HPP_
34 |
35 | #include "qpp/classes/idisplay.hpp"
36 |
37 | namespace qpp {
38 | namespace internal {
39 | /**
40 | * \brief No-op
41 | */
42 | struct QCircuitNOPStep : IDisplay {
43 | /**
44 | * \brief Equality operator
45 | *
46 | * \return True (always)
47 | */
48 | bool operator==(const QCircuitNOPStep&) const noexcept { return true; }
49 |
50 | /**
51 | * \brief Inequality operator
52 | *
53 | * \return False (always)
54 | */
55 | bool operator!=(const QCircuitNOPStep& rhs) const noexcept {
56 | return !(*this == rhs);
57 | }
58 |
59 | private:
60 | /**
61 | * \brief qpp::IDisplay::display() override
62 | *
63 | * Writes to the output stream a textual representation of the
64 | * \a qpp::internal::QCircuitNOPStep instance
65 | *
66 | * \param os Output stream passed by reference
67 | * \return Reference to the output stream
68 | */
69 | std::ostream& display(std::ostream& os) const override {
70 | os << "NOP";
71 |
72 | return os;
73 | }
74 | };
75 |
76 | } /* namespace internal */
77 | } /* namespace qpp */
78 |
79 | #endif /* QPP_INTERNAL_CLASSES_QCIRCUIT_NOP_STEP_HPP_ */
80 |
--------------------------------------------------------------------------------
/prettyprint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Code beautifier with clang-format
4 | # Recursively parses the directories passed as command line arguments
5 |
6 | # Arguments:
7 | #
8 | # $@ - List of directories
9 |
10 | if test -z "$CLANG_FORMAT"; then
11 | echo "Please set the CLANG_FORMAT environment variable to point to the \
12 | location of clang-format"
13 | exit 1
14 | else
15 | if ! [ -x "$(command -v "$CLANG_FORMAT")" ]; then
16 | echo "Error: $CLANG_FORMAT executable not found." >&2
17 | exit 1
18 | fi
19 | echo "Code formatting with '$CLANG_FORMAT' the directories:"
20 | fi
21 |
22 | for directory in "$@"; do
23 | echo "$directory"
24 | find "$directory" \( -iname '*.cpp' -o -iname '*.c' -o -iname '*.h' \
25 | -o -iname '*.hpp' \) -exec "$CLANG_FORMAT" -style=file -i {} +
26 | done
27 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "pyqpp"
3 | requires-python = ">=3.9"
4 | version = "6.0"
5 | description = "Python 3 wrapper for Quantum++"
6 | authors = [
7 | { name = "softwareQ Inc.", email = "info@softwareq.ca" },
8 | ]
9 | readme = "pyqpp/README.md"
10 | license = { text = "MIT" }
11 | dependencies = [
12 | "numpy",
13 | ]
14 |
15 | [project.urls]
16 | homepage = "https://github.com/softwareqinc/qpp"
17 | repository = "https://github.com/softwareqinc/qpp.git"
18 |
19 | [build-system]
20 | requires = [
21 | "pybind11>=2.10.0",
22 | "setuptools>=42",
23 | "wheel",
24 | ]
25 | build-backend = "setuptools.build_meta"
26 |
27 | [tool.setuptools]
28 | py-modules = []
29 |
--------------------------------------------------------------------------------
/pyqpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | project(pyqpp)
3 | set(CMAKE_CXX_STANDARD 17)
4 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
5 | set(CMAKE_CXX_EXTENSIONS OFF)
6 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
7 |
8 | find_package(Python3 QUIET COMPONENTS Interpreter Development)
9 | if(${Python3_FOUND})
10 | include("../cmake/pybind11.cmake")
11 | else()
12 | message(FATAL_ERROR "Python3 development kit not found, can not build pyqpp.")
13 | endif()
14 |
15 | include("../cmake/qpp_eigen3.cmake")
16 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/classes/gates_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_CLASSES_GATES_BIND_HPP_
28 | #define PYQPP_CLASSES_GATES_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* qpp::Gates */
33 | inline void init_classes_gates(py::module_& m) {
34 | using namespace qpp;
35 |
36 | auto gates = m.def_submodule("gates");
37 | gates.attr("Id2") = qpp::gt.Id2;
38 |
39 | gates.attr("X") = qpp::gt.X;
40 | gates.attr("Y") = qpp::gt.Y;
41 | gates.attr("Z") = qpp::gt.Z;
42 | gates.attr("H") = qpp::gt.H;
43 | gates.attr("S") = qpp::gt.S;
44 | gates.attr("T") = qpp::gt.T;
45 |
46 | gates.attr("CNOT") = qpp::gt.CNOT;
47 | gates.attr("CZ") = qpp::gt.CZ;
48 | gates.attr("CNOTba") = qpp::gt.CNOTba;
49 | gates.attr("SWAP") = qpp::gt.SWAP;
50 |
51 | gates.attr("RXX") = qpp::gt.RXX;
52 | gates.attr("RYY") = qpp::gt.RYY;
53 |
54 | gates.attr("TOF") = qpp::gt.TOF;
55 | gates.attr("FRED") = qpp::gt.FRED;
56 |
57 | gates.def(
58 | "Fd", [](idx D) { return qpp::gt.Fd(D); },
59 | "Quantum Fourier transform gate for qudits", py::arg("D") = 2);
60 | gates.def(
61 | "get_name", [](const cmat& U) { return qpp::gt.get_name(U); },
62 | "Get the name of the most common qubit gates", py::arg("U"));
63 | gates.def(
64 | "Id", [](idx D) { return qpp::gt.Id(D); }, "Identity gate",
65 | py::arg("D") = 2);
66 | gates.def(
67 | "MODMUL", [](idx a, idx N, idx n) { return qpp::gt.MODMUL(a, N, n); },
68 | "Modular multiplication gate for qubits", py::arg("a"), py::arg("N"),
69 | py::arg("n"));
70 | gates.def(
71 | "Rn",
72 | [](realT theta, const std::array& n) {
73 | return qpp::gt.Rn(theta, n);
74 | },
75 | "Qubit rotation of theta about the 3-dimensional real (unit) vector n",
76 | py::arg("theta"), py::arg("n"));
77 | gates.def(
78 | "RX", [](realT theta) { return qpp::gt.RX(theta); },
79 | "Qubit rotation of theta about the X axis", py::arg("theta"));
80 | gates.def(
81 | "RY", [](realT theta) { return qpp::gt.RY(theta); },
82 | "Qubit rotation of theta about the Y axis", py::arg("theta"));
83 | gates.def(
84 | "RZ", [](realT theta) { return qpp::gt.RZ(theta); },
85 | "Qubit rotation of theta about the Z axis", py::arg("theta"));
86 | gates.def(
87 | "SWAPd", [](idx D) { return qpp::gt.SWAPd(D); }, "SWAP gate for qudits",
88 | py::arg("D") = 2);
89 | gates.def(
90 | "Xd", [](idx D) { return qpp::gt.Xd(D); },
91 | "Generalized X gate for qudits", py::arg("D") = 2);
92 | gates.def(
93 | "Zd", [](idx D) { return qpp::gt.Zd(D); },
94 | "Generalized Z gate for qudits", py::arg("D") = 2);
95 | }
96 |
97 | #endif /* PYQPP_CLASSES_GATES_BIND_HPP_ */
98 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/classes/states_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_CLASSES_STATES_BIND_HPP_
28 | #define PYQPP_CLASSES_STATES_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* qpp::States */
33 | inline void init_classes_states(py::module_& m) {
34 | using namespace qpp;
35 |
36 | auto states = m.def_submodule("states");
37 | states.attr("x0") = qpp::st.x0;
38 | states.attr("x1") = qpp::st.x1;
39 | states.attr("y0") = qpp::st.y0;
40 | states.attr("y1") = qpp::st.y1;
41 | states.attr("z0") = qpp::st.z0;
42 | states.attr("z1") = qpp::st.z1;
43 |
44 | states.attr("b00") = qpp::st.b00;
45 | states.attr("b01") = qpp::st.b01;
46 | states.attr("b10") = qpp::st.b10;
47 | states.attr("b11") = qpp::st.b11;
48 |
49 | states.attr("pb00") = qpp::st.pb00;
50 | states.attr("pb01") = qpp::st.pb01;
51 | states.attr("pb10") = qpp::st.pb10;
52 | states.attr("pb11") = qpp::st.pb11;
53 |
54 | states.attr("GHZ") = qpp::st.GHZ;
55 | states.attr("W") = qpp::st.W;
56 |
57 | states.attr("pGHZ") = qpp::st.pGHZ;
58 | states.attr("pW") = qpp::st.pW;
59 |
60 | states.def(
61 | "j", [](idx j, idx d) { return qpp::st.j(j, d); },
62 | "$|j\\rangle$ computational basis state of a single qudit",
63 | py::arg("j"), py::arg("d") = 2);
64 | states.def(
65 | "jn", [](idx j, idx n, idx d) { return qpp::st.jn(j, n, d); },
66 | "$|j\\rangle^{\\otimes n}$ state of n qudits", py::arg("j"),
67 | py::arg("n") = 1, py::arg("d") = 2);
68 | states.def(
69 | "mes", [](idx d) { return qpp::st.mes(d); },
70 | "Maximally entangled state of 2 qudits", py::arg("d") = 2);
71 | states.def(
72 | "minus", [](idx n) { return qpp::st.minus(n); },
73 | "Minus state of n qubits", py::arg("n") = 1);
74 | states.def(
75 | "one", [](idx n, idx d) { return qpp::st.one(n, d); },
76 | "One state of n qudits", py::arg("n") = 1, py::arg("d") = 2);
77 | states.def(
78 | "plus", [](idx n) { return qpp::st.plus(n); }, "Plus state of n qubits",
79 | py::arg("n") = 1);
80 | states.def(
81 | "zero", [](idx n, idx d) { return qpp::st.zero(n, d); },
82 | "Zero state of n qudits", py::arg("n") = 1, py::arg("d") = 2);
83 | }
84 |
85 | #endif /* PYQPP_CLASSES_STATES_BIND_HPP_ */
86 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/constants_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_CONSTANTS_BIND_HPP_
28 | #define PYQPP_CONSTANTS_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* Constants from constants.hpp */
33 | inline void init_constants(py::module_& m) {
34 | using namespace qpp;
35 |
36 | m.attr("ee") = qpp::ee;
37 | m.def("omega", &qpp::omega, "D-th root of unity", py::arg("D"));
38 | m.attr("pi") = qpp::pi;
39 | }
40 |
41 | #endif /* PYQPP_CONSTANTS_BIND_HPP_ */
42 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/functions_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_FUNCTIONS_BIND_HPP_
28 | #define PYQPP_FUNCTIONS_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* Some free functions (non-exhaustive list) from functions.hpp */
33 | inline void init_functions(py::module_& m) {
34 | using namespace qpp;
35 |
36 | /* Template methods must be explicitly instantiated, some examples below */
37 | m.def(
38 | "adjoint", [](const cmat& A) { return qpp::adjoint(A); }, "Adjoint",
39 | py::arg("A"));
40 | m.def(
41 | "conjugate", [](const cmat& A) { return qpp::conjugate(A); },
42 | "Complex conjugate", py::arg("A"));
43 | m.def(
44 | "det", [](const cmat& A) { return qpp::det(A); }, "Determinant",
45 | py::arg("A"));
46 | m.def(
47 | "inverse", [](const cmat& A) { return qpp::inverse(A); }, "Inverse",
48 | py::arg("A"));
49 | m.def(
50 | "kron", [](const cmat& A, const cmat& B) { return qpp::kron(A, B); },
51 | "Kronecker product", py::arg("A"), py::arg("B"));
52 | m.def("kron", static_cast&)>(&qpp::kron),
53 | "Kronecker product of a list of elements", py::arg("As"));
54 | m.def(
55 | "logdet", [](const cmat& A) { return qpp::logdet(A); },
56 | "Logarithm of the determinant", py::arg("A"));
57 | m.def(
58 | "norm", [](const cmat& A) { return qpp::norm(A); }, "Frobenius norm",
59 | py::arg("A"));
60 | m.def(
61 | "prod", [](const cmat& A) { return qpp::prod(A); },
62 | "Element-wise product", py::arg("As"));
63 | m.def(
64 | "prod", [](const std::vector& As) { return qpp::prod(As); },
65 | "Products of the elements of the list", py::arg("As"));
66 | m.def(
67 | "sum", [](const cmat& A) { return qpp::sum(A); }, "Element-wise sum",
68 | py::arg("A"));
69 | m.def(
70 | "sum", [](const std::vector& As) { return qpp::sum(As); },
71 | "Sum of the elements of the list", py::arg("A"));
72 | m.def(
73 | "trace", [](const cmat& A) { return qpp::trace(A); }, "trace",
74 | py::arg("A"));
75 | m.def(
76 | "transpose", [](const cmat& A) { return qpp::transpose(A); },
77 | "Transpose", py::arg("A"));
78 | m.def(
79 | "dirac",
80 | [](const cmat& A, std::vector dims_rows,
81 | std::vector dims_cols) {
82 | return qpp::dirac(A, dims_rows, dims_cols);
83 | },
84 | "Dirac notation", py::arg("A"), py::arg("dims_rows"),
85 | py::arg("dims_cols"));
86 | m.def(
87 | "dirac", [](const cmat& A, idx d = 2) { return qpp::dirac(A, d); },
88 | "Dirac notation", py::arg("A"), py::arg("d") = 2);
89 | }
90 |
91 | #endif /* PYQPP_FUNCTIONS_BIND_HPP_ */
92 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/instruments_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_INSTRUMENTS_BIND_HPP_
28 | #define PYQPP_INSTRUMENTS_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* Some free functions (non-exhaustive list) from instruments.hpp */
33 | inline void init_instruments(py::module_& m) {
34 | using namespace qpp;
35 |
36 | m.def(
37 | "sample",
38 | [](const cmat& A, const std::vector& target,
39 | const std::vector& dims) {
40 | return qpp::sample(A, target, dims);
41 | },
42 | "Samples from a quantum state in the computational basis (Z-basis)",
43 | py::arg("A"), py::arg("target"), py::arg("dims"));
44 | m.def(
45 | "sample",
46 | [](const cmat& A, const std::vector& target, idx d = 2) {
47 | return qpp::sample(A, target, d);
48 | },
49 | "Samples from a quantum state in the computational basis (Z-basis)",
50 | py::arg("A"), py::arg("target"), py::arg("d") = 2);
51 | m.def(
52 | "sample",
53 | [](idx num_samples, const cmat& A, const std::vector& target,
54 | const std::vector& dims) {
55 | std::map result;
56 | auto stats = qpp::sample(num_samples, A, target, dims);
57 | for (auto&& elem : stats) {
58 | std::stringstream ss;
59 | ss << qpp::disp(
60 | elem.first,
61 | IOManipContainerOpts{}.set_sep("").set_left("").set_right(
62 | ""));
63 | result[ss.str()] = elem.second;
64 | }
65 | return result;
66 | },
67 | "Samples repeatedly from a quantum state in the computational basis "
68 | "(Z-basis)",
69 | py::arg("num_samples"), py::arg("A"), py::arg("target"),
70 | py::arg("dims"));
71 | m.def(
72 | "sample",
73 | [](idx num_samples, const cmat& A, const std::vector& target,
74 | idx d = 2) {
75 | std::map result;
76 | auto stats = qpp::sample(num_samples, A, target, d);
77 | for (auto&& elem : stats) {
78 | std::stringstream ss;
79 | ss << qpp::disp(
80 | elem.first,
81 | IOManipContainerOpts{}.set_sep("").set_left("").set_right(
82 | ""));
83 | result[ss.str()] = elem.second;
84 | }
85 | return result;
86 | },
87 | "Samples repeatedly from a quantum state in the computational basis "
88 | "(Z-basis)",
89 | py::arg("num_samples"), py::arg("A"), py::arg("target"),
90 | py::arg("d") = 2);
91 | }
92 |
93 | #endif /* PYQPP_INSTRUMENTS_BIND_HPP_ */
94 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/pyqpp_common.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_COMMON_H_
28 | #define PYQPP_COMMON_H_
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #include "qpp/qpp.hpp"
36 |
37 | namespace py = pybind11;
38 |
39 | #endif /* PYQPP_COMMON_H_ */
40 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/pyqpp_specific_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_PYQPP_SPECIFIC_BIND_HPP_
28 | #define PYQPP_PYQPP_SPECIFIC_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* Python-specific functions only (not necessarily with an equivalent version in
33 | * qpp) */
34 | inline void init_pyqpp_specific(py::module_& m) {
35 | using namespace qpp;
36 |
37 | m.def(
38 | "set_prng_seed",
39 | [](std::size_t seed) {
40 | qpp::RandomDevices::get_instance().get_prng().seed(seed);
41 | },
42 | "Sets the prng seed to a specific value", py::arg("seed"));
43 | m.def(
44 | "set_prng_seed",
45 | []() {
46 | qpp::RandomDevices::get_instance().get_prng().seed(
47 | std::random_device{}());
48 | },
49 | "Sets the prng seed to a random value");
50 | }
51 |
52 | #endif /* PYQPP_PYQPP_SPECIFIC_BIND_HPP_ */
53 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/qasm/qasm_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_QASM_QASM_BIND_HPP_
28 | #define PYQPP_QASM_QASM_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* OpenQASM interfacing */
33 | inline void init_qasm_qasm(py::module_& m) {
34 | using namespace qpp;
35 |
36 | auto py_qasm = m.def_submodule("qasm");
37 | py_qasm.def("read_from_file", &qpp::qasm::read_from_file,
38 | "Get QCircuit representation of OpenQASM circuit from file");
39 | py_qasm.def("read_from_string", &qpp::qasm::read_from_string,
40 | "Get QCircuit representation of OpenQASM circuit from string");
41 | }
42 |
43 | #endif /* PYQPP_QASM_QASM_BIND_HPP_ */
44 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/random_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_RANDOM_BIND_HPP_
28 | #define PYQPP_RANDOM_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* Some free functions (non-exhaustive list) from random.hpp */
33 | inline void init_random(py::module_& m) {
34 | using namespace qpp;
35 |
36 | m.def("randU", &qpp::randU, "Generates a random unitary matrix",
37 | py::arg("D") = 2);
38 | }
39 |
40 | #endif /* PYQPP_RANDOM_BIND_HPP_ */
41 |
--------------------------------------------------------------------------------
/pyqpp/include/pyqpp/types_bind.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #ifndef PYQPP_TYPES_BIND_HPP_
28 | #define PYQPP_TYPES_BIND_HPP_
29 |
30 | #include "pyqpp/pyqpp_common.hpp"
31 |
32 | /* Types from types.hpp */
33 | inline void init_types(py::module_& m) {
34 | using namespace qpp;
35 |
36 | // supports only complex
37 | using py_dirac_t = dirac_t;
38 |
39 | /* qpp::dirac_t */
40 | auto py_dirac = py::class_(m, "dirac_t");
41 | py_dirac.def(py::self == py::self);
42 | py_dirac.def(py::self != py::self);
43 | py_dirac.def("__copy__",
44 | [](const py_dirac_t& self) { return py_dirac_t(self); });
45 | py_dirac.def("__deepcopy__", [](const py_dirac_t& self, py::dict) {
46 | return py_dirac_t(self);
47 | });
48 | py_dirac.def("__repr__", [](const py_dirac_t& self) {
49 | std::ostringstream oss;
50 | oss << disp(self);
51 | return oss.str();
52 | });
53 |
54 | using py_proxy_to_engine_dits_t = internal::LabelledVectorProxy;
55 | using py_const_proxy_to_engine_dits_t =
56 | internal::LabelledVectorProxy;
57 |
58 | auto py_proxy_to_engine_dits =
59 | py::class_(m, "proxy_to_engine_dits");
60 | py_proxy_to_engine_dits.def(
61 | "__getitem__",
62 | [](const py_proxy_to_engine_dits_t& self, idx i) { return self[i]; });
63 | py_proxy_to_engine_dits.def(
64 | "__setitem__",
65 | [](py_proxy_to_engine_dits_t& self, idx i, idx val) { self[i] = val; });
66 |
67 | auto py_const_proxy_to_engine_dits =
68 | py::class_(
69 | m, "const_proxy_to_engine_dits");
70 | py_const_proxy_to_engine_dits.def(
71 | "__getitem__",
72 | [](py_const_proxy_to_engine_dits_t& self, idx i) { return self[i]; });
73 | }
74 |
75 | #endif /* PYQPP_TYPES_BIND_HPP_ */
76 |
--------------------------------------------------------------------------------
/pyqpp/qpp_wrapper.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of pyqpp.
3 | *
4 | * Copyright (c) 2017 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | #include "pyqpp/pyqpp_common.hpp"
28 |
29 | #include "pyqpp/constants_bind.hpp"
30 | #include "pyqpp/functions_bind.hpp"
31 | #include "pyqpp/instruments_bind.hpp"
32 | #include "pyqpp/random_bind.hpp"
33 | #include "pyqpp/types_bind.hpp"
34 |
35 | #include "pyqpp/classes/gates_bind.hpp"
36 | #include "pyqpp/classes/qcircuit_bind.hpp"
37 | #include "pyqpp/classes/qdummy_engine_bind.hpp"
38 | #include "pyqpp/classes/qengine_bind.hpp"
39 | #include "pyqpp/classes/qnoisy_engine_bind.hpp"
40 | #include "pyqpp/classes/reversible_bind.hpp"
41 | #include "pyqpp/classes/states_bind.hpp"
42 |
43 | #include "pyqpp/qasm/qasm_bind.hpp"
44 |
45 | #include "pyqpp/pyqpp_specific_bind.hpp"
46 |
47 | PYBIND11_MODULE(pyqpp, m) {
48 | m.doc() =
49 | "Python 3 wrapper for Quantum++ (https://github.com/softwareQinc/qpp)";
50 |
51 | init_constants(m);
52 | init_functions(m);
53 | init_instruments(m);
54 | init_random(m);
55 | init_types(m);
56 |
57 | init_classes_gates(m);
58 | init_classes_reversible(m);
59 | init_classes_states(m);
60 |
61 | init_classes_qcircuit(m);
62 | init_classes_qengine(m);
63 | init_classes_qdummy_engine(m);
64 | init_classes_qnoisy_engine(m);
65 |
66 | init_qasm_qasm(m);
67 |
68 | init_pyqpp_specific(m);
69 | }
70 |
--------------------------------------------------------------------------------
/qasmtools/include/qasmtools/ast/ast.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of qasmtools.
3 | *
4 | * Copyright (c) 2019 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qasmtools/ast/ast.hpp
29 | */
30 |
31 | #ifndef QASMTOOLS_AST_AST_HPP_
32 | #define QASMTOOLS_AST_AST_HPP_
33 |
34 | #include "base.hpp"
35 | #include "decl.hpp"
36 | #include "expr.hpp"
37 | #include "program.hpp"
38 | #include "semantic.hpp"
39 | #include "stmt.hpp"
40 | #include "visitor.hpp"
41 |
42 | #endif /* QASMTOOLS_AST_AST_HPP_ */
43 |
--------------------------------------------------------------------------------
/qasmtools/include/qasmtools/ast/base.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of qasmtools.
3 | *
4 | * Copyright (c) 2019 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qasmtools/ast/base.hpp
29 | * \brief OpenQASM syntax trees
30 | */
31 |
32 | #ifndef QASMTOOLS_AST_BASE_HPP_
33 | #define QASMTOOLS_AST_BASE_HPP_
34 |
35 | #include
36 | #include
37 | #include
38 |
39 | #include "../parser/position.hpp"
40 | #include "cloneable.hpp"
41 | #include "visitor.hpp"
42 |
43 | namespace qasmtools {
44 | namespace ast {
45 |
46 | template
47 | using ptr = std::unique_ptr;
48 |
49 | using symbol = std::string;
50 |
51 | /**
52 | * \class qasmtools::ast::ASTNode
53 | * \brief Base class for AST nodes
54 | */
55 | class ASTNode : public object::cloneable {
56 | static int& max_uid_() {
57 | static int v;
58 | return v;
59 | } ///< the maximum uid that has been assigned
60 |
61 | protected:
62 | const int uid_; ///< the node's unique ID
63 | const parser::Position pos_; ///< the node's source code position
64 |
65 | public:
66 | ASTNode(parser::Position pos) : uid_(++max_uid_()), pos_(pos) {}
67 | virtual ~ASTNode() = default;
68 |
69 | /**
70 | * \brief Get the ID of the node
71 | *
72 | * \return The node's unique ID
73 | */
74 | int uid() const { return uid_; }
75 |
76 | /**
77 | * \brief Get the position of the node
78 | *
79 | * \return The node's position in source
80 | */
81 | parser::Position pos() const { return pos_; }
82 |
83 | /**
84 | * \brief Provides dispatch for the Visitor pattern
85 | */
86 | virtual void accept(Visitor& visitor) = 0;
87 |
88 | /**
89 | * \brief Print the formatted QASM source code of the node
90 | *
91 | * \param os Output stream
92 | */
93 | virtual std::ostream& pretty_print(std::ostream& os) const = 0;
94 |
95 | /**
96 | * \brief Extraction operator override
97 | *
98 | * Extraction is non-virtual and delegates to pretty_print
99 | *
100 | * \param os Output stream
101 | * \param node Node to print
102 | */
103 | friend std::ostream& operator<<(std::ostream& os, const ASTNode& node) {
104 | return node.pretty_print(os);
105 | }
106 | };
107 |
108 | } /* namespace ast */
109 | } /* namespace qasmtools */
110 |
111 | #endif /* QASMTOOLS_AST_BASE_HPP_ */
112 |
--------------------------------------------------------------------------------
/qasmtools/include/qasmtools/ast/cloneable.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Covariance and smart pointers. Adapted from
3 | * https://github.com/CppCodeReviewers/Covariant-Return-Types-and-Smart-Pointers
4 | *
5 | * The MIT License (MIT)
6 | *
7 | * Copyright (c) 2014 C++ Code Revievers
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | * SOFTWARE.
26 | */
27 |
28 | /**
29 | * \file qasmtools/ast/cloneable.hpp
30 | * \brief Covariance and smart pointers
31 | */
32 |
33 | #ifndef QASMTOOLS_AST_CLONEABLE_HPP_
34 | #define QASMTOOLS_AST_CLONEABLE_HPP_
35 |
36 | #include
37 |
38 | namespace qasmtools {
39 | namespace ast {
40 |
41 | template
42 | using ptr = std::unique_ptr;
43 |
44 | namespace object {
45 | template
46 | inline ptr clone(const T& object) {
47 | using base_type = typename T::base_type;
48 | static_assert(std::is_base_of::value,
49 | "T object has to derived from T::base_type");
50 | auto ptrr = static_cast(object).clone();
51 | return ptr(static_cast(ptrr));
52 | }
53 |
54 | template
55 | struct cloneable {
56 | using base_type = T;
57 |
58 | virtual ~cloneable() = default;
59 |
60 | protected:
61 | virtual T* clone() const = 0;
62 |
63 | template
64 | friend ptr object::clone(const X&);
65 | };
66 | } /* namespace object */
67 |
68 | } /* namespace ast */
69 | } /* namespace qasmtools */
70 |
71 | #endif /* QASMTOOLS_AST_CLONEABLE_HPP_ */
72 |
--------------------------------------------------------------------------------
/qasmtools/include/qasmtools/ast/visitor.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of qasmtools.
3 | *
4 | * Copyright (c) 2019 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qasmtools/ast/visitor.hpp
29 | * \brief Visitor interface for syntax trees
30 | */
31 |
32 | #ifndef QASMTOOLS_AST_VISITOR_HPP_
33 | #define QASMTOOLS_AST_VISITOR_HPP_
34 |
35 | namespace qasmtools {
36 | namespace ast {
37 |
38 | /* Forward declarations */
39 | class VarAccess;
40 | class BExpr;
41 | class UExpr;
42 | class PiExpr;
43 | class IntExpr;
44 | class RealExpr;
45 | class VarExpr;
46 | class MeasureStmt;
47 | class ResetStmt;
48 | class IfStmt;
49 | class UGate;
50 | class CNOTGate;
51 | class BarrierGate;
52 | class DeclaredGate;
53 | class GateDecl;
54 | class OracleDecl;
55 | class RegisterDecl;
56 | class AncillaDecl;
57 | class Program;
58 |
59 | /**
60 | * \class qasmtools::ast::Visitor
61 | * \brief Base visitor interface
62 | *
63 | * Classic visitor via (virtual) double dispatch. Standard usage is to
64 | * derive from this class and provide implementations of visit for **every**
65 | * node type.
66 | *
67 | * Traversal to sub-nodes is handled by the particular visitor, not the
68 | * node class. For a visitor that automatically handles traversal and also
69 | * allows picking and choosing the particular visit overloads, see
70 | * qasmtools::ast::Traverse.
71 | */
72 | class Visitor {
73 | public:
74 | // Variables
75 | virtual void visit(VarAccess&) = 0;
76 | // Expressions
77 | virtual void visit(BExpr&) = 0;
78 | virtual void visit(UExpr&) = 0;
79 | virtual void visit(PiExpr&) = 0;
80 | virtual void visit(IntExpr&) = 0;
81 | virtual void visit(RealExpr&) = 0;
82 | virtual void visit(VarExpr&) = 0;
83 | // Statements
84 | virtual void visit(MeasureStmt&) = 0;
85 | virtual void visit(ResetStmt&) = 0;
86 | virtual void visit(IfStmt&) = 0;
87 | // Gates
88 | virtual void visit(UGate&) = 0;
89 | virtual void visit(CNOTGate&) = 0;
90 | virtual void visit(BarrierGate&) = 0;
91 | virtual void visit(DeclaredGate&) = 0;
92 | // Declarations
93 | virtual void visit(GateDecl&) = 0;
94 | virtual void visit(OracleDecl&) = 0;
95 | virtual void visit(RegisterDecl&) = 0;
96 | virtual void visit(AncillaDecl&) = 0;
97 | // Program
98 | virtual void visit(Program&) = 0;
99 | // Destructor
100 | virtual ~Visitor() = default;
101 | };
102 |
103 | } /* namespace ast */
104 | } /* namespace qasmtools */
105 |
106 | #endif /* QASMTOOLS_AST_VISITOR_HPP_ */
107 |
--------------------------------------------------------------------------------
/qasmtools/include/qasmtools/parser/position.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of qasmtools.
3 | *
4 | * Copyright (c) 2019 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qasmtools/parser/position.hpp
29 | */
30 |
31 | #ifndef QASMTOOLS_PARSER_POSITION_HPP_
32 | #define QASMTOOLS_PARSER_POSITION_HPP_
33 |
34 | #include
35 | #include
36 |
37 | namespace qasmtools {
38 | namespace parser {
39 |
40 | /**
41 | * \class qasmtools::parser::Position
42 | * \brief Positions in source code
43 | */
44 | class Position {
45 | std::string fname_ = ""; ///< name of the containing file
46 | int line_ = 1; ///< line number
47 | int column_ = 1; ///< column number
48 |
49 | public:
50 | /**
51 | * \brief Default constructor
52 | */
53 | Position() = default;
54 |
55 | /**
56 | * \brief Constructs a position within a file
57 | *
58 | * \param fname Filename
59 | * \param line Line number
60 | * \param column Column number
61 | */
62 | Position(const std::string& fname, int line, int column)
63 | : fname_(fname), line_(line), column_(column) {}
64 |
65 | /**
66 | * \brief Extraction operator overload
67 | *
68 | * \param os Output stream
69 | * \param pos qasmtools::parser::Position
70 | * \return Reference to the output stream
71 | */
72 | friend std::ostream& operator<<(std::ostream& os, const Position& pos) {
73 | os << pos.fname_ << ":" << pos.line_ << ":" << pos.column_;
74 | return os;
75 | }
76 |
77 | /**
78 | * \brief The name of the containing file
79 | *
80 | * \return Const reference to the filename
81 | */
82 | const std::string& get_filename() const { return fname_; }
83 |
84 | /**
85 | * \brief The line of the position
86 | *
87 | * \return The line number
88 | */
89 | int get_linenum() const { return line_; }
90 |
91 | /**
92 | * \brief The column of the position
93 | *
94 | * \return The column number
95 | */
96 | int get_column() const { return column_; }
97 |
98 | /**
99 | * \brief Advance the line number by a specified amount
100 | *
101 | * \note Sets the column to 0
102 | *
103 | * \param num Number of lines to advance (optional, default is 1)
104 | */
105 | void advance_line(int num = 1) {
106 | line_ += num;
107 | column_ = 1;
108 | }
109 |
110 | /**
111 | * \brief Advance the column number by a specified amount
112 | *
113 | * \param num Number of columns to advance (optional, default is 1)
114 | */
115 | void advance_column(int num = 1) { column_ += num; }
116 | };
117 |
118 | } /* namespace parser */
119 | } /* namespace qasmtools */
120 |
121 | #endif /* QASMTOOLS_PARSER_POSITION_HPP_ */
122 |
--------------------------------------------------------------------------------
/qasmtools/include/qasmtools/utils/templates.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of qasmtools.
3 | *
4 | * Copyright (c) 2019 - 2025 softwareQ Inc. All rights reserved.
5 | *
6 | * MIT License
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy
9 | * of this software and associated documentation files (the "Software"), to deal
10 | * in the Software without restriction, including without limitation the rights
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | * copies of the Software, and to permit persons to whom the Software is
13 | * furnished to do so, subject to the following conditions:
14 | *
15 | * The above copyright notice and this permission notice shall be included in
16 | * all copies or substantial portions of the Software.
17 | *
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | * SOFTWARE.
25 | */
26 |
27 | /**
28 | * \file qasmtools/utils/templates.hpp
29 | * \brief Helper templates
30 | */
31 |
32 | #ifndef QASMTOOLS_UTILS_TEMPLATES_HPP_
33 | #define QASMTOOLS_UTILS_TEMPLATES_HPP_
34 |
35 | namespace qasmtools {
36 | namespace utils {
37 | /**
38 | * \brief Convenience template for variant visitors
39 | */
40 | template
41 | struct overloaded : Ts... {
42 | using Ts::operator()...;
43 | };
44 | template
45 | overloaded(Ts...) -> overloaded;
46 |
47 | } /* namespace utils */
48 | } /* namespace qasmtools */
49 |
50 | #endif /* QASMTOOLS_UTILS_TEMPLATES_HPP_ */
51 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/W-state.qasm:
--------------------------------------------------------------------------------
1 | // Name of Experiment: W-state v1
2 |
3 | OPENQASM 2.0;
4 | include "qelib1.inc";
5 |
6 |
7 | qreg q[3];
8 | creg c[3];
9 | gate cH a,b {
10 | h b;
11 | sdg b;
12 | cx a,b;
13 | h b;
14 | t b;
15 | cx a,b;
16 | t b;
17 | h b;
18 | s b;
19 | x b;
20 | s a;
21 | }
22 |
23 | u3(1.91063,0,0) q[0];
24 | cH q[0],q[1];
25 | ccx q[0],q[1],q[2];
26 | x q[0];
27 | x q[1];
28 | cx q[0],q[1];
29 | measure q[0] -> c[0];
30 | measure q[1] -> c[1];
31 | measure q[2] -> c[2];
32 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/adder.qasm:
--------------------------------------------------------------------------------
1 | // quantum ripple-carry adder from Cuccaro et al, quant-ph/0410184
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 | gate majority a,b,c
5 | {
6 | cx c,b;
7 | cx c,a;
8 | ccx a,b,c;
9 | }
10 | gate unmaj a,b,c
11 | {
12 | ccx a,b,c;
13 | cx c,a;
14 | cx a,b;
15 | }
16 | qreg cin[1];
17 | qreg a[4];
18 | qreg b[4];
19 | qreg cout[1];
20 | creg ans[5];
21 | // set input states
22 | x a[0]; // a = 0001
23 | x b; // b = 1111
24 | // add a to b, storing result in b
25 | majority cin[0],b[0],a[0];
26 | majority a[0],b[1],a[1];
27 | majority a[1],b[2],a[2];
28 | majority a[2],b[3],a[3];
29 | cx a[3],cout[0];
30 | unmaj a[2],b[3],a[3];
31 | unmaj a[1],b[2],a[2];
32 | unmaj a[0],b[1],a[1];
33 | unmaj cin[0],b[0],a[0];
34 | measure b[0] -> ans[0];
35 | measure b[1] -> ans[1];
36 | measure b[2] -> ans[2];
37 | measure b[3] -> ans[3];
38 | measure cout[0] -> ans[4];
39 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/bigadder.qasm:
--------------------------------------------------------------------------------
1 | // quantum ripple-carry adder
2 | // 8-bit adder made out of 2 4-bit adders from adder.qasm
3 | // Cuccaro et al, quant-ph/0410184
4 | OPENQASM 2.0;
5 | include "qelib1.inc";
6 | gate majority a,b,c
7 | {
8 | cx c,b;
9 | cx c,a;
10 | ccx a,b,c;
11 | }
12 | gate unmaj a,b,c
13 | {
14 | ccx a,b,c;
15 | cx c,a;
16 | cx a,b;
17 | }
18 |
19 | // add a to b, storing result in b
20 | gate add4 a0,a1,a2,a3,b0,b1,b2,b3,cin,cout
21 | {
22 | majority cin,b0,a0;
23 | majority a0,b1,a1;
24 | majority a1,b2,a2;
25 | majority a2,b3,a3;
26 | cx a3,cout;
27 | unmaj a2,b3,a3;
28 | unmaj a1,b2,a2;
29 | unmaj a0,b1,a1;
30 | unmaj cin,b0,a0;
31 | }
32 |
33 | // add two 8-bit numbers by calling the 4-bit ripple-carry adder
34 | // carry bit on output lives in carry[0]
35 | qreg carry[2];
36 | qreg a[8];
37 | qreg b[8];
38 | creg ans[8];
39 | creg carryout[1];
40 | // set input states
41 | x a[0]; // a = 00000001
42 | x b;
43 | x b[6]; // b = 10111111
44 | // output should be 11000000 0
45 |
46 | add4 a[0],a[1],a[2],a[3],b[0],b[1],b[2],b[3],carry[0],carry[1];
47 | add4 a[4],a[5],a[6],a[7],b[4],b[5],b[6],b[7],carry[1],carry[0];
48 |
49 | measure b[0] -> ans[0];
50 | measure b[1] -> ans[1];
51 | measure b[2] -> ans[2];
52 | measure b[3] -> ans[3];
53 | measure b[4] -> ans[4];
54 | measure b[5] -> ans[5];
55 | measure b[6] -> ans[6];
56 | measure b[7] -> ans[7];
57 | measure carry[0] -> carryout[0];
58 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/inverseqft1.qasm:
--------------------------------------------------------------------------------
1 | // QFT and measure, version 1
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 | qreg q[4];
5 | creg c[4];
6 | h q;
7 | barrier q;
8 | h q[0];
9 | measure q[0] -> c[0];
10 | if(c==1) u1(pi/2) q[1];
11 | h q[1];
12 | measure q[1] -> c[1];
13 | if(c==1) u1(pi/4) q[2];
14 | if(c==2) u1(pi/2) q[2];
15 | if(c==3) u1(pi/2+pi/4) q[2];
16 | h q[2];
17 | measure q[2] -> c[2];
18 | if(c==1) u1(pi/8) q[3];
19 | if(c==2) u1(pi/4) q[3];
20 | if(c==3) u1(pi/4+pi/8) q[3];
21 | if(c==4) u1(pi/2) q[3];
22 | if(c==5) u1(pi/2+pi/8) q[3];
23 | if(c==6) u1(pi/2+pi/4) q[3];
24 | if(c==7) u1(pi/2+pi/4+pi/8) q[3];
25 | h q[3];
26 | measure q[3] -> c[3];
27 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/inverseqft2.qasm:
--------------------------------------------------------------------------------
1 | // QFT and measure, version 2
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 | qreg q[4];
5 | creg c0[1];
6 | creg c1[1];
7 | creg c2[1];
8 | creg c3[1];
9 | h q;
10 | barrier q;
11 | h q[0];
12 | measure q[0] -> c0[0];
13 | if(c0==1) u1(pi/2) q[1];
14 | h q[1];
15 | measure q[1] -> c1[0];
16 | if(c0==1) u1(pi/4) q[2];
17 | if(c1==1) u1(pi/2) q[2];
18 | h q[2];
19 | measure q[2] -> c2[0];
20 | if(c0==1) u1(pi/8) q[3];
21 | if(c1==1) u1(pi/4) q[3];
22 | if(c2==1) u1(pi/2) q[3];
23 | h q[3];
24 | measure q[3] -> c3[0];
25 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/ipea_3_pi_8.qasm:
--------------------------------------------------------------------------------
1 | // Name of Experiment: ipea_3*pi/8 v2
2 |
3 | OPENQASM 2.0;
4 | include "qelib1.inc";
5 |
6 | qreg q[2];
7 | creg c[4];
8 | gate cu1fixed (a) c,t {
9 | u1 (-a) t;
10 | cx c,t;
11 | u1 (a) t;
12 | cx c,t;
13 | }
14 | gate cu c,t {
15 | cu1fixed (3*pi/8) c,t;
16 | }
17 |
18 | h q[0];
19 | cu q[0],q[1];
20 | cu q[0],q[1];
21 | cu q[0],q[1];
22 | cu q[0],q[1];
23 | cu q[0],q[1];
24 | cu q[0],q[1];
25 | cu q[0],q[1];
26 | cu q[0],q[1];
27 | h q[0];
28 | measure q[0] -> c[0];
29 | reset q[0];
30 | h q[0];
31 | cu q[0],q[1];
32 | cu q[0],q[1];
33 | cu q[0],q[1];
34 | cu q[0],q[1];
35 | if(c==1) u1(-pi/2) q[0];
36 | h q[0];
37 | measure q[0] -> c[1];
38 | reset q[0];
39 | h q[0];
40 | cu q[0],q[1];
41 | cu q[0],q[1];
42 | if(c==1) u1(-pi/4) q[0];
43 | if(c==2) u1(-pi/2) q[0];
44 | if(c==3) u1(-3*pi/4) q[0];
45 | h q[0];
46 | measure q[0] -> c[2];
47 | reset q[0];
48 | h q[0];
49 | cu q[0],q[1];
50 | if(c==1) u1(-pi/8) q[0];
51 | if(c==2) u1(-2*pi/8) q[0];
52 | if(c==3) u1(-3*pi/8) q[0];
53 | if(c==4) u1(-4*pi/8) q[0];
54 | if(c==5) u1(-5*pi/8) q[0];
55 | if(c==6) u1(-6*pi/8) q[0];
56 | if(c==7) u1(-7*pi/8) q[0];
57 | h q[0];
58 | measure q[0] -> c[3];
59 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/pea_3_pi_8.qasm:
--------------------------------------------------------------------------------
1 | // Name of Experiment: pea_3*pi/8 v3
2 |
3 | OPENQASM 2.0;
4 | include "qelib1.inc";
5 |
6 |
7 | qreg q[5];
8 | creg c[4];
9 | gate cu1fixed (a) c,t {
10 | u1 (-a) t;
11 | cx c,t;
12 | u1 (a) t;
13 | cx c,t;
14 | }
15 | gate cu c,t {
16 | cu1fixed (3*pi/8) c,t;
17 | }
18 |
19 | h q[0];
20 | h q[1];
21 | h q[2];
22 | h q[3];
23 | cu q[3],q[4];
24 | cu q[2],q[4];
25 | cu q[2],q[4];
26 | cu q[1],q[4];
27 | cu q[1],q[4];
28 | cu q[1],q[4];
29 | cu q[1],q[4];
30 | cu q[0],q[4];
31 | cu q[0],q[4];
32 | cu q[0],q[4];
33 | cu q[0],q[4];
34 | cu q[0],q[4];
35 | cu q[0],q[4];
36 | cu q[0],q[4];
37 | cu q[0],q[4];
38 | h q[0];
39 | cu1(-pi/2) q[0],q[1];
40 | h q[1];
41 | cu1(-pi/4) q[0],q[2];
42 | cu1(-pi/2) q[1],q[2];
43 | h q[2];
44 | cu1(-pi/8) q[0],q[3];
45 | cu1(-pi/4) q[1],q[3];
46 | cu1(-pi/2) q[2],q[3];
47 | h q[3];
48 | measure q[0] -> c[0];
49 | measure q[1] -> c[1];
50 | measure q[2] -> c[2];
51 | measure q[3] -> c[3];
52 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/qec.qasm:
--------------------------------------------------------------------------------
1 | // Repetition code syndrome measurement
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 | qreg q[3];
5 | qreg a[2];
6 | creg c[3];
7 | creg syn[2];
8 | gate syndrome d1,d2,d3,a1,a2
9 | {
10 | cx d1,a1; cx d2,a1;
11 | cx d2,a2; cx d3,a2;
12 | }
13 | x q[0]; // error
14 | barrier q;
15 | syndrome q[0],q[1],q[2],a[0],a[1];
16 | measure a -> syn;
17 | if(syn==1) x q[0];
18 | if(syn==2) x q[2];
19 | if(syn==3) x q[1];
20 | measure q -> c;
21 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/qelib1.inc:
--------------------------------------------------------------------------------
1 | // Quantum Experience (QE) Standard Header
2 | // file: qelib1.inc
3 |
4 | // --- QE Hardware primitives ---
5 |
6 | // 3-parameter 2-pulse single qubit gate
7 | gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }
8 | // 2-parameter 1-pulse single qubit gate
9 | gate u2(phi,lambda) q { U(pi/2,phi,lambda) q; }
10 | // 1-parameter 0-pulse single qubit gate
11 | gate u1(lambda) q { U(0,0,lambda) q; }
12 | // controlled-NOT
13 | gate cx c,t { CX c,t; }
14 | // idle gate (identity)
15 | gate id a { U(0,0,0) a; }
16 |
17 | // --- QE Standard Gates ---
18 |
19 | // Pauli gate: bit-flip
20 | gate x a { u3(pi,0,pi) a; }
21 | // Pauli gate: bit and phase flip
22 | gate y a { u3(pi,pi/2,pi/2) a; }
23 | // Pauli gate: phase flip
24 | gate z a { u1(pi) a; }
25 | // Clifford gate: Hadamard
26 | gate h a { u2(0,pi) a; }
27 | // Clifford gate: sqrt(Z) phase gate
28 | gate s a { u1(pi/2) a; }
29 | // Clifford gate: conjugate of sqrt(Z)
30 | gate sdg a { u1(-pi/2) a; }
31 | // C3 gate: sqrt(S) phase gate
32 | gate t a { u1(pi/4) a; }
33 | // C3 gate: conjugate of sqrt(S)
34 | gate tdg a { u1(-pi/4) a; }
35 |
36 | // --- Standard rotations ---
37 | // Rotation around X-axis
38 | gate rx(theta) a { u3(theta,-pi/2,pi/2) a; }
39 | // rotation around Y-axis
40 | gate ry(theta) a { u3(theta,0,0) a; }
41 | // rotation around Z axis
42 | gate rz(phi) a { u1(phi) a; }
43 |
44 | // --- QE Standard User-Defined Gates ---
45 |
46 | // controlled-Phase
47 | gate cz a,b { h b; cx a,b; h b; }
48 | // controlled-Y
49 | gate cy a,b { sdg b; cx a,b; s b; }
50 | // controlled-H
51 | gate ch a,b {
52 | h b; sdg b;
53 | cx a,b;
54 | h b; t b;
55 | cx a,b;
56 | t b; h b; s b; x b; s a;
57 | }
58 | // C3 gate: Toffoli
59 | gate ccx a,b,c
60 | {
61 | h c;
62 | cx b,c; tdg c;
63 | cx a,c; t c;
64 | cx b,c; tdg c;
65 | cx a,c; t b; t c; h c;
66 | cx a,b; t a; tdg b;
67 | cx a,b;
68 | }
69 | // controlled rz rotation
70 | gate crz(lambda) a,b
71 | {
72 | u1(lambda/2) b;
73 | cx a,b;
74 | u1(-lambda/2) b;
75 | cx a,b;
76 | }
77 | // controlled phase rotation
78 | gate cu1(lambda) a,b
79 | {
80 | u1(lambda/2) a;
81 | cx a,b;
82 | u1(-lambda/2) b;
83 | cx a,b;
84 | u1(lambda/2) b;
85 | }
86 | // controlled-U
87 | gate cu3(theta,phi,lambda) c, t
88 | {
89 | // implements controlled-U(theta,phi,lambda) with target t and control c
90 | u1((lambda-phi)/2) t;
91 | cx c,t;
92 | u3(-theta/2,0,-(phi+lambda)/2) t;
93 | cx c,t;
94 | u3(theta/2,phi,0) t;
95 | }
96 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/qft.qasm:
--------------------------------------------------------------------------------
1 | // quantum Fourier transform
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 | qreg q[4];
5 | creg c[4];
6 | x q[0];
7 | x q[2];
8 | barrier q;
9 | h q[0];
10 | cu1(pi/2) q[1],q[0];
11 | h q[1];
12 | cu1(pi/4) q[2],q[0];
13 | cu1(pi/2) q[2],q[1];
14 | h q[2];
15 | cu1(pi/8) q[3],q[0];
16 | cu1(pi/4) q[3],q[1];
17 | cu1(pi/2) q[3],q[2];
18 | h q[3];
19 | measure q -> c;
20 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/qpt.qasm:
--------------------------------------------------------------------------------
1 | OPENQASM 2.0;
2 | include "qelib1.inc";
3 | gate pre q { } // pre-rotation
4 | gate post q { } // post-rotation
5 | qreg q[1];
6 | creg c[1];
7 | pre q[0];
8 | barrier q;
9 | h q[0];
10 | barrier q;
11 | post q[0];
12 | measure q[0] -> c[0];
13 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/rb.qasm:
--------------------------------------------------------------------------------
1 | // One randomized benchmarking sequence
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 | qreg q[2];
5 | creg c[2];
6 | h q[0];
7 | barrier q;
8 | cz q[0],q[1];
9 | barrier q;
10 | s q[0];
11 | cz q[0],q[1];
12 | barrier q;
13 | s q[0];
14 | z q[0];
15 | h q[0];
16 | barrier q;
17 | measure q -> c;
18 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/teleport.qasm:
--------------------------------------------------------------------------------
1 | // quantum teleportation example
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 | qreg q[3];
5 | creg c0[1];
6 | creg c1[1];
7 | creg c2[1];
8 | // optional post-rotation for state tomography
9 | gate post q { }
10 | u3(0.3,0.2,0.1) q[0];
11 | h q[1];
12 | cx q[1],q[2];
13 | barrier q;
14 | cx q[0],q[1];
15 | h q[0];
16 | measure q[0] -> c0[0];
17 | measure q[1] -> c1[0];
18 | if(c1==1) x q[2];
19 | if(c0==1) z q[2];
20 | post q[2];
21 | measure q[2] -> c2[0];
22 |
--------------------------------------------------------------------------------
/qasmtools/qasm/generic/teleportv2.qasm:
--------------------------------------------------------------------------------
1 | // quantum teleportation example
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 | qreg q[3];
5 | creg c[3];
6 | // optional post-rotation for state tomography
7 | gate post q { }
8 | u3(0.3,0.2,0.1) q[0];
9 | h q[1];
10 | cx q[1],q[2];
11 | barrier q;
12 | cx q[0],q[1];
13 | h q[0];
14 | measure q[0] -> c[0];
15 | measure q[1] -> c[1];
16 | if(c==1) z q[2];
17 | if(c==2) x q[2];
18 | if(c==3) y q[2];
19 | post q[2];
20 | measure q[2] -> c[2];
21 |
--------------------------------------------------------------------------------
/qasmtools/qasm/ibmqx2/011_3_qubit_grover_50_.qasm:
--------------------------------------------------------------------------------
1 | // Name of Experiment: 011 3 qubit grover 50% v1
2 | // Description: A 3 qubit grover amplification repeated twice
3 |
4 | OPENQASM 2.0;
5 | include "qelib1.inc";
6 |
7 | qreg q[5];
8 | creg c[3];
9 |
10 | h q[0];
11 | h q[1];
12 | h q[2];
13 | s q[0];
14 | s q[1];
15 | s q[2];
16 | cx q[1],q[2];
17 | tdg q[2];
18 | cx q[0],q[2];
19 | t q[2];
20 | cx q[1],q[2];
21 | tdg q[2];
22 | cx q[0],q[2];
23 | t q[1];
24 | t q[2];
25 | cx q[1],q[2];
26 | h q[1];
27 | h q[2];
28 | cx q[1],q[2];
29 | h q[1];
30 | h q[2];
31 | cx q[1],q[2];
32 | cx q[0],q[2];
33 | t q[0];
34 | h q[1];
35 | tdg q[2];
36 | cx q[0],q[2];
37 | s q[0];
38 | s q[1];
39 | s q[2];
40 | h q[0];
41 | h q[1];
42 | h q[2];
43 | x q[0];
44 | x q[1];
45 | x q[2];
46 | cx q[1],q[2];
47 | tdg q[2];
48 | cx q[0],q[2];
49 | t q[2];
50 | cx q[1],q[2];
51 | tdg q[2];
52 | cx q[0],q[2];
53 | t q[1];
54 | t q[2];
55 | cx q[1],q[2];
56 | h q[1];
57 | h q[2];
58 | cx q[1],q[2];
59 | h q[1];
60 | h q[2];
61 | cx q[1],q[2];
62 | cx q[0],q[2];
63 | t q[0];
64 | h q[1];
65 | tdg q[2];
66 | cx q[0],q[2];
67 | x q[0];
68 | x q[1];
69 | x q[2];
70 | h q[0];
71 | h q[1];
72 | h q[2];
73 | s q[0];
74 | s q[1];
75 | s q[2];
76 | cx q[1],q[2];
77 | tdg q[2];
78 | cx q[0],q[2];
79 | t q[2];
80 | cx q[1],q[2];
81 | tdg q[2];
82 | cx q[0],q[2];
83 | t q[1];
84 | t q[2];
85 | cx q[1],q[2];
86 | h q[1];
87 | h q[2];
88 | cx q[1],q[2];
89 | h q[1];
90 | h q[2];
91 | cx q[1],q[2];
92 | cx q[0],q[2];
93 | t q[0];
94 | h q[1];
95 | tdg q[2];
96 | cx q[0],q[2];
97 | s q[0];
98 | s q[1];
99 | s q[2];
100 | h q[0];
101 | h q[1];
102 | h q[2];
103 | x q[0];
104 | x q[1];
105 | x q[2];
106 | cx q[1],q[2];
107 | tdg q[2];
108 | cx q[0],q[2];
109 | t q[2];
110 | cx q[1],q[2];
111 | tdg q[2];
112 | cx q[0],q[2];
113 | t q[1];
114 | t q[2];
115 | cx q[1],q[2];
116 | h q[1];
117 | h q[2];
118 | cx q[1],q[2];
119 | h q[1];
120 | h q[2];
121 | cx q[1],q[2];
122 | cx q[0],q[2];
123 | t q[0];
124 | h q[1];
125 | tdg q[2];
126 | cx q[0],q[2];
127 | x q[0];
128 | x q[1];
129 | x q[2];
130 | h q[0];
131 | h q[1];
132 | h q[2];
133 | measure q[0] -> c[0];
134 | measure q[1] -> c[1];
135 | measure q[2] -> c[2];
136 |
--------------------------------------------------------------------------------
/qasmtools/qasm/ibmqx2/Deutsch_Algorithm.qasm:
--------------------------------------------------------------------------------
1 | // Implementation of Deutsch algorithm with two qubits for f(x)=x
2 | OPENQASM 2.0;
3 | include "qelib1.inc";
4 |
5 | qreg q[5];
6 | creg c[5];
7 |
8 | x q[4];
9 | h q[3];
10 | h q[4];
11 | cx q[3],q[4];
12 | h q[3];
13 | measure q[3] -> c[3];
14 |
--------------------------------------------------------------------------------
/qasmtools/qasm/ibmqx2/W3test.qasm:
--------------------------------------------------------------------------------
1 | // Name of Experiment: W3test v1
2 | // example of W-state |001> + |010> + |100>
3 | // found by user lukasknips at http://ibm.biz/qiskit-W3-Example
4 |
5 | OPENQASM 2.0;
6 | include "qelib1.inc";
7 |
8 |
9 | qreg q[5];
10 | creg c[5];
11 |
12 | u3(-1.23096,0,0) q[0];
13 | u3(pi/4,0,0) q[1];
14 | cx q[0],q[2];
15 | z q[2];
16 | h q[2];
17 | cx q[1],q[2];
18 | z q[2];
19 | u3(pi/4,0,0) q[1];
20 | h q[2];
21 | cx q[1],q[2];
22 | measure q[0] -> c[0];
23 | measure q[1] -> c[1];
24 | measure q[2] -> c[2];
25 |
--------------------------------------------------------------------------------
/qasmtools/qasm/ibmqx2/images/5qubitQXlabeled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/softwareQinc/qpp/c96fcb0d9c3308f0e5d06738797f557b082b0515/qasmtools/qasm/ibmqx2/images/5qubitQXlabeled.png
--------------------------------------------------------------------------------
/qasmtools/qasm/ibmqx2/iswap.qasm:
--------------------------------------------------------------------------------
1 | // Name of Experiment: iswap v4
2 |
3 | OPENQASM 2.0;
4 | include "qelib1.inc";
5 |
6 | qreg q[5];
7 | creg c[5];
8 |
9 | x q[0];
10 | s q[0];
11 | s q[1];
12 | h q[0];
13 | cx q[0],q[1];
14 | h q[0];
15 | h q[1];
16 | cx q[0],q[1];
17 | h q[0];
18 | measure q[0] -> c[0];
19 | measure q[1] -> c[1];
20 |
--------------------------------------------------------------------------------
/qasmtools/qasm/ibmqx2/qe_qft_3.qasm:
--------------------------------------------------------------------------------
1 | // quantum Fourier transform for the Quantum Experience
2 | // on the first 3 qubits
3 |
4 | OPENQASM 2.0;
5 | include "qelib1.inc";
6 |
7 | // Register declarations
8 | qreg q[5];
9 | creg c[5];
10 |
11 | // Choose starting state
12 | // ** Put your code here **
13 |
14 | // Quantum Fourier transform
15 | // For this small example, we have full connectivity.
16 |
17 | h q[0];
18 | // cu1(pi/2) q[0],q[1];
19 | u1(pi/4) q[0];
20 | cx q[0],q[1];
21 | u1(-pi/4) q[1];
22 | cx q[0],q[1];
23 | u1(pi/4) q[1];
24 | // end cu1
25 | h q[1];
26 | // cu1(pi/4) q[0],q[2];
27 | u1(pi/8) q[0];
28 | cx q[0],q[2];
29 | u1(-pi/8) q[2];
30 | cx q[0],q[2];
31 | u1(pi/8) q[2];
32 | // end cu1
33 | // cu1(pi/2) q[1],q[2];
34 | u1(pi/4) q[1];
35 | cx q[1],q[2];
36 | u1(-pi/4) q[2];
37 | cx q[1],q[2];
38 | u1(pi/4) q[2];
39 | // end cu1
40 | h q[2];
41 |
42 | // Outputs are q[2], q[1], q[0]
43 |
44 | // Choose measurement
45 | // ** Put your code here **
46 |
47 | measure q -> c;
48 |
--------------------------------------------------------------------------------
/qasmtools/qasm/ibmqx2/qe_qft_4.qasm:
--------------------------------------------------------------------------------
1 | // quantum Fourier transform for the Quantum Experience
2 | // on the first 4 qubits
3 |
4 | OPENQASM 2.0;
5 | include "qelib1.inc";
6 |
7 | // Register declarations
8 | qreg q[5];
9 | creg c[5];
10 |
11 | // Choose starting state
12 | // ** Put your code here **
13 |
14 | // Quantum Fourier transform
15 |
16 | u1(0.196349540849362) q[3];
17 | u2(0.0,3.5342917352885173) q[2];
18 | u2(0.0,3.9269908169872414) q[1];
19 | u1(6.283185307179586) q[0];
20 | cx q[0],q[1];
21 | u1(6.283185307179586) q[1];
22 | u3(0.7853981633974485,1.5707963267948966,4.71238898038469) q[0];
23 | cx q[0],q[1];
24 | u1(6.283185307179586) q[1];
25 | u3(-0.7853981633974485,1.5707963267948966,4.71238898038469) q[0];
26 | cx q[0],q[2];
27 | u1(6.283185307179586) q[2];
28 | u3(0.392699081698724,1.5707963267948966,4.71238898038469) q[0];
29 | cx q[0],q[2];
30 | u2(0.7853981633974485,3.141592653589793) q[2];
31 | u2(0.392699081698724,3.141592653589793) q[0];
32 | cx q[0],q[2];
33 | u2(0.0,3.141592653589793) q[0];
34 | u2(0.0,3.141592653589793) q[2];
35 | cx q[0],q[2];
36 | u2(0.0,3.141592653589793) q[2];
37 | u2(0.0,3.141592653589793) q[0];
38 | cx q[0],q[2];
39 | cx q[0],q[1];
40 | u1(-0.7853981633974485) q[1];
41 | cx q[0],q[1];
42 | u2(0.0,3.141592653589793) q[0];
43 | u1(0.7853981633974485) q[1];
44 | cx q[3],q[4];
45 | u2(0.0,3.141592653589793) q[3];
46 | u2(0.0,3.141592653589793) q[4];
47 | cx q[3],q[4];
48 | u2(0.0,3.141592653589793) q[4];
49 | u2(0.0,3.141592653589793) q[3];
50 | cx q[3],q[4];
51 | cx q[4],q[2];
52 | u1(-0.196349540849362) q[2];
53 | cx q[4],q[2];
54 | u1(0.392699081698724) q[4];
55 | u1(0.196349540849362) q[2];
56 | cx q[1],q[2];
57 | u2(0.0,3.141592653589793) q[1];
58 | u2(0.0,3.141592653589793) q[2];
59 | cx q[1],q[2];
60 | u2(0.0,3.141592653589793) q[2];
61 | u2(0.0,3.141592653589793) q[1];
62 | cx q[1],q[2];
63 | cx q[4],q[2];
64 | u1(-0.392699081698724) q[2];
65 | cx q[4],q[2];
66 | u1(0.7853981633974485) q[4];
67 | u1(0.392699081698724) q[2];
68 | cx q[0],q[2];
69 | u2(0.0,3.141592653589793) q[0];
70 | u2(0.0,3.141592653589793) q[2];
71 | cx q[0],q[2];
72 | u2(0.0,3.141592653589793) q[2];
73 | u2(0.0,3.141592653589793) q[0];
74 | cx q[0],q[2];
75 | cx q[3],q[4];
76 | u2(0.0,3.141592653589793) q[3];
77 | u2(0.0,3.141592653589793) q[4];
78 | cx q[3],q[4];
79 | u2(0.0,3.141592653589793) q[4];
80 | u2(0.0,3.141592653589793) q[3];
81 | cx q[3],q[4];
82 | cx q[3],q[2];
83 | u1(-0.7853981633974485) q[2];
84 | cx q[3],q[2];
85 | u2(0.0,3.141592653589793) q[3];
86 | u1(0.7853981633974485) q[2];
87 |
88 | // Outputs are q[3], q[2], q[0], q[1]
89 | // (LSB on the right)
90 |
91 | measure q -> c;
92 |
--------------------------------------------------------------------------------
/qasmtools/qasm/ibmqx2/qe_qft_5.qasm:
--------------------------------------------------------------------------------
1 | // quantum Fourier transform for the Quantum Experience
2 | // on all 5 qubits
3 |
4 | OPENQASM 2.0;
5 | include "qelib1.inc";
6 |
7 | // Register declarations
8 | qreg q[5];
9 | creg c[5];
10 |
11 | // Choose starting state
12 | // ** Put your code here **
13 |
14 | // Quantum Fourier transform
15 | u2(0.0,3.2397674240144743) q[4];
16 | u1(0.196349540849362) q[3];
17 | u2(0.0,3.5342917352885173) q[2];
18 | u2(0.0,3.9269908169872414) q[1];
19 | u1(6.283185307179586) q[0];
20 | cx q[0],q[1];
21 | u1(6.283185307179586) q[1];
22 | u3(0.7853981633974485,1.5707963267948966,4.71238898038469) q[0];
23 | cx q[0],q[1];
24 | u1(6.283185307179586) q[1];
25 | u3(-0.7853981633974485,1.5707963267948966,4.71238898038469) q[0];
26 | cx q[0],q[2];
27 | u1(6.283185307179586) q[2];
28 | u3(0.392699081698724,1.5707963267948966,4.71238898038469) q[0];
29 | cx q[0],q[2];
30 | u2(0.7853981633974485,3.141592653589793) q[2];
31 | u2(0.392699081698724,3.141592653589793) q[0];
32 | cx q[0],q[2];
33 | u2(0.0,3.141592653589793) q[0];
34 | u2(0.0,3.141592653589793) q[2];
35 | cx q[0],q[2];
36 | u2(0.0,3.141592653589793) q[2];
37 | u2(0.0,3.141592653589793) q[0];
38 | cx q[0],q[2];
39 | cx q[0],q[1];
40 | u1(-0.7853981633974485) q[1];
41 | cx q[0],q[1];
42 | u2(0.0,3.141592653589793) q[0];
43 | u1(0.7853981633974485) q[1];
44 | cx q[0],q[1];
45 | u2(0.0,3.141592653589793) q[0];
46 | u2(0.0,3.141592653589793) q[1];
47 | cx q[0],q[1];
48 | u2(0.0,3.141592653589793) q[1];
49 | u2(0.0,3.141592653589793) q[0];
50 | cx q[0],q[1];
51 | u2(0.0,3.141592653589793) q[0];
52 | cx q[3],q[2];
53 | u1(-0.196349540849362) q[2];
54 | cx q[3],q[2];
55 | u1(0.392699081698724) q[3];
56 | u1(0.196349540849362) q[2];
57 | cx q[3],q[2];
58 | u2(0.0,3.141592653589793) q[3];
59 | u2(0.0,3.141592653589793) q[2];
60 | cx q[3],q[2];
61 | u2(0.0,3.141592653589793) q[2];
62 | u2(0.0,3.141592653589793) q[3];
63 | cx q[3],q[2];
64 | u2(0.0,3.141592653589793) q[2];
65 | cx q[0],q[2];
66 | u1(6.283185307179586) q[2];
67 | u3(0.392699081698724,1.5707963267948966,4.71238898038469) q[0];
68 | cx q[0],q[2];
69 | u2(0.7853981633974485,3.141592653589793) q[2];
70 | u2(0.392699081698724,3.141592653589793) q[0];
71 | cx q[0],q[2];
72 | u2(0.0,3.141592653589793) q[0];
73 | u2(0.0,3.141592653589793) q[2];
74 | cx q[0],q[2];
75 | u2(0.0,3.141592653589793) q[2];
76 | u2(0.0,3.141592653589793) q[0];
77 | cx q[0],q[2];
78 | cx q[0],q[1];
79 | u1(-0.7853981633974485) q[1];
80 | cx q[0],q[1];
81 | u1(6.283185307179586) q[0];
82 | u2(0.0,3.9269908169872414) q[1];
83 | u2(0.0,3.141592653589793) q[3];
84 | cx q[3],q[4];
85 | u1(6.283185307179586) q[4];
86 | u3(0.098174770424681,1.5707963267948966,4.71238898038469) q[3];
87 | cx q[3],q[4];
88 | u2(0.196349540849362,3.141592653589793) q[4];
89 | u2(0.098174770424681,3.141592653589793) q[3];
90 | cx q[3],q[4];
91 | u2(0.0,3.141592653589793) q[3];
92 | u2(0.0,3.141592653589793) q[4];
93 | cx q[3],q[4];
94 | u2(0.0,3.141592653589793) q[4];
95 | u2(0.0,3.141592653589793) q[3];
96 | cx q[3],q[4];
97 | cx q[3],q[2];
98 | u1(-0.196349540849362) q[2];
99 | cx q[3],q[2];
100 | u1(0.392699081698724) q[3];
101 | u1(0.196349540849362) q[2];
102 | cx q[3],q[2];
103 | u2(0.0,3.141592653589793) q[3];
104 | u2(0.0,3.141592653589793) q[2];
105 | cx q[3],q[2];
106 | u2(0.0,3.141592653589793) q[2];
107 | u2(0.0,3.141592653589793) q[3];
108 | cx q[3],q[2];
109 | u2(0.0,3.141592653589793) q[2];
110 | cx q[1],q[2];
111 | u1(6.283185307179586) q[2];
112 | u3(0.392699081698724,1.5707963267948966,4.71238898038469) q[1];
113 | cx q[1],q[2];
114 | u3(-0.7853981633974485,1.5707963267948966,4.71238898038469) q[2];
115 | cx q[0],q[2];
116 | u1(6.283185307179586) q[2];
117 | u3(0.7853981633974485,1.5707963267948966,4.71238898038469) q[0];
118 | cx q[0],q[2];
119 | u1(6.283185307179586) q[2];
120 | u2(0.7853981633974485,3.141592653589793) q[0];
121 | u2(0.392699081698724,3.141592653589793) q[1];
122 |
123 | // Outputs are q[2], q[0], q[1], q[3], q[4]
124 | // (LSB on the right)
125 |
126 | measure q -> c;
127 |
--------------------------------------------------------------------------------
/qasmtools/qasm/invalid/gate_no_found.qasm:
--------------------------------------------------------------------------------
1 | // name: Gate not found
2 | // section: TODO
3 | OPENQASM 2.0;
4 | qreg q[1];
5 | w q;
6 | creg c[1];
7 | measure q->c;
8 |
--------------------------------------------------------------------------------
/qasmtools/qasm/invalid/missing_semicolon.qasm:
--------------------------------------------------------------------------------
1 | // name: missing semicolon
2 | // section: TODO
3 | OPENQASM 2.0
4 | qreg q[1];
5 | creg c[1];
6 | measure q->c;
7 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | import sys
3 |
4 | from pybind11.setup_helpers import Pybind11Extension
5 | from setuptools import setup
6 |
7 | p = subprocess.Popen(
8 | "cmake -S pyqpp -B pyqpp/build",
9 | shell=True,
10 | stdout=subprocess.PIPE,
11 | stderr=subprocess.STDOUT,
12 | )
13 |
14 | prefix_eigen = "Detected Eigen3 in: "
15 | prefix_pybind11 = "Detected pybind11 in: "
16 | eigen_path = None
17 | pybind11_path = None
18 |
19 | print("Running cmake -S pyqpp -B pyqpp/build")
20 | cmake_output = p.stdout.read().decode("ascii").split("\n")
21 | for line in cmake_output:
22 | print(line)
23 | pos_eigen = line.find(prefix_eigen)
24 | pos_pybind11 = line.find(prefix_pybind11)
25 | if pos_eigen != -1:
26 | eigen_path = line[pos_eigen + len(prefix_eigen) :]
27 | if pos_pybind11 != -1:
28 | pybind11_path = line[pos_pybind11 + len(prefix_pybind11) :]
29 |
30 | if eigen_path is None:
31 | raise Exception("Eigen3 not found!")
32 |
33 | if pybind11_path is None:
34 | raise Exception("pybind11 not found!")
35 |
36 | source_files = ["pyqpp/qpp_wrapper.cpp"]
37 | ext_modules = [
38 | Pybind11Extension(
39 | "pyqpp",
40 | source_files,
41 | extra_compile_args=[
42 | "-I" + pybind11_path + "/include",
43 | "-I" + eigen_path,
44 | "-Iinclude",
45 | "-Iqasmtools/include",
46 | "-Ipyqpp/include",
47 | "-DQPP_IDX_DEFAULT",
48 | "-DQPP_BIGINT_DEFAULT",
49 | "-DQPP_FP_DEFAULT",
50 | ],
51 | cxx_std=17,
52 | include_pybind11=False,
53 | ),
54 | ]
55 |
56 | setup(platforms=sys.platform, ext_modules=ext_modules)
57 |
--------------------------------------------------------------------------------
/stress_tests/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
103 | # PyCharm & virtualenv
104 | .idea
105 | bin/
106 | include/
107 | lib/
108 | spell/
109 | pip-selfcheck.json
110 | pyvenv.cfg
111 |
112 | # vim
113 | *.swp
114 |
115 | ./build
116 | results*
117 |
--------------------------------------------------------------------------------
/stress_tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | project(stress_tests LANGUAGES CXX)
3 | set(CMAKE_CXX_STANDARD 17)
4 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
5 | set(CMAKE_CXX_EXTENSIONS OFF)
6 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
7 |
8 | # Guard against in-source builds (snippet from Eigen's CMakeLists.txt)
9 | if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
10 | message(
11 | FATAL_ERROR
12 | "In-source builds not allowed. Please instruct CMake to use an\
13 | out-of-source build, e.g.,
14 | cmake -B build && cmake --build build
15 | You may need to remove CMakeCache.txt.")
16 | endif()
17 |
18 | add_library(libqpp INTERFACE)
19 | target_include_directories(
20 | libqpp INTERFACE $)
21 |
22 | # qasmtools library
23 | target_include_directories(
24 | libqpp
25 | INTERFACE $
26 | )
27 |
28 | # Dependencies, do not modify unless you know what you're doing
29 | include(../cmake/qpp_eigen3.cmake)
30 |
31 | # Dependencies, do not modify unless you know what you're doing
32 | include(../cmake/qpp_dependencies.cmake)
33 |
34 | # Enable all warnings for GCC and Clang/AppleClang
35 | if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" OR ${CMAKE_CXX_COMPILER_ID}
36 | STREQUAL "GNU")
37 | add_compile_options("-pedantic" "-Wall" "-Wextra" "-Weffc++")
38 | if(${SANITIZE})
39 | if(NOT (${CMAKE_CXX_COMPILER_ID} MATCHES "AppleClang"))
40 | list(APPEND SANITIZE_OPTIONS -fsanitize=undefined)
41 | add_compile_options("${SANITIZE_OPTIONS}")
42 | set(CMAKE_EXE_LINKER_FLAGS
43 | "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZE_OPTIONS}")
44 | endif()
45 | endif()
46 | endif()
47 |
48 | # Source file(s) to be compiled, modify as needed
49 | aux_source_directory(${CMAKE_SOURCE_DIR}/src STRESS_TESTS)
50 |
51 | # Build all stress tests in ${STRESS_TESTS}
52 | foreach(file ${STRESS_TESTS})
53 | get_filename_component(TARGET_NAME ${file} NAME_WE)
54 | add_executable(${TARGET_NAME} ${file})
55 | target_link_libraries(${TARGET_NAME} PUBLIC ${QPP_LINK_DEPS} libqpp)
56 | endforeach()
57 |
--------------------------------------------------------------------------------
/stress_tests/README.md:
--------------------------------------------------------------------------------
1 | # Deprecated stress test suite - preserved solely for reference purposes.
2 |
3 | ## Stress test suite (for POSIX compliant systems)
4 |
5 | Tests some quantum circuit/operation as a function of the number of cores of
6 | the machine and number of qubits (hard-coded in the script `run.sh`). Records
7 | the time for each such run in `results_$DATE.csv`, where `$DATE` represents the
8 | current date and time of the run. Requires [OpenMP](https://www.openmp.org/).
9 |
10 | To compile, I recommend using [CMake](https://cmake.org), then perform an
11 | out-of-source build. Assuming you are at the root of this project, i.e., inside
12 | `qpp/stress_test`, type
13 |
14 | ```bash
15 | cmake -B build
16 | cmake --build build --parallel 4
17 | ```
18 |
19 | To run, execute
20 |
21 | ```bash
22 | bash run.sh
23 | ```
24 |
25 | e.g.,
26 |
27 | ```bash
28 | bash run.sh build/qft results
29 | ```
30 |
31 | The results will be written in `results_output_directory/results_$DATE.csv`. If
32 | the directory `results_output_directory` does not exist, it will be created.
33 |
34 | ## Python stress tests
35 |
36 | We wrote some [Qiskit](https://qiskit.org/) and [QuTiP](https://qutip.org/)
37 | stress tests scripts, all located in the `python` directory. The output format
38 | they produce is exactly the same as the one produced by the C++ version, and
39 | the `run.sh` script works with them with no modification, e.g.,
40 |
41 | ```bash
42 | bash run.sh python/qft_qutip.py results
43 | ```
44 |
45 | The command above assumes that [Qiskit](https://qiskit.org/) and
46 | [QuTiP](https://qutip.org/) were successfully installed on your system. For
47 | installation details, please refer to their corresponding documentation.
48 |
--------------------------------------------------------------------------------
/stress_tests/python/ptrace_qutip.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # QuTiP partial trace stress tests
4 |
5 | import os
6 | import qutip
7 | import sys
8 | import timeit
9 |
10 | if len(sys.argv) != 3:
11 | sys.exit("Please specify the maximum number of cores and qubits!")
12 |
13 | num_cores = int(sys.argv[1]) # max number of cores
14 | n = int(sys.argv[2]) # number of qubits
15 | D = 2 ** n # total dimension
16 |
17 | os.environ['OPENBLAS_NUM_THREADS'] = str(num_cores)
18 | os.environ['MKL_NUM_THREADS'] = str(num_cores)
19 | qutip.settings.num_cpus = num_cores
20 |
21 |
22 | result = qutip.rand_herm(D, dims=[[2] * n, [2] * n])
23 |
24 | # start timing
25 | start_time = timeit.default_timer()
26 |
27 | # partial trace over the first qubit
28 | result = result.ptrace(range(1, n))
29 |
30 | elapsed = timeit.default_timer() - start_time
31 | # end timing
32 |
33 | print("{0}, {1}, {2}".format(num_cores, n, elapsed))
34 |
--------------------------------------------------------------------------------
/stress_tests/python/qft_qiskit.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Qiskit QFT stress tests
4 |
5 | from qiskit import *
6 |
7 | import math
8 | import os
9 | import sys
10 | import timeit
11 |
12 | if len(sys.argv) != 3:
13 | sys.exit("Please specify the maximum number of cores and qubits!")
14 |
15 | num_cores = int(sys.argv[1]) # max number of cores
16 | n = int(sys.argv[2]) # number of qubits
17 |
18 | os.environ['OPENBLAS_NUM_THREADS'] = str(num_cores)
19 | os.environ['MKL_NUM_THREADS'] = str(num_cores)
20 |
21 | q = QuantumRegister(n)
22 | qc = QuantumCircuit(q)
23 |
24 | # start timing
25 | start_time = timeit.default_timer()
26 |
27 | for i in range(n):
28 | qc.h(q[i])
29 | for j in range(2, n - i + 1):
30 | qc.crz(2 * math.pi / 2 ** j, q[i + j - 1], q[i])
31 |
32 | for i in range(n // 2):
33 | qc.swap(q[i], q[n - 1 - i])
34 |
35 | # Compile and run the Quantum circuit on a simulator backend
36 |
37 |
38 | all_local_backends = Aer.backends(
39 | local=True) # returns a list of local backends
40 | qasm_simulator = all_local_backends[0]
41 | statevector_simulator = all_local_backends[1]
42 | job_sim = execute(qc, backend=statevector_simulator, shots=1)
43 | result = job_sim.result()
44 |
45 | elapsed = timeit.default_timer() - start_time
46 | # end timing
47 |
48 | print("{0}, {1}, {2}".format(num_cores, n, elapsed))
49 |
--------------------------------------------------------------------------------
/stress_tests/python/qft_qutip.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # QuTiP QFT stress tests
4 |
5 | import numpy
6 | import os
7 | import qutip
8 | import sys
9 | import timeit
10 |
11 | from qutip.qip.circuit import QubitCircuit
12 |
13 | if len(sys.argv) != 3:
14 | sys.exit("Please specify the maximum number of cores and qubits!")
15 |
16 | num_cores = int(sys.argv[1]) # max number of cores
17 | n = int(sys.argv[2]) # number of qubits
18 |
19 | os.environ['OPENBLAS_NUM_THREADS'] = str(num_cores)
20 | os.environ['MKL_NUM_THREADS'] = str(num_cores)
21 | qutip.settings.num_cpus = num_cores
22 |
23 |
24 | def qft_gate_sequence(n=1, swapping=True):
25 | """
26 | Quantum Fourier Transform operator on n qubits returning the gate sequence.
27 |
28 | Parameters
29 | ----------
30 | n: int
31 | Number of qubits.
32 | swapping: boolean
33 | Flag indicating sequence of swap gates to be applied at the end or not.
34 |
35 | Returns
36 | -------
37 | qc: instance of QubitCircuit
38 | Gate sequence of Hadamard and controlled rotation gates implementing
39 | QFT.
40 | """
41 |
42 | if n < 1:
43 | raise ValueError("Minimum value of n can be 1")
44 |
45 | qc = QubitCircuit(n)
46 | if n == 1:
47 | qc.add_gate("SNOT", targets=[0])
48 | else:
49 | for i in range(n):
50 | qc.add_gate("SNOT", targets=[i])
51 | for j in range(2, n - i + 1):
52 | qc.add_gate(r"CPHASE", targets=[i], controls=[i + j - 1],
53 | arg_label=r"{\pi/2^{%d}}" % (j - 1),
54 | arg_value=numpy.pi / (2 ** (j - 1)))
55 | if swapping is True:
56 | for i in range(n // 2):
57 | qc.add_gate(r"SWAP", targets=[i, n - 1 - i])
58 |
59 | return qc
60 |
61 |
62 | psi = qutip.ket('0' * n)
63 |
64 | # start timing
65 | start_time = timeit.default_timer()
66 |
67 | qc0 = qft_gate_sequence(n, True)
68 | for gate in qc0.propagators():
69 | psi = gate * psi
70 |
71 | elapsed = timeit.default_timer() - start_time
72 | # end timing
73 |
74 | print("{0}, {1}, {2}".format(num_cores, n, elapsed))
75 |
--------------------------------------------------------------------------------
/stress_tests/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # $1 - path to stress test executable
4 | # $2 - directory where results will be collected
5 |
6 | if [ $# -lt 2 ]; then
7 | echo "Usage: $0 " >&2
8 | exit 1
9 | fi
10 |
11 | stress_test="$1"
12 | results_dir="$2"
13 |
14 | max_cores=8 # number of cores
15 | nq_start=2 # number of qubits to start with
16 | nq_end=24 # number of qubits to end with
17 |
18 | current_date=$(date '+%Y-%m-%d_%a_%H-%M-%S') # current date
19 |
20 | if [ ! -d "$results_dir" ]; then
21 | mkdir "$2"
22 | fi
23 | out_file="$results_dir"/results_$current_date.csv # result output file
24 |
25 | filename=$(basename -- "$stress_test")
26 | extension="${filename##*.}"
27 | if [ "$extension" == "py" ]; then
28 | interpreter="python3 $stress_test"
29 | else
30 | interpreter=$stress_test
31 | fi
32 |
33 | echo "Stress test, see $results_dir/results_$current_date.csv"
34 | echo "$stress_test" >"$out_file"
35 | echo "num_cores, num_qubits, time_seconds" | tee -a "$out_file"
36 | for ((num_cores = 1; num_cores <= max_cores; num_cores++)); do
37 | for ((n = nq_start; n <= nq_end; n++)); do
38 | $interpreter "$num_cores" "$n" | tee -a "$out_file"
39 | done
40 | done
41 |
--------------------------------------------------------------------------------
/stress_tests/src/ptrace.cpp:
--------------------------------------------------------------------------------
1 | // Partial trace stress test on a density matrix of n qubits
2 | // Reduce the number of NQ_END in run.sh to accommodate for density matrices
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 |
12 | #include "qpp/qpp.hpp"
13 |
14 | int main(int argc, char** argv) {
15 | using namespace qpp;
16 | if (argc != 3) {
17 | std::cerr << "Usage: " << argv[0] << " \n";
18 | exit(EXIT_FAILURE);
19 | }
20 |
21 | int num_cores = std::stoi(argv[1]); // number of cores
22 | idx n = std::stoi(argv[2]); // number of qubits
23 | idx D = static_cast(std::llround(std::pow(2, n))); // dimension 2^n
24 | omp_set_num_threads(num_cores); // number of cores
25 |
26 | cmat randcmat = cmat::Random(D, D); // random matrix
27 | std::vector subsys_ptrace = {0}; // partial trace over first qubit
28 |
29 | Timer<> t; // start timing
30 | ptrace(randcmat, subsys_ptrace);
31 | std::cout << num_cores << ", " << n << ", " << t.toc() << '\n';
32 | }
33 |
--------------------------------------------------------------------------------
/stress_tests/src/qft.cpp:
--------------------------------------------------------------------------------
1 | // Quantum Fourier transform stress test on a pure state of n qubits
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include "qpp/qpp.hpp"
12 |
13 | int main(int argc, char** argv) {
14 | using namespace qpp;
15 | if (argc != 3) {
16 | std::cerr << "Usage: " << argv[0] << " \n";
17 | exit(EXIT_FAILURE);
18 | }
19 |
20 | int num_cores = std::stoi(argv[1]); // number of cores
21 | idx n = std::stoi(argv[2]); // number of qubits
22 | omp_set_num_threads(num_cores); // number of cores
23 |
24 | std::vector qubits(n); // initial state
25 | ket psi = mket(qubits);
26 | ket result = psi;
27 |
28 | Timer<> t; // start timing
29 | for (idx i = 0; i < n; ++i) {
30 | result = apply(result, gt.H, {i}); // apply Hadamard on qubit i
31 | // apply controlled rotations
32 | for (idx j = 2; j <= n - i; ++j) {
33 | cmat Rj(2, 2);
34 | Rj << 1, 0, 0, omega(static_cast(std::pow(2, j)));
35 | result = applyCTRL(result, Rj, {i + j - 1}, {i});
36 | }
37 | }
38 | // we have the qubits in reversed order, we must swap them
39 | for (idx i = 0; i < n / 2; ++i) {
40 | result = apply(result, gt.SWAP, {i, n - i - 1});
41 | }
42 | std::cout << num_cores << ", " << n << ", " << t.toc() << '\n';
43 | }
44 |
--------------------------------------------------------------------------------
/stress_tests/src/syspermute.cpp:
--------------------------------------------------------------------------------
1 | // System permutation stress test on a pure state of n qubits
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | #include "qpp/qpp.hpp"
12 |
13 | int main(int argc, char** argv) {
14 | using namespace qpp;
15 | if (argc != 3) {
16 | std::cerr << "Usage: " << argv[0] << " \n";
17 | exit(EXIT_FAILURE);
18 | }
19 |
20 | int num_cores = std::stoi(argv[1]); // number of cores
21 | idx n = std::stoi(argv[2]); // number of qubits
22 | idx D = static_cast(std::llround(std::pow(2, n))); // dimension 2^n
23 | omp_set_num_threads(num_cores); // number of cores
24 |
25 | ket randket = ket::Random(D); // random ket
26 | std::vector subsys_syspermute; // partially syspermute reversed order
27 | for (idx i = 0; i < n; ++i) {
28 | subsys_syspermute.push_back(i);
29 | }
30 |
31 | Timer<> t; // start timing
32 | syspermute(randket, subsys_syspermute);
33 | std::cout << num_cores << ", " << n << ", " << t.toc() << '\n';
34 | }
35 |
--------------------------------------------------------------------------------
/unit_tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | include(GoogleTest)
2 | set(TARGET_NAME "unit_tests")
3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
4 |
5 | # GoogleTest
6 | include(FetchContent)
7 | message(STATUS "Fetching GoogleTest...")
8 | FetchContent_Declare(
9 | googletest
10 | GIT_REPOSITORY https://github.com/google/googletest.git
11 | GIT_TAG main
12 | GIT_SHALLOW TRUE
13 | GIT_PROGRESS TRUE)
14 | # For Windows: Prevent overriding the parent project's compiler/linker settings,
15 | # and add /bigobj option
16 | if(MSVC)
17 | add_compile_options(/bigobj)
18 | set(gtest_force_shared_crt
19 | ON
20 | CACHE BOOL "" FORCE)
21 | endif()
22 | FetchContent_MakeAvailable(googletest)
23 |
24 | aux_source_directory(tests TEST_FILES)
25 | aux_source_directory(tests/MATLAB TEST_FILES)
26 | aux_source_directory(tests/classes TEST_FILES)
27 | aux_source_directory(tests/qasm TEST_FILES)
28 |
29 | add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL tests/main.cpp)
30 | add_dependencies(unit_tests ${TARGET_NAME})
31 |
32 | cmake_policy(SET CMP0076 NEW)
33 |
34 | # Build all tests in ${TEST_FILES}
35 | foreach(file ${TEST_FILES})
36 | # Do not build "tests/MATLAB/matlab.cpp" if there's no MATLAB support
37 | if(${file} STREQUAL "tests/MATLAB/matlab.cpp" AND NOT MATLAB_FOUND)
38 | continue()
39 | endif()
40 | target_sources(${TARGET_NAME} PUBLIC ${file})
41 | endforeach()
42 |
43 | target_link_libraries(${TARGET_NAME} PUBLIC ${QPP_LINK_DEPS} gmock libqpp)
44 | gtest_discover_tests(${TARGET_NAME})
45 |
--------------------------------------------------------------------------------
/unit_tests/tests/classes/layouts.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "gtest/gtest.h"
4 |
5 | #include "qpp/qpp.hpp"
6 |
7 | using namespace qpp;
8 |
9 | // Unit testing "qpp/classes/layouts.hpp"
10 |
11 | /// BEGIN std::vector Lattice::get_dims() const override
12 | TEST(qpp_Lattice_get_dims, AllTests) {}
13 |
14 | /// BEGIN idx Lattice::operator()(const std::vector& xs) const override
15 | TEST(qpp_Lattice_functor, Vector) {}
16 |
17 | /// BEGIN template idx Lattice::operator()(Ts... xs) const
18 | TEST(qpp_Lattice_functor, Variadic) {}
19 |
20 | /// BEGIN std::vector Lattice::to_coordinates(idx i) const override
21 | TEST(qpp_Lattice_to_coordinates, AllTests) {}
22 |
23 | /// BEGIN idx PeriodicBoundaryLattice::operator()(
24 | /// const std::vector& xs) const override
25 | TEST(qpp_PeriodicBoundaryLattice_functor, AllTests) {}
26 |
--------------------------------------------------------------------------------
/unit_tests/tests/classes/noise.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "gtest/gtest.h"
4 |
5 | #include "qpp/qpp.hpp"
6 |
7 | using namespace qpp;
8 |
9 | // Unit testing "qpp/classes/noise.hpp"
10 |
11 | /// BEGIN idx NoiseBase::get_d() const noexcept
12 | TEST(qpp_NoiseBase_get_d, AllTests) {}
13 |
14 | /// BEGIN std::vector NoiseBase::get_Ks() const
15 | TEST(qpp_NoiseBase_get_Ks, AllTests) {}
16 |
17 | /// BEGIN idx NoiseBase::get_last_idx() const
18 | TEST(qpp_NoiseBase_get_last_idx, AllTests) {}
19 |
20 | /// BEGIN cmat NoiseBase::get_last_K() const
21 | TEST(qpp_NoiseBase_get_last_K, AllTests) {}
22 |
23 | /// BEGIN realT NoiseBase::get_last_p() const
24 | TEST(qpp_NoiseBase_get_last_p, AllTests) {}
25 |
26 | /// BEGIN std::vector NoiseBase::get_probs() const
27 | TEST(qpp_NoiseBase_get_probs, AllTests) {}
28 |
29 | /// BEGIN virtual cmat NoiseBase::operator()(const cmat& state) const
30 | TEST(qpp_NoiseBase_functor, AllQudits) {}
31 |
32 | /// BEGIN virtual cmat NoiseBase::operator()(const cmat& state, idx target)
33 | /// const
34 | TEST(qpp_NoiseBase_functor, SpecificQudit) {}
35 |
36 | /// BEGIN virtual cmat NoiseBase::operator()(const cmat& state,
37 | /// const std::vector& target) const
38 | TEST(qpp_NoiseBase_functor, CorrelatedNoise) {}
39 |
40 | /// BEGIN explicit QubitAmplitudeDampingNoise::QubitAmplitudeDampingNoise(
41 | /// realT gamma)
42 | TEST(qpp_QubitAmplitudeDampingNoise_QubitAmplitudeDampingNoise, AllTests) {}
43 |
44 | /// BEGIN explicit QubitBitFlipNoise::QubitBitFlipNoise(realT p)
45 | TEST(qpp_QubitBitFlipNoise_QubitBitFlipNoise, AllTests) {}
46 |
47 | /// BEGIN explicit QubitBitPhaseFlipNoise::QubitBitPhaseFlipNoise(realT p)
48 | TEST(qpp_QubitBitPhaseFlipNoise_QubitBitPhaseFlipNoise, AllTests) {}
49 |
50 | /// BEGIN explicit QubitDepolarizingNoise::QubitDepolarizingNoise(realT p)
51 | TEST(qpp_QubitDepolarizingNoise_QubitDepolarizingNoise, AllTests) {}
52 |
53 | /// BEGIN explicit QubitPhaseFlipNoise::QubitPhaseFlipNoise(realT p)
54 | TEST(qpp_QubitPhaseFlipNoise_QubitPhaseFlipNoise, AllTests) {}
55 |
56 | /// BEGIN explicit QuditDepolarizingNoise::QuditDepolarizingNoise(realT p,
57 | /// idx d)
58 | TEST(qpp_QuditDepolarizingNoise_QuditDepolarizingNoise, AllTests) {}
59 |
--------------------------------------------------------------------------------
/unit_tests/tests/classes/qdummy_engine.cpp:
--------------------------------------------------------------------------------
1 | #include "gtest/gtest.h"
2 |
3 | #include "qpp/qpp.hpp"
4 |
5 | using namespace qpp;
6 |
7 | // Unit testing "qpp/classes/qdummy_engine.hpp"
8 |
9 | /// BEGIN QBaseEngine& QDummyEngineT::execute(
10 | /// typename QCircuitTraits