├── .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::iterator_type& it) 11 | TEST(qpp_QDummyEngine_execute, Iterator) {} 12 | 13 | /// BEGIN QBaseEngine& QDummyEngine::execute( 14 | /// const typename QCircuitTraits::value_type& elem) override 15 | TEST(qpp_QDummyEngine_execute, ValueType) {} 16 | 17 | /// BEGIN QBaseEngine& QDummyEngine::execute(idx reps = 1) override 18 | TEST(qpp_QDummyEngine_execute, AllCircuitWithRepetitions) {} 19 | 20 | /// BEGIN const QCT& QDummyEngine::get_circuit() const& noexcept 21 | TEST(qpp_QDummyEngine_get_circuit, Lvalue) {} 22 | 23 | /// BEGIN QCT QDummyEngine::get_circuit() const&& noexcept 24 | TEST(qpp_QDummyEngine_get_circuit, Rvalue) {} 25 | 26 | /// BEGIN T QDummyEngine::get_state() const override 27 | TEST(qpp_QDummyEngine_get_state, AllTests) {} 28 | 29 | /// BEGIN QBaseEngine& QDummyEngine::set_state(const T& state) override 30 | TEST(qpp_QDummyEngine_set_state, AllTests) {} 31 | 32 | /// BEGIN std::string QDummyEngine::to_JSON( 33 | /// bool enclosed_in_curly_brackets = true) const override 34 | TEST(qpp_QDummyEngine_to_JSON, AllTests) {} 35 | 36 | /// BEGIN std::string QDummyEngine::traits_get_name() const override 37 | TEST(qpp_QDummyEngine_traits_get_name, AllTests) {} 38 | 39 | /// BEGIN bool QDummyEngine::traits_is_noisy() const override 40 | TEST(qpp_QDummyEngine_traits_is_noisy, AllTests) {} 41 | 42 | /// BEGIN bool QDummyEngine::traits_is_pure() const override 43 | TEST(qpp_QDummyEngine_traits_is_pure, AllTests) {} 44 | -------------------------------------------------------------------------------- /unit_tests/tests/classes/qengine.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | #include "qpp/qpp.hpp" 4 | 5 | using namespace qpp; 6 | 7 | // Unit testing "qpp/classes/qengine.hpp" 8 | 9 | /// BEGIN QBaseEngine& QEngineT::execute( 10 | /// typename QCircuitTraits::iterator_type& it) 11 | TEST(qpp_QEngineT_execute, Iterator) {} 12 | 13 | /// BEGIN QEngineT& QEngineT::execute( 14 | /// const typename QCircuitTraits::value_type& elem) override 15 | TEST(qpp_QEngineT_execute, ValueType) {} 16 | 17 | /// BEGIN QEngineT& QEngineT::execute(idx reps = 1) override 18 | TEST(qpp_QEngineT_execute, AllCircuitWithRepetitions) {} 19 | 20 | /// BEGIN const QCT& QBaseEngine::get_circuit() const& noexcept 21 | TEST(qpp_QEngineT_get_circuit, Lvalue) {} 22 | 23 | /// BEGIN QCT QBaseEngine::get_circuit() const&& noexcept 24 | TEST(qpp_QEngineT_get_circuit, Rvalue) {} 25 | 26 | /// BEGIN idx QEngineT::get_dit(idx i) const 27 | TEST(qpp_QEngineT_get_dit, AllTests) {} 28 | 29 | /// BEGIN std::vector QEngineT::get_dits() const 30 | TEST(qpp_QEngineT_get_dits, AllTests) {} 31 | 32 | /// BEGIN bool QEngineT::get_ensure_post_selection() const 33 | TEST(qpp_QEngineT_get_ensure_post_selection, AllTests) {} 34 | 35 | /// BEGIN idx QEngineT::get_max_post_selection_reps() const 36 | TEST(qpp_QEngineT_get_max_post_selection_reps, AllTests) {} 37 | 38 | /// BEGIN std::vector QEngineT::get_measured_d() const 39 | TEST(qpp_QEngineT_get_measured_d, AllTests) {} 40 | 41 | /// BEGIN std::vector QEngineT::get_non_measured_d() const 42 | TEST(qpp_QEngineT_get_non_measured_d, AllTests) {} 43 | 44 | /// BEGIN std::vector QEngineT::get_probs() const 45 | TEST(qpp_QEngineT_get_probs, AllTests) {} 46 | 47 | /// BEGIN T QEngineT::get_state() const override 48 | TEST(qpp_QEngineT_get_state, AllTests) {} 49 | 50 | /// BEGIN internal::QEngineStatistics QEngineT::get_stats() const 51 | TEST(qpp_QEngineT_get_stats, AllTests) {} 52 | 53 | /// BEGIN bool QEngineT::post_select_ok() const 54 | TEST(qpp_QEngineT_post_select_ok, AllTests) {} 55 | 56 | /// BEGIN QEngineT& QEngineT::reset(bool reset_stats = true) 57 | TEST(qpp_QEngineT_reset, AllTests) {} 58 | 59 | /// BEGIN QEngineT& QEngineT::reset_stats() 60 | TEST(qpp_QEngineT_reset_stats, AllTests) {} 61 | 62 | /// BEGIN QEngineT& QEngineT::set_dit(idx i, idx value) 63 | TEST(qpp_QEngineT_set_dit, AllTests) {} 64 | 65 | /// BEGIN QEngineT& QEngineT::set_dits(std::vector dits) 66 | TEST(qpp_QEngineT_set_dits, AllTests) {} 67 | 68 | /// BEGIN QEngineT& QEngineT::set_ensure_post_selection(bool val) 69 | TEST(qpp_QEngineT_set_ensure_post_selection, AllTests) {} 70 | 71 | /// BEGIN QEngineT& QEngineT::set_max_post_selection_reps( 72 | /// idx max_post_selection_reps) 73 | TEST(qpp_QEngineT_set_max_post_selection_reps, AllTests) {} 74 | 75 | /// BEGIN QEngineT& QEngineT::set_state(const T& state) override 76 | TEST(qpp_QEngineT_set_state, AllTests) {} 77 | 78 | /// BEGIN std::string QEngineT::to_JSON( 79 | /// bool enclosed_in_curly_brackets = true) const override 80 | TEST(qpp_QEngineT_to_JSON, AllTests) {} 81 | 82 | /// BEGIN std::string QEngineT::traits_get_name() const override 83 | TEST(qpp_QEngineT_traits_get_name, AllTests) {} 84 | 85 | /// BEGIN bool QEngineT::traits_is_noisy() const override 86 | TEST(qpp_QEngineT_traits_is_noisy, AllTests) {} 87 | 88 | /// BEGIN bool QEngineT::traits_is_pure() const override 89 | TEST(qpp_QEngineT_traits_is_pure, AllTests) {} 90 | 91 | /// BEGIN bool QEngineT::was_measured_d(idx i) const 92 | TEST(qpp_QEngineT_was_measured_d, AllTests) {} 93 | -------------------------------------------------------------------------------- /unit_tests/tests/classes/qnoisy_engine.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | #include "qpp/qpp.hpp" 4 | 5 | using namespace qpp; 6 | 7 | // Unit testing "qpp/classes/qnoisy_engine.hpp" 8 | 9 | /// BEGIN QBaseEngine& QNoisyEngineT::execute( 10 | /// typename QCircuitTraits::iterator_type& it) 11 | TEST(qpp_QNoisyEngineT_execute, Iterator) {} 12 | 13 | /// BEGIN QNoisyEngineT& QNoisyEngineT::execute( 14 | /// const typename QCircuitTraits::value_type& elem) override 15 | TEST(qpp_QNoisyEngineT_execute, ValueType) {} 16 | 17 | /// BEGIN QNoisyEngineT& QNoisyEngineT::execute(idx reps = 1) override 18 | TEST(qpp_QNoisyEngineT_execute, AllCircuitWithRepetitions) {} 19 | 20 | /// BEGIN std::vector> 21 | /// QNoisyEngineT::get_noise_results() const 22 | TEST(qpp_QNoisyEngineT_get_noise_results, AllTests) {} 23 | 24 | /// BEGIN QEngineT& QNoisyEngineT::reset(bool reset_stats = true) 25 | TEST(qpp_QNoisyEngineT_reset, AllTests) {} 26 | 27 | /// BEGIN std::string QNoisyEngineT::traits_get_name() const override 28 | TEST(qpp_QNoisyEngineT_traits_get_name, AllTests) {} 29 | 30 | /// BEGIN bool QNoisyEngineT::traits_is_noisy() const override 31 | TEST(qpp_QNoisyEngineT_traits_is_noisy, AllTests) {} 32 | 33 | /// BEGIN bool QNoisyEngineT::traits_is_pure() const override 34 | TEST(qpp_QNoisyEngineT_traits_is_pure, AllTests) {} 35 | -------------------------------------------------------------------------------- /unit_tests/tests/classes/random_devices.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/random_devices.hpp" 10 | 11 | /// BEGIN std::mt19937& RandomDevices::get_prng() 12 | TEST(qpp_RandomDevices_get_prng, AllTests) {} 13 | 14 | /// BEGIN RandomDevices::load(std::istream& is) 15 | /// 16 | /// RandomDevices::save(std::ostream& os) const 17 | TEST(qpp_RandomDevices_load_save, AllTests) { 18 | // save the state of the PRNG 19 | std::stringstream ss; 20 | rdevs.save(ss); 21 | 22 | // generate some random matrix 23 | cmat A1 = rand(4, 4); 24 | // generate some random index 25 | idx i1 = randidx(0, 100); 26 | // generate some random biging 27 | bigint b1 = rand(static_cast(-100), static_cast(100)); 28 | // finally generate some random realT 29 | realT d1 = rand(static_cast(-100.0), static_cast(100.0)); 30 | 31 | // load the state of the PRNG 32 | ss.seekg(0); 33 | rdevs.load(ss); 34 | 35 | // generate again some random matrix 36 | cmat A2 = rand(4, 4); 37 | // generate again some random index 38 | idx i2 = randidx(0, 100); 39 | // generate again some random biging 40 | bigint b2 = rand(static_cast(-100), static_cast(100)); 41 | // finally generate again some random realT 42 | realT d2 = rand(static_cast(-100.0), static_cast(100.0)); 43 | 44 | // make sure we reproduce the randomness 45 | EXPECT_EQ(0, norm(A1 - A2)); 46 | EXPECT_EQ(i1, i2); 47 | EXPECT_EQ(b1, b2); 48 | EXPECT_EQ(d1, d2); 49 | } 50 | -------------------------------------------------------------------------------- /unit_tests/tests/classes/timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // for std::this_thread::sleep_for() 3 | 4 | #include "gtest/gtest.h" 5 | 6 | #include "qpp/qpp.hpp" 7 | 8 | using namespace qpp; 9 | 10 | // Unit testing "qpp/classes/timer.hpp" 11 | 12 | // All test below test std::chrono::steady_clock timers, 13 | // i.e Timer 14 | 15 | // the precision should be at least within 0.05s <=> 50 ms <=> 50000 micros 16 | 17 | /// BEGIN template U Timer::get_duration() const noexcept 18 | TEST(qpp_Timer_get_duration, AllTests) { 19 | using namespace std::chrono; 20 | 21 | Timer<> t1; // default duration is double 22 | std::this_thread::sleep_for(seconds(1)); // sleep 1 second 23 | t1.toc(); // get current time snap 24 | 25 | auto duration_t1_s = t1.get_duration(); // in seconds 26 | EXPECT_NEAR(duration_t1_s.count(), 1, 0.05); // within 0.05s 27 | 28 | auto duration_t1_ms = t1.get_duration(); // in milli seconds 29 | EXPECT_NEAR(static_cast(duration_t1_ms.count()), 1000, 30 | 50); // within 0.05s 31 | 32 | Timer t2; // in micro seconds 33 | std::this_thread::sleep_for(microseconds(100000)); // sleep 0.1 seconds 34 | t2.toc(); // get current time snap 35 | 36 | auto duration_t2_micros = t2.get_duration(); 37 | EXPECT_NEAR(static_cast(duration_t2_micros.count()), 100000, 38 | 50000); // within 0.05s 39 | } 40 | 41 | /// BEGIN Timer& Timer::tic() noexcept 42 | /// 43 | /// double Timer::tics() const noexcept 44 | /// 45 | /// Timer& Timer::toc() noexcept 46 | TEST(qpp_Timer_tic_tics_toc, AllTests) { 47 | using namespace std::chrono; 48 | 49 | Timer<> t; 50 | std::this_thread::sleep_for(milliseconds(100)); // sleep 0.1 seconds 51 | t.tic(); // reset the timer 52 | t.toc(); // get current time snap 53 | EXPECT_NEAR(t.tics(), 0, 0.05); // within 0.05s 54 | 55 | t.tic(); // reset 56 | // sleep an additional 0.1s (without reseting the timer) 57 | std::this_thread::sleep_for(milliseconds(100)); 58 | t.toc(); // get current time snap 59 | EXPECT_NEAR(t.tics(), 0.1, 0.05); // within 0.05s 60 | 61 | std::this_thread::sleep_for(milliseconds(100)); 62 | t.toc(); // get current time snap 63 | EXPECT_NEAR(t.tics(), 0.2, 0.05); // within 0.05s 64 | 65 | t.tic(); // reset 66 | std::this_thread::sleep_for(milliseconds(100)); 67 | t.toc(); // get current time snap 68 | EXPECT_NEAR(t.tics(), 0.1, 0.05); // within 0.05s 69 | } 70 | -------------------------------------------------------------------------------- /unit_tests/tests/issues.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | #include "qpp/qpp.hpp" 4 | 5 | using namespace qpp; 6 | 7 | // Unit testing reported issues and pull requests 8 | 9 | TEST(qpp_PR, 110) { 10 | auto const state = (0_ket + 1_ket).normalized().eval(); 11 | auto const res = measure(state, gt.Id2); 12 | auto const& resulting_states = std::get(res); 13 | 14 | EXPECT_EQ(resulting_states[0][0], static_cast(1.)); 15 | EXPECT_EQ(resulting_states[1][1], static_cast(1.)); 16 | } 17 | 18 | TEST(qpp_PR, 113) { 19 | auto circuit = QCircuit{1, 1}; 20 | circuit.measureV(gt.Id2, 0, 0); 21 | 22 | auto engine = QEngine{circuit}; 23 | EXPECT_NO_THROW(engine.execute()); 24 | } 25 | -------------------------------------------------------------------------------- /unit_tests/tests/main.cpp: -------------------------------------------------------------------------------- 1 | // Unit testing entry point 2 | 3 | #include "gtest/gtest.h" 4 | 5 | int main(int argc, char** argv) { 6 | ::testing::InitGoogleTest(&argc, argv); 7 | return RUN_ALL_TESTS(); 8 | } 9 | -------------------------------------------------------------------------------- /unit_tests/tests/qasm/circuits/units/builtingates.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | 4 | qreg a[1]; 5 | qreg b[2]; 6 | creg c[2]; 7 | 8 | U(0.1, 0.2, 0.3) a[0]; 9 | 10 | // proportional to X 11 | U(pi, 0, pi) b[0]; 12 | CX b[0],b[1]; 13 | 14 | measure b[0] -> c[0]; 15 | measure b[1] -> c[1]; 16 | -------------------------------------------------------------------------------- /unit_tests/tests/qasm/circuits/units/mappedgates.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | 4 | qreg q[2]; 5 | 6 | h q; 7 | -------------------------------------------------------------------------------- /unit_tests/tests/qasm/circuits/units/nondestrmeas.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | 4 | qreg q[1]; 5 | creg c[1]; 6 | 7 | x q[0]; 8 | measure q[0] -> c[0]; 9 | -------------------------------------------------------------------------------- /unit_tests/tests/qasm/circuits/units/reset.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | 4 | qreg q[1]; 5 | 6 | h q[0]; 7 | reset q[0]; 8 | -------------------------------------------------------------------------------- /unit_tests/tests/qasm/circuits/units/scinot.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | 4 | qreg q[1]; 5 | 6 | h q[0]; 7 | rz(1.0E-3) q[0]; 8 | h q[0]; 9 | -------------------------------------------------------------------------------- /unit_tests/tests/qasm/circuits/units/teleportation.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | 4 | qreg a[1]; 5 | qreg b[2]; 6 | creg c[1]; 7 | creg d[1]; 8 | 9 | // prepare Bell state 10 | h b[0]; 11 | cx b[0],b[1]; 12 | 13 | // prepare teleported state 14 | u3(0.3,0.2,0.1) a[0]; 15 | 16 | // perform measurement 17 | cx a[0],b[0]; 18 | h a[0]; 19 | measure a[0] -> c[0]; 20 | measure b[0] -> d[0]; 21 | 22 | // classically controlled corrections 23 | if (d==1) x b[1]; 24 | if (c==1) z b[1]; 25 | 26 | // u3 adjoint, final expected state should be |0> 27 | // u3^\dagger(a,b,c) = u3(-a,-c,-b) 28 | u3(-0.3,-0.1,-0.2) b[1] 29 | -------------------------------------------------------------------------------- /unit_tests/tests/traits.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "gtest/gtest.h" 6 | 7 | #include "qpp/qpp.hpp" 8 | 9 | using namespace qpp; 10 | 11 | // Unit testing "qpp/traits.hpp" 12 | 13 | /// BEGIN template struct is_complex 14 | TEST(qpp_is_complex, AllTests) { 15 | EXPECT_TRUE(is_complex>::value); 16 | EXPECT_TRUE(is_complex>::value); 17 | 18 | EXPECT_FALSE(is_complex::value); 19 | EXPECT_FALSE(is_complex::value); 20 | } 21 | 22 | /// BEGIN template struct is_iterable 23 | TEST(qpp_is_iterable, AllTests) { 24 | EXPECT_TRUE(is_iterable>::value); 25 | EXPECT_TRUE(is_iterable>::value); 26 | 27 | class X {}; 28 | EXPECT_FALSE(is_iterable::value); 29 | EXPECT_FALSE(is_iterable::value); 30 | } 31 | 32 | /// BEGIN template struct is_matrix_expression 33 | TEST(qpp_is_matrix_expression, AllTests) { 34 | rmat A, B, C, D; 35 | int x{}, y{}, z{}; 36 | 37 | EXPECT_TRUE(is_matrix_expression::value); 38 | EXPECT_TRUE(is_matrix_expression::value); 39 | EXPECT_TRUE(is_matrix_expression::value); 40 | EXPECT_TRUE(is_matrix_expression::value); 41 | 42 | EXPECT_FALSE(is_matrix_expression::value); 43 | } 44 | --------------------------------------------------------------------------------