├── examples ├── automated │ ├── CMakeLists.txt │ ├── report_quest_env.c │ ├── apply_no_unitary_pauli_gadget.c │ └── README.md ├── extended │ ├── CMakeLists.txt │ └── README.md ├── isolated │ ├── CMakeLists.txt │ ├── setting_errorhandler.c │ ├── README.md │ ├── setting_errorhandler.cpp │ ├── reporting_matrices.cpp │ ├── reporting_paulis.c │ ├── complex_arithmetic.c │ ├── reporting_paulis.cpp │ ├── complex_arithmetic.cpp │ ├── reporting_matrices.c │ ├── reporting_environments.c │ ├── reporting_environments.cpp │ ├── initialising_superoperators.cpp │ ├── reporting_quregs.c │ ├── reporting_quregs.cpp │ ├── initialising_superoperators.c │ ├── initialising_krausmaps.cpp │ └── initialising_krausmaps.c ├── tutorials │ ├── README.md │ └── min_example.c ├── README.md └── CMakeLists.txt ├── utils ├── docs │ ├── logos │ │ ├── amd.png │ │ ├── logo.png │ │ ├── nqcc.png │ │ ├── qmt.png │ │ ├── banner.png │ │ ├── favicon.ico │ │ ├── navbar.png │ │ ├── nvidia.png │ │ ├── oxford.png │ │ ├── edinburgh.png │ │ └── logo_large.png │ ├── latex │ │ └── commands.tex │ └── layout │ │ ├── doxygen-awesome-quest.js │ │ ├── doxygen-awesome-sidebar-only-darkmode-toggle.css │ │ ├── doxygen-awesome-quest.css │ │ ├── header.html │ │ └── doxygen-awesome-sidebar-only.css └── README.md ├── quest ├── CMakeLists.txt ├── src │ ├── comm │ │ ├── CMakeLists.txt │ │ ├── comm_config.hpp │ │ ├── comm_indices.hpp │ │ ├── comm_routines.hpp │ │ └── comm_config.cpp │ ├── cpu │ │ ├── CMakeLists.txt │ │ └── cpu_config.hpp │ ├── CMakeLists.txt │ ├── api │ │ ├── modes.cpp │ │ ├── CMakeLists.txt │ │ └── types.cpp │ ├── core │ │ ├── CMakeLists.txt │ │ ├── constants.hpp │ │ ├── envvars.hpp │ │ ├── autodeployer.hpp │ │ ├── parser.hpp │ │ ├── randomiser.hpp │ │ ├── inliner.hpp │ │ ├── paulilogic.hpp │ │ ├── memory.hpp │ │ └── envvars.cpp │ └── gpu │ │ ├── CMakeLists.txt │ │ ├── gpu_config.hpp │ │ └── cuda_to_hip.hpp └── include │ ├── CMakeLists.txt │ ├── quest.h │ ├── environment.h │ ├── wrappers.h │ ├── modes.h │ └── precision.h ├── tests ├── integration │ └── CMakeLists.txt ├── utils │ ├── CMakeLists.txt │ ├── convert.hpp │ ├── cache.hpp │ ├── lists.hpp │ ├── macros.hpp │ ├── qvector.hpp │ ├── measure.hpp │ ├── compare.hpp │ ├── qmatrix.hpp │ ├── config.cpp │ ├── random.hpp │ ├── linalg.hpp │ ├── evolve.hpp │ ├── qvector.cpp │ ├── config.hpp │ ├── measure.cpp │ └── convert.cpp ├── unit │ ├── multiplication.cpp │ ├── CMakeLists.txt │ ├── trotterisation.cpp │ ├── types.cpp │ └── environment.cpp ├── CMakeLists.txt ├── deprecated │ ├── CMakeLists.txt │ └── test_main.cpp └── README.md ├── cmake ├── QuESTConfig.cmake.in └── FindCUQUANTUM.cmake ├── docs ├── contributing.md ├── README.md ├── styleguide.md ├── architecture.md └── news.md ├── LICENCE.txt ├── .github ├── workflows │ ├── doc.yml │ └── test_free.yml └── scripts │ └── setup_cuda.ps1 └── AUTHORS.txt /examples/automated/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Tyson Jones 2 | 3 | add_all_local_examples() 4 | -------------------------------------------------------------------------------- /examples/extended/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Tyson Jones 2 | 3 | add_all_local_examples() 4 | -------------------------------------------------------------------------------- /examples/isolated/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Tyson Jones 2 | 3 | add_all_local_examples() 4 | -------------------------------------------------------------------------------- /utils/docs/logos/amd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/amd.png -------------------------------------------------------------------------------- /utils/docs/logos/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/logo.png -------------------------------------------------------------------------------- /utils/docs/logos/nqcc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/nqcc.png -------------------------------------------------------------------------------- /utils/docs/logos/qmt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/qmt.png -------------------------------------------------------------------------------- /utils/docs/logos/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/banner.png -------------------------------------------------------------------------------- /utils/docs/logos/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/favicon.ico -------------------------------------------------------------------------------- /utils/docs/logos/navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/navbar.png -------------------------------------------------------------------------------- /utils/docs/logos/nvidia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/nvidia.png -------------------------------------------------------------------------------- /utils/docs/logos/oxford.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/oxford.png -------------------------------------------------------------------------------- /quest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | add_subdirectory(src) 4 | add_subdirectory(include) -------------------------------------------------------------------------------- /utils/docs/logos/edinburgh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/edinburgh.png -------------------------------------------------------------------------------- /utils/docs/logos/logo_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuEST-Kit/QuEST/HEAD/utils/docs/logos/logo_large.png -------------------------------------------------------------------------------- /utils/README.md: -------------------------------------------------------------------------------- 1 | 2 | This folder contains auxiliary files used by QuEST, such as documentation configuration files. 3 | -------------------------------------------------------------------------------- /tests/integration/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | target_sources(tests 4 | PUBLIC 5 | densitymatrix.cpp 6 | ) -------------------------------------------------------------------------------- /quest/src/comm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | target_sources(QuEST 4 | PRIVATE 5 | comm_config.cpp 6 | comm_routines.cpp 7 | ) -------------------------------------------------------------------------------- /quest/src/cpu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | target_sources(QuEST 4 | PRIVATE 5 | cpu_config.cpp 6 | cpu_subroutines.cpp 7 | ) -------------------------------------------------------------------------------- /quest/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | add_subdirectory(api) 4 | add_subdirectory(comm) 5 | add_subdirectory(core) 6 | add_subdirectory(cpu) 7 | add_subdirectory(gpu) -------------------------------------------------------------------------------- /cmake/QuESTConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # @author Erich Essmann 2 | # @author Luc Jaulmes (patched use of LIB_NAME) 3 | 4 | @PACKAGE_INIT@ 5 | include("${CMAKE_CURRENT_LIST_DIR}/@LIB_NAME@Targets.cmake") 6 | -------------------------------------------------------------------------------- /quest/src/api/modes.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * API flags and functions for specifying deployment modes. 3 | * 4 | * @author Tyson Jones 5 | */ 6 | 7 | #include "quest/include/modes.h" 8 | 9 | 10 | int modeflag::USE_AUTO = -1; 11 | -------------------------------------------------------------------------------- /examples/tutorials/README.md: -------------------------------------------------------------------------------- 1 | # 🔖  Tutorials 2 | 3 | 9 | 10 | This folder contains _tutorials_ which walk through the use of QuEST. 11 | 12 | -------------------------------------------------------------------------------- /tests/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | target_sources(tests 4 | PUBLIC 5 | cache.cpp 6 | compare.cpp 7 | config.cpp 8 | convert.cpp 9 | evolve.cpp 10 | linalg.cpp 11 | lists.cpp 12 | measure.cpp 13 | qmatrix.cpp 14 | qvector.cpp 15 | random.cpp 16 | ) -------------------------------------------------------------------------------- /examples/automated/report_quest_env.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Shows the output of reportQuESTEnv() on 3 | * Github Action runners 4 | * 5 | * @author Tyson Jones 6 | */ 7 | 8 | #include "quest.h" 9 | 10 | int main() { 11 | initQuESTEnv(); 12 | reportQuESTEnv(); 13 | finalizeQuESTEnv(); 14 | } 15 | -------------------------------------------------------------------------------- /tests/unit/multiplication.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Testing of the multiplication API module is actually 3 | * performed in operations.cpp, in addition to testing 4 | * the operations module, since their testing logics are 5 | * inextricable. This file exists only to redirect the 6 | * confused reader searching for the multiplication tests. 7 | */ 8 | -------------------------------------------------------------------------------- /quest/src/core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | target_sources(QuEST 4 | PRIVATE 5 | accelerator.cpp 6 | autodeployer.cpp 7 | envvars.cpp 8 | errors.cpp 9 | localiser.cpp 10 | memory.cpp 11 | parser.cpp 12 | paulilogic.cpp 13 | printer.cpp 14 | randomiser.cpp 15 | utilities.cpp 16 | validation.cpp 17 | ) -------------------------------------------------------------------------------- /quest/src/api/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(QuEST 2 | PRIVATE 3 | calculations.cpp 4 | channels.cpp 5 | debug.cpp 6 | decoherence.cpp 7 | environment.cpp 8 | initialisations.cpp 9 | matrices.cpp 10 | modes.cpp 11 | multiplication.cpp 12 | operations.cpp 13 | paulis.cpp 14 | qureg.cpp 15 | trotterisation.cpp 16 | types.cpp 17 | ) -------------------------------------------------------------------------------- /tests/unit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | target_sources(tests 4 | PUBLIC 5 | calculations.cpp 6 | channels.cpp 7 | debug.cpp 8 | decoherence.cpp 9 | environment.cpp 10 | initialisations.cpp 11 | matrices.cpp 12 | multiplication.cpp 13 | operations.cpp 14 | paulis.cpp 15 | qureg.cpp 16 | trotterisation.cpp 17 | types.cpp 18 | ) -------------------------------------------------------------------------------- /quest/src/core/constants.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Mathematical constants used by the source code. 3 | * This circumvents the need to litter the code with 4 | * compiler-specific guards to discover maths macros. 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | #ifndef CONSTANTS_HPP 10 | #define CONSTANTS_HPP 11 | 12 | #include "quest/include/types.h" 13 | 14 | 15 | inline constexpr qreal const_PI = 3.14159265358979323846; 16 | 17 | 18 | #endif // CONSTANTS_HPP -------------------------------------------------------------------------------- /examples/automated/apply_no_unitary_pauli_gadget.c: -------------------------------------------------------------------------------- 1 | #include "quest.h" 2 | 3 | int main() { 4 | initQuESTEnv(); 5 | 6 | Qureg qureg = createQureg(3); 7 | PauliStr str = getInlinePauliStr("XYZ", {0,1,2}); 8 | qcomp angle = getQcomp(.4, .8); 9 | 10 | initPlusState(qureg); 11 | applyNonUnitaryPauliGadget(qureg, str, angle); 12 | 13 | qreal norm = calcTotalProb(qureg); 14 | reportScalar("norm", norm); 15 | 16 | finalizeQuESTEnv(); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | add_executable(tests 4 | main.cpp 5 | ) 6 | target_link_libraries(tests PRIVATE QuEST::QuEST Catch2::Catch2) 7 | target_compile_features(tests PUBLIC cxx_std_20) 8 | 9 | add_subdirectory(unit) 10 | add_subdirectory(utils) 11 | add_subdirectory(integration) 12 | 13 | if (ENABLE_DEPRECATED_API) 14 | add_subdirectory(deprecated) 15 | endif() 16 | 17 | 18 | # let Catch2 register all tests with CTest 19 | catch_discover_tests(tests) 20 | -------------------------------------------------------------------------------- /quest/src/gpu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | 3 | target_sources(QuEST 4 | PRIVATE 5 | gpu_config.cpp 6 | gpu_subroutines.cpp 7 | ) 8 | 9 | if (ENABLE_CUDA) 10 | set_source_files_properties( 11 | gpu_config.cpp 12 | gpu_subroutines.cpp 13 | TARGET_DIRECTORY QuEST 14 | PROPERTIES 15 | LANGUAGE CUDA 16 | ) 17 | endif() 18 | 19 | if (ENABLE_HIP) 20 | set_source_files_properties( 21 | gpu_config.cpp 22 | gpu_subroutines.cpp 23 | TARGET_DIRECTORY QuEST 24 | PROPERTIES 25 | LANGUAGE HIP 26 | ) 27 | endif() -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | # ❤️  Contributing 2 | 3 | 9 | 10 | > [!IMPORTANT] 11 | > This page is under construction! 12 | 13 | 14 | 15 | In the meantime, feel free to open an issue, a discussion or a pull request, or reach out to `tyson.jones.input@gmail.com`. 16 | 17 | > [!TIP] 18 | > See [PR #615](https://github.com/QuEST-Kit/QuEST/pull/615) for an illustration of integrating 19 | > new functions into the QuEST software architecture. 20 | -------------------------------------------------------------------------------- /tests/deprecated/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | # @author Erich Essmann (patched MPI) 3 | 4 | add_executable(dep_tests 5 | test_main.cpp 6 | test_calculations.cpp 7 | test_data_structures.cpp 8 | test_decoherence.cpp 9 | test_gates.cpp 10 | test_operators.cpp 11 | test_state_initialisations.cpp 12 | test_unitaries.cpp 13 | test_utilities.cpp 14 | ) 15 | target_link_libraries(dep_tests PUBLIC QuEST::QuEST Catch2::Catch2) 16 | 17 | if (ENABLE_DISTRIBUTION) 18 | target_link_libraries(dep_tests PRIVATE MPI::MPI_CXX) 19 | endif() 20 | 21 | catch_discover_tests(dep_tests) -------------------------------------------------------------------------------- /examples/extended/README.md: -------------------------------------------------------------------------------- 1 | # 🔖📚  Extended examples 2 | 3 | 9 | 10 | This folder contains _extended_ examples which demonstrate the use of QuEST in standalone applications, such as the emulation of canonical quantum algorithms. We provide both `C` and `C++` versions (compiled against standards `C11` and `C++17`) of each example. All fines herein are _compiled_ (but not executed) by the [compile](https://github.com/QuEST-Kit/QuEST/actions/workflows/compile.yml) Github Action. 11 | 12 | -------------------------------------------------------------------------------- /quest/include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | # @author Erich Essmann 3 | # @author Luc Jaulmes (using config file) 4 | # @author Tyson Jones (doc) 5 | 6 | # Generate a header file which defines all configurable preprocessors 7 | # needed by the QuEST source (e.g. COMPILE_MPI), as informed by the 8 | # user-set CMake options. This permits us to avoid passing any macros 9 | # through compiler flags and the associated conflicts arising when 10 | # installing QuEST. Note that config.h must be manually created when 11 | # not compiling via CMake, e.g. when using a custom build script 12 | configure_file(config.h.in config.h @ONLY) 13 | -------------------------------------------------------------------------------- /examples/tutorials/min_example.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * A minimum C/C++-agnostic example of running 3 | * QuEST, reporting the execution environment 4 | * and preparing 20-qubit random pure state. 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | #include "quest.h" 10 | 11 | int main(void) { 12 | 13 | initQuESTEnv(); 14 | reportQuESTEnv(); 15 | 16 | Qureg qureg = createForcedQureg(20); 17 | reportQuregParams(qureg); 18 | 19 | initRandomPureState(qureg); 20 | reportQureg(qureg); 21 | 22 | qreal prob = calcTotalProb(qureg); 23 | reportScalar("Total probability", prob); 24 | 25 | destroyQureg(qureg); 26 | finalizeQuESTEnv(); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /examples/isolated/setting_errorhandler.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of setting the invalid error input handler in C11, 3 | * overriding the default behaviour of immediately exiting. 4 | * 5 | * @author Tyson Jones 6 | */ 7 | 8 | #include "quest.h" 9 | #include 10 | #include 11 | 12 | 13 | void myErrorHandler(const char* errFunc, const char* errMsg) { 14 | printf("Ruh-roh, Raggy! Function '%s' has reported '%s'.\n", errFunc, errMsg); 15 | printf("We will now be very good children and exit immediately!\n"); 16 | exit(0); 17 | } 18 | 19 | 20 | int main() { 21 | initQuESTEnv(); 22 | setInputErrorHandler(myErrorHandler); 23 | 24 | Qureg qureg = createQureg(-123); 25 | 26 | finalizeQuESTEnv(); 27 | } 28 | -------------------------------------------------------------------------------- /quest/src/comm/comm_config.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Functions for querying the distributed configuration 3 | * using the MPI interface, agnostically to the specific 4 | * implementation (like OpenMPI vs MPICH). These functions 5 | * are callable even when MPI has not been compiled/linked. 6 | * 7 | * @author Tyson Jones 8 | */ 9 | 10 | #ifndef COMM_CONFIG_HPP 11 | #define COMM_CONFIG_HPP 12 | 13 | 14 | constexpr int ROOT_RANK = 0; 15 | 16 | bool comm_isMpiCompiled(); 17 | bool comm_isMpiGpuAware(); 18 | 19 | void comm_init(); 20 | void comm_end(); 21 | void comm_sync(); 22 | 23 | int comm_getRank(); 24 | int comm_getNumNodes(); 25 | 26 | bool comm_isInit(); 27 | bool comm_isRootNode(); 28 | bool comm_isRootNode(int rank); 29 | 30 | 31 | #endif // COMM_CONFIG_HPP -------------------------------------------------------------------------------- /quest/src/core/envvars.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Functions for loading environment variables, useful for 3 | * configuring QuEST ahead of calling initQuESTEnv(), after 4 | * compilation. 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | #ifndef ENVVARS_HPP 10 | #define ENVVARS_HPP 11 | 12 | #include 13 | 14 | 15 | namespace envvar_names { 16 | extern std::string PERMIT_NODES_TO_SHARE_GPU; 17 | extern std::string DEFAULT_VALIDATION_EPSILON; 18 | } 19 | 20 | 21 | /* 22 | * LOAD VARS 23 | */ 24 | 25 | void envvars_validateAndLoadEnvVars(const char* caller); 26 | 27 | 28 | /* 29 | * GET VAR 30 | */ 31 | 32 | bool envvars_getWhetherGpuSharingIsPermitted(); 33 | 34 | qreal envvars_getDefaultValidationEpsilon(); 35 | 36 | 37 | #endif // ENVVARS_HPP 38 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # 🔖  Examples 2 | 3 | 9 | 10 | These folders contain example `C` and `C++` files which use QuEST's [API](https://quest-kit.github.io/QuEST/group__api.html), helping illustrate how to use specific functions. Instructions for compiling and running them are given in [`compile.md`](/docs/compile.md#tests) and [`launch.md`](/docs/launch.md#tests) respectively, though some are automatically run by Github Actions. 11 | 13 | 14 | A description of each folder is given within. -------------------------------------------------------------------------------- /examples/isolated/README.md: -------------------------------------------------------------------------------- 1 | # 🔖🔍  Isolated examples 2 | 3 | 9 | 10 | This folder contains _isolated_ examples which demonstrate the possible uses of a specific QuEST function or facility. They mostly serve to illustrate the various ways that a single task (such as initialising a `KrausMap`) can be performed with the QuEST API. We provide both `C` and `C++` versions (compiled against standards `C11` and `C++17`) of each example to highlight the interfaces available to the respective languages. 11 | 12 | Every `.c` and `.cpp` in this folder is compiled _and_ executed by the [compile](https://github.com/QuEST-Kit/QuEST/actions/workflows/compile.yml) Github Action, to automatically check for compilation and link-time issues. 13 | -------------------------------------------------------------------------------- /quest/src/core/autodeployer.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Functions which automatically choose QuESTEnv, Qureg and 3 | * FullStateDiagMatr deployment parameters, replacing flag 4 | * modeflag::USE_AUTO with 0 or 1, depending on the compiled 5 | * facilities, available hardware, and object dimensions. 6 | * 7 | * @author Tyson Jones 8 | */ 9 | 10 | #ifndef AUTODEPLOYER_HPP 11 | #define AUTODEPLOYER_HPP 12 | 13 | #include "quest/include/environment.h" 14 | 15 | 16 | 17 | #define MIN_NUM_LOCAL_QUBITS_FOR_AUTO_QUREG_MULTITHREADING 8 18 | 19 | #define MIN_NUM_LOCAL_QUBITS_FOR_AUTO_QUREG_GPU_ACCELERATION 12 20 | 21 | #define MIN_NUM_LOCAL_QUBITS_FOR_AUTO_QUREG_DISTRIBUTION 26 22 | 23 | 24 | 25 | void autodep_chooseQuESTEnvDeployment(int &useDistrib, int &useGpuAccel, int &useMultithread); 26 | 27 | void autodep_chooseQuregDeployment(int numQubits, int isDensMatr, int &useDistrib, int &useGpuAccel, int &useMultithread, QuESTEnv env); 28 | 29 | void autodep_chooseFullStateDiagMatrDeployment(int numQubits, int &useDistrib, int &useGpuAccel, int &useMultithread, QuESTEnv env); 30 | 31 | 32 | 33 | #endif // AUTODEPLOYER_HPP -------------------------------------------------------------------------------- /tests/utils/convert.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilsconvert Convert 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities for converting QuEST API structures 8 | * (like Qureg, CompMatr, PauliStr) to/from testing types 9 | * (like qvector and qmatrix). 10 | * @{ 11 | */ 12 | 13 | #ifndef CONVERT_HPP 14 | #define CONVERT_HPP 15 | 16 | #include "quest.h" 17 | #include "qvector.hpp" 18 | #include "qmatrix.hpp" 19 | 20 | 21 | void setQuregToReference(Qureg, qvector); 22 | void setQuregToReference(Qureg, qmatrix); 23 | 24 | qvector getVector(Qureg); 25 | qmatrix getMatrix(Qureg); 26 | 27 | qmatrix getMatrix(CompMatr1); 28 | qmatrix getMatrix(CompMatr2); 29 | qmatrix getMatrix(CompMatr ); 30 | qmatrix getMatrix(DiagMatr1); 31 | qmatrix getMatrix(DiagMatr2); 32 | qmatrix getMatrix(DiagMatr ); 33 | qmatrix getMatrix(SuperOp ); 34 | 35 | qmatrix getMatrix(PauliStr str, vector targs); 36 | qmatrix getMatrix(PauliStr str, int numQubits); 37 | qmatrix getMatrix(PauliStrSum sum, int numQubits); 38 | 39 | 40 | #endif // CONVERT_HPP 41 | 42 | /** @} (end defgroup) */ 43 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 The QuEST Authors and Contributors 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 | -------------------------------------------------------------------------------- /quest/src/core/parser.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Internal signatures for parsing user-given strings. 3 | * 4 | * @author Tyson Jones 5 | */ 6 | 7 | #ifndef PARSER_HPP 8 | #define PARSER_HPP 9 | 10 | #include "quest/include/types.h" 11 | #include "quest/include/paulis.h" 12 | 13 | #include 14 | 15 | using std::string; 16 | 17 | 18 | 19 | /* 20 | * PARSING NUMBERS 21 | */ 22 | 23 | bool parser_isAnySizedReal(string str); 24 | bool parser_isAnySizedComplex(string str); 25 | 26 | bool parser_isValidReal(string str); 27 | bool parser_isValidComplex(string str); 28 | 29 | qreal parser_parseReal(string str); 30 | qcomp parser_parseComplex(string str); 31 | 32 | 33 | 34 | /* 35 | * PARSING INDIVIDUAL PAULIS 36 | */ 37 | 38 | const string parser_RECOGNISED_PAULI_CHARS = "0123ixyzIXYZ"; 39 | 40 | int parser_getPauliIntFromChar(char ch); 41 | 42 | 43 | 44 | /* 45 | * PARSING PAULI STRING SUMS 46 | */ 47 | 48 | PauliStrSum parser_validateAndParsePauliStrSum(string lines, bool rightIsLeastSignificant, const char* caller); 49 | 50 | 51 | 52 | /* 53 | * FILE IO 54 | */ 55 | 56 | bool parser_canReadFile(string fn); 57 | 58 | string parser_loadFile(string fn); 59 | 60 | 61 | 62 | #endif // PARSER_HPP -------------------------------------------------------------------------------- /tests/utils/cache.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilscache Cache 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities which create Quregs across all 8 | * available hardware deployments 9 | * @{ 10 | */ 11 | 12 | #ifndef CACHE_HPP 13 | #define CACHE_HPP 14 | 15 | #include "quest.h" 16 | 17 | #include "qvector.hpp" 18 | #include "qmatrix.hpp" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | using quregCache = std::unordered_map; 26 | using matrixCache = std::unordered_map; 27 | using deployInfo = std::vector>; 28 | 29 | int getNumCachedQubits(); 30 | deployInfo getSupportedDeployments(); 31 | 32 | void createCachedFullStateDiagMatrs(); 33 | void destroyCachedFullStateDiagMatrs(); 34 | matrixCache getCachedFullStateDiagMatrs(); 35 | 36 | void createCachedQuregs(); 37 | void destroyCachedQuregs(); 38 | quregCache getCachedStatevecs(); 39 | quregCache getCachedDensmatrs(); 40 | quregCache getAltCachedStatevecs(); 41 | quregCache getAltCachedDensmatrs(); 42 | 43 | qvector getRefStatevec(); 44 | qmatrix getRefDensmatr(); 45 | 46 | 47 | #endif // CACHE_HPP 48 | 49 | /** @} (end defgroup) */ 50 | -------------------------------------------------------------------------------- /tests/utils/lists.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilslists Lists 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities which generate lists of integers. 8 | * @{ 9 | */ 10 | 11 | #ifndef LISTS_HPP 12 | #define LISTS_HPP 13 | 14 | #include 15 | 16 | #include "quest.h" 17 | 18 | #include 19 | #include 20 | 21 | using std::vector; 22 | 23 | using listpair = std::tuple,vector>; 24 | using listtrio = std::tuple,vector,vector>; 25 | 26 | 27 | vector getRange(int start, int endExcl); 28 | vector getRange(int endExcl); 29 | vector getComplement(vector listA, vector listB); 30 | vector getSublist(vector list, int start, int len); 31 | vector getSublist(vector list, int start, int len); 32 | 33 | 34 | template using CatchGen = Catch::Generators::GeneratorWrapper; 35 | CatchGen> sublists(CatchGen&& gen, int sublen); 36 | CatchGen disjointsublists(CatchGen&& gen, int sublen1, int sublen2); 37 | 38 | 39 | vector GENERATE_TARGS(int numQubits, int numTargs); 40 | listpair GENERATE_CTRLS_AND_TARGS(int numQubits, int numCtrls, int numTargs); 41 | 42 | 43 | #endif // LISTS_HPP 44 | 45 | /** @} (end defgroup) */ 46 | -------------------------------------------------------------------------------- /quest/src/comm/comm_indices.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Functions which unambiguously identify the buffer indices 3 | * at which communicated amplitudes are sent and received. 4 | * These are inlined mainly to avoid symbol duplication as 5 | * a header-only file, but also so that callers of e.g. 6 | * getBufferRecvInd() (which use the result as an index-offset 7 | * in hot loops) can exploit the compile-time known constant. 8 | * 9 | * @author Tyson Jones 10 | */ 11 | 12 | #ifndef COMM_INDICES_HPP 13 | #define COMM_INDICES_HPP 14 | 15 | #include "quest/include/types.h" 16 | #include "quest/include/qureg.h" 17 | 18 | #include 19 | 20 | 21 | 22 | static inline qindex getSubBufferSendInd(Qureg qureg) { 23 | 24 | // the maximum size of a swapped sub-buffer is half its capacity, so we 25 | // will always pack sub-buffers starting from half capacity 26 | return qureg.numAmpsPerNode / 2; 27 | } 28 | 29 | 30 | constexpr static inline qindex getBufferRecvInd() { 31 | 32 | // we always receive amplitudes to the start of the buffer, regardless 33 | // of whether we are receiving a full or sub-buffer 34 | return 0; 35 | } 36 | 37 | 38 | static inline std::pair getSubBufferSendRecvInds(Qureg qureg) { 39 | 40 | return {getSubBufferSendInd(qureg), getBufferRecvInd()}; 41 | } 42 | 43 | 44 | 45 | #endif // COMM_INDICES_HPP -------------------------------------------------------------------------------- /utils/docs/latex/commands.tex: -------------------------------------------------------------------------------- 1 | \newcommand{\poormanscomment}{ Please forgive this unorthodox comment; there is apparently no supported comment syntax here! } 2 | \renewcommand{\poormanscomment}{ This file contains custom LaTeX commands which can be used inside Doxygen math environments. } 3 | \renewcommand{\poormanscomment}{ Beware that superfluous whitespace causes errors - Doxygen is much fussier than LaTeX itself! } 4 | 5 | \newcommand{\id}{\mathbb{1}} 6 | \newcommand{\paulix}{\hat{X}} 7 | \newcommand{\pauliy}{\hat{Y}} 8 | \newcommand{\pauliz}{\hat{Z}} 9 | \newcommand{\ket}[1]{|#1\rangle} 10 | \newcommand{\bra}[1]{\langle#1|} 11 | \newcommand{\braket}[2]{\langle#1|#2\rangle} 12 | \newcommand{\ketbra}[2]{|#1\rangle\langle#2|} 13 | \newcommand{\re}[1]{\text{Re}\left(#1\right)} 14 | \newcommand{\im}[1]{\text{Im}\left(#1\right)} 15 | \newcommand{\tr}[1]{\text{Tr}\left(#1\right)} 16 | \newcommand{\svpsi}{\ket{\psi}} 17 | \newcommand{\brapsi}{\bra{\psi}} 18 | \newcommand{\dmrho}{\mathbf{\rho}} 19 | \newcommand{\pstr}{\sigma^{\otimes}} 20 | \newcommand{\iu}{\mathrm{i}} 21 | 22 | 23 | \renewcommand{\poormanscomment}{ The validation epsilon, which should maybe have a special (bold?) symbol } 24 | \newcommand{\valeps}{\epsilon} 25 | 26 | \renewcommand{\poormanscomment}{ Hat is not rendering properly with the (strangely non-CMU) font, so is temporarily disabled } 27 | \renewcommand{\hat}[1]{#1} 28 | -------------------------------------------------------------------------------- /quest/src/api/types.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * API convenience functions related to types. 3 | * 4 | * @author Tyson Jones 5 | */ 6 | 7 | #include "quest/include/types.h" 8 | 9 | #include "quest/src/core/printer.hpp" 10 | #include "quest/src/core/validation.hpp" 11 | 12 | #include 13 | 14 | using std::string; 15 | 16 | 17 | 18 | /* 19 | * STRINGS 20 | */ 21 | 22 | void reportStr(std::string str) { 23 | validate_envIsInit(__func__); 24 | 25 | print(str); 26 | print_newlines(); 27 | } 28 | 29 | extern "C" void reportStr(const char* str) { 30 | reportStr(string(str)); 31 | } 32 | 33 | 34 | 35 | /* 36 | * SCALARS 37 | */ 38 | 39 | void reportScalar(string label, string numstr) { 40 | validate_envIsInit(__func__); 41 | 42 | // harmlessly re-validates 43 | reportStr(label + (label.empty()? "" : ": ") + numstr); 44 | } 45 | 46 | void reportScalar(string label, qcomp num) { reportScalar(label, printer_toStr(num)); } 47 | void reportScalar(string label, qreal num) { reportScalar(label, printer_toStr(num)); } 48 | void reportScalar(const char* label, qreal num) { reportScalar(string(label), printer_toStr(num)); } 49 | 50 | extern "C" { 51 | void reportScalar (const char* label, qcomp num) { reportScalar(string(label), printer_toStr(num)); } 52 | void _reportScalar_real (const char* label, qreal num) { reportScalar(string(label), printer_toStr(num)); } 53 | } 54 | -------------------------------------------------------------------------------- /quest/src/core/randomiser.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Functions for generating random numbers consistent 3 | * between distributed nodes, used for emulating 4 | * quantum measurements and randomly initialising Quregs. 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | #ifndef RANDOMISER_HPP 10 | #define RANDOMISER_HPP 11 | 12 | #include "quest/include/types.h" 13 | 14 | #include 15 | #include 16 | 17 | using std::vector; 18 | 19 | 20 | 21 | /* 22 | * SEEDING 23 | */ 24 | 25 | 26 | void rand_setSeeds(vector seeds); 27 | 28 | void rand_setSeedsToDefault(); 29 | 30 | int rand_getNumSeeds(); 31 | 32 | vector rand_getSeeds(); 33 | 34 | 35 | 36 | /* 37 | * SAMPLING 38 | */ 39 | 40 | 41 | int rand_getRandomSingleQubitOutcome(qreal probOfZero); 42 | 43 | qindex rand_getRandomMultiQubitOutcome(vector probs); 44 | 45 | 46 | 47 | /* 48 | * STATE AMPLITUDE SAMPLING 49 | */ 50 | 51 | 52 | unsigned rand_getThreadSharedRandomSeed(bool distinctPerNode); 53 | 54 | std::mt19937_64 rand_getThreadPrivateGenerator(unsigned sharedSeed, int threadId); 55 | 56 | std::normal_distribution rand_getThreadPrivateAmpAbsDistribution(); 57 | 58 | std::uniform_real_distribution rand_getThreadPrivateAmpPhaseDistribution(); 59 | 60 | qcomp rand_getThreadPrivateRandomAmp(std::mt19937_64 &gen, std::normal_distribution &normDist, std::uniform_real_distribution &phaseDist); 61 | 62 | 63 | 64 | #endif // RANDOMISER_HPP -------------------------------------------------------------------------------- /tests/deprecated/test_main.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Entry-point for the ported tests of QuEST's deprecated 3 | * v3 API. 4 | * 5 | * This file was originally written for catch2 v2, though has 6 | * since been refactored for compatibility with catch2 v3. The 7 | * comments however have not been updated and may mislead. 8 | * 9 | * @author Tyson Jones 10 | * @author Oliver Thomson Brown (ported to Catch2 v3) 11 | * @author Ali Rezaei (tested porting to QuEST v4) 12 | */ 13 | 14 | 15 | /** Use our modified Catch in custom-main mode (main defined below). 16 | * catch.hpp was modified to, in distributed mode, output only once. 17 | */ 18 | #include 19 | 20 | #include "quest.h" 21 | #include "test_utilities.hpp" 22 | 23 | #include 24 | 25 | 26 | 27 | /* 28 | * recast QuEST errors into exceptions which Catch2 can intercept 29 | */ 30 | 31 | /// @private 32 | extern "C" void validationErrorHandler(const char* errFunc, const char* errMsg) { 33 | 34 | throw std::runtime_error(std::string(errFunc) + ": " + std::string(errMsg)); 35 | } 36 | 37 | 38 | /** Explicit declaration of main to create (destroy) the QuESTEnv before (after) 39 | * invoking the Catch unit tests 40 | */ 41 | int main(int argc, char* argv[]) { 42 | 43 | initQuESTEnv(); 44 | setInputErrorHandler(validationErrorHandler); 45 | setRandomTestStateSeeds(); 46 | 47 | int result = Catch::Session().run( argc, argv ); 48 | 49 | finalizeQuESTEnv(); 50 | return result; 51 | } 52 | -------------------------------------------------------------------------------- /tests/utils/macros.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilsmacros Macros 5 | * @ingroup testutils 6 | * @brief 7 | * Macros used by the tests and testing utilities. 8 | * @{ 9 | */ 10 | 11 | #ifndef MACROS_HPP 12 | #define MACROS_HPP 13 | 14 | #include 15 | 16 | 17 | /* 18 | * preconditions to the internal unit testing functions are checked using 19 | * DEMAND rather than Catch2's REQUIRE, so that they are not counted in the 20 | * total unit testing statistics (e.g. number of checks passed). 21 | */ 22 | 23 | #define DEMAND( cond ) do { if (!(cond)) { FAIL( ); } } while (0) 24 | 25 | 26 | // section labels 27 | 28 | #define LABEL_CORRECTNESS "correctness" 29 | #define LABEL_VALIDATION "validation" 30 | #define LABEL_STATEVEC "statevector" 31 | #define LABEL_DENSMATR "densitymatrix" 32 | #define LABEL_C_INTERFACE "C interface" 33 | #define LABEL_CPP_INTERFACE "C++ interface" 34 | 35 | #define LABEL_DELIMITER ", " 36 | 37 | #define LABEL_UNIT_TAG "[unit]" 38 | #define LABEL_MIXED_DEPLOY_TAG "[mixed]" 39 | #define LABEL_INTEGRATION_TAG "[integration]" 40 | 41 | 42 | // detect LLVM address sanitizer (on GCC and Clang only) 43 | #if defined(__SANITIZE_ADDRESS__) 44 | #define SANITIZER_IS_ACTIVE 45 | #elif defined(__has_feature) 46 | #if __has_feature(address_sanitizer) 47 | #define SANITIZER_IS_ACTIVE 48 | #endif 49 | #endif 50 | 51 | 52 | #endif // MACROS_HPP 53 | 54 | /** @} (end defgroup) */ 55 | -------------------------------------------------------------------------------- /utils/docs/layout/doxygen-awesome-quest.js: -------------------------------------------------------------------------------- 1 | 2 | window.addEventListener('DOMContentLoaded', (event) => { 3 | 4 | /* injects the QuEST version number below the logo in the 5 | * left nav-bar; this requires this script is included in 6 | * header.html, and the version number style is customised 7 | * in *-quest.css. This snippet was taken from Zephyr's 8 | * github (github.com/zephyrproject-rtos/zephyr) at: 9 | * zephyr/doc/_doxygen/doxygen-awesome-zephyr.js */ 10 | 11 | let version = document.getElementById('projectnumber').innerText 12 | let titleTable = document.querySelector('#titlearea table'); 13 | let cell = titleTable.insertRow(1).insertCell(0); 14 | cell.innerHTML = '
' + version + '
'; 15 | 16 | 17 | /* deletes the superfluous/ugly title atop Mainpage (which 18 | * says "The Quantum Exact Simulation Toolkit"), before the 19 | * banner image. The same html element is necessary on other 20 | * pages, so we selectively delete it from index.html. This 21 | * would be more elegantly done using css in *-quest.css, 22 | * which would avoid the post-render-delete visual stutter, 23 | * but alas I cannot find unique page-ids I can refer to! */ 24 | 25 | let fn = window.location.pathname.split("/").pop(); 26 | if (fn === "index.html") { 27 | const element = document.querySelector(".header"); 28 | if (element) { 29 | element.remove(); 30 | } 31 | } 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /tests/utils/qvector.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilsqvector qvector 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities which define 'qvector', used 8 | * as a reference proxy to a quantum statevector. 9 | * @{ 10 | */ 11 | 12 | #ifndef QVECTOR_HPP 13 | #define QVECTOR_HPP 14 | 15 | #include "quest.h" 16 | #include "macros.hpp" 17 | #include 18 | 19 | 20 | typedef std::vector qvector; 21 | 22 | 23 | qvector getZeroVector(size_t dim); 24 | qvector getConstantVector(size_t dim, qcomp elem); 25 | 26 | qvector operator * (const qcomp&, const qvector&); 27 | qvector operator * (const qvector&, const qcomp&); 28 | qvector operator * (const qreal&, const qvector&); 29 | qvector operator * (const qvector&, const qreal&); 30 | qvector operator *= (qvector&, const qcomp&); 31 | qvector operator *= (qvector&, const qreal&); 32 | 33 | qvector operator / (const qvector&, const qcomp&); 34 | qvector operator / (const qvector&, const qreal&); 35 | qvector operator /= (qvector&, const qcomp&); 36 | qvector operator /= (qvector&, const qreal&); 37 | 38 | qvector operator + (const qvector&, const qvector&); 39 | qvector operator += (qvector&, const qvector&); 40 | 41 | qvector operator - (const qvector&, const qvector&); 42 | qvector operator -= (qvector&, const qvector&); 43 | 44 | void setSubVector(qvector &dest, qvector sub, size_t i); 45 | void setToDebugState(qvector &v); 46 | 47 | 48 | #endif // QVECTOR_HPP 49 | 50 | /** @} (end defgroup) */ 51 | -------------------------------------------------------------------------------- /tests/unit/trotterisation.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Unit tests of the trotterisation module. 3 | * 4 | * @author Tyson Jones 5 | * 6 | * @defgroup unittrotter Trotterisation 7 | * @ingroup unittests 8 | */ 9 | 10 | #include "quest.h" 11 | 12 | 13 | 14 | /* 15 | * UTILITIES 16 | */ 17 | 18 | #define TEST_CATEGORY \ 19 | LABEL_UNIT_TAG "[trotterisation]" 20 | 21 | 22 | 23 | /** 24 | * @todo 25 | * UNTESTED FUNCTIONS 26 | */ 27 | 28 | void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qcomp angle, int order, int reps); 29 | 30 | void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps); 31 | 32 | void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps); 33 | 34 | void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int* controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps); 35 | 36 | void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStrSum sum, qreal angle, int order, int reps); 37 | 38 | void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps); 39 | 40 | void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps); 41 | 42 | void applyTrotterizedNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal* damps, PauliStr* jumps, int numJumps, qreal time, int order, int reps); 43 | -------------------------------------------------------------------------------- /.github/workflows/doc.yml: -------------------------------------------------------------------------------- 1 | # Generates API documentation using doxygen, 2 | # and hosts it on Github using Github Pages 3 | # 4 | # @author Tyson Jones 5 | 6 | name: doc 7 | 8 | 9 | permissions: 10 | contents: write 11 | pages: write 12 | id-token: write 13 | 14 | 15 | on: 16 | push: 17 | branches: 18 | - main 19 | workflow_dispatch: 20 | 21 | 22 | # prevent concurrent generation 23 | concurrency: 24 | group: "pages" 25 | cancel-in-progress: false 26 | 27 | 28 | jobs: 29 | 30 | build-doc: 31 | name: Generate doc 32 | runs-on: ubuntu-latest 33 | 34 | environment: 35 | name: github-pages 36 | url: ${{ steps.deployment.outputs.page_url }} 37 | 38 | env: 39 | doxy_file: utils/docs/Doxyfile 40 | doxy_out: Doxygen_doc/html 41 | build_dir: "build" 42 | 43 | steps: 44 | - name: Obtain copy of repository 45 | uses: actions/checkout@main 46 | 47 | - name: Install Graphviz (for circuit diagrams) 48 | uses: tlylt/install-graphviz@v1 49 | 50 | - name: Generate doc with doxygen 51 | uses: mattnotmitt/doxygen-action@v1.12.0 52 | with: 53 | doxyfile-path: ${{ env.doxy_file }} 54 | enable-latex: true 55 | 56 | - name: Setup Github Pages 57 | uses: actions/configure-pages@v5 58 | 59 | - name: Upload doc as artifact 60 | uses: actions/upload-pages-artifact@v3 61 | with: 62 | path: ./${{ env.doxy_out }} 63 | 64 | - name: Deploy doc to GitHub Pages 65 | id: deployment 66 | uses: actions/deploy-pages@v4 67 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # @author Oliver Thomson Brown 2 | # @author Erich Essmann (updating rpath) 3 | # @author Tyson Jones (refactored to functions + glob) 4 | 5 | 6 | 7 | # compiles in_fn to ../examples/direc/in_fn_c 8 | 9 | function(add_example direc in_fn) 10 | 11 | # fn.cpp -> filename=fn, filelang=cpp 12 | get_filename_component(filename ${in_fn} NAME_WE) 13 | get_filename_component(filelang ${in_fn} LAST_EXT) 14 | string(REPLACE "." "" filelang ${filelang}) 15 | 16 | set(target "${filename}_${filelang}") 17 | set(out_fn "${filename}_${filelang}") 18 | set(out_dir "${CMAKE_INSTALL_BINDIR}/examples/${direc}/") 19 | 20 | add_executable(${target} ${in_fn}) 21 | target_link_libraries(${target} PUBLIC QuEST) 22 | 23 | install( 24 | TARGETS ${target} 25 | RUNTIME 26 | DESTINATION ${out_dir} 27 | ) 28 | 29 | set_target_properties(${target} 30 | PROPERTIES 31 | INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" 32 | OUTPUT_NAME "${out_fn}" 33 | ) 34 | 35 | endfunction() 36 | 37 | 38 | 39 | # compiles all .c or .cpp files in the subdirecs below 40 | 41 | function(add_all_local_examples) 42 | 43 | get_filename_component(direc ${CMAKE_CURRENT_LIST_DIR} NAME) 44 | 45 | file(GLOB files 46 | "${CMAKE_CURRENT_SOURCE_DIR}/*.c" 47 | "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" 48 | ) 49 | 50 | foreach(fn ${files}) 51 | add_example(${direc} ${fn}) 52 | endforeach() 53 | 54 | endfunction() 55 | 56 | 57 | 58 | # all subdirecs below will invoke add_all_local_examples() 59 | 60 | add_subdirectory(isolated) 61 | add_subdirectory(extended) 62 | add_subdirectory(automated) 63 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # 🧪  Tests 8 | 9 | This folder contains QuEST's extensive tests. See [`compile.md`](/docs/compile.md#tests) and [`launch.md`](/docs/launch.md#tests) to get them running. 10 | 11 | The subdirectories are: 12 | - [`utils`](utils/) containing test utilities, including non-optimised functions against which QuEST output is compared. 13 | - [`unit`](unit) containing [unit tests](https://en.wikipedia.org/wiki/Unit_testing) which test individual QuEST functions in isolation, under their entire input domains (where feasible). 14 | - [`integration`](integration/) containing [integration tests](https://en.wikipedia.org/wiki/Integration_testing) which test multiple QuEST functions working at scale. 15 | - [`deprecated`](deprecated/) containing `v3`'s tests and utilities, only used when explicitly [activated](/docs/compile.md#v3). 16 | 17 | The tests use [Catch2](https://github.com/catchorg/Catch2) and are generally structured as 18 | ```cpp 19 | TEST_CASE( "someApiFunc", "[funcs]" ) { 20 | 21 | PREPARE_TEST(...) 22 | 23 | SECTION( "correctness" ) { 24 | 25 | SECTION( "statevector" ) { 26 | 27 | auto a = getApiResult(); 28 | auto b = getReferenceResult(); 29 | REQUIRE_AGREE(a, b); 30 | } 31 | 32 | SECTION( "density matrix" ) { 33 | 34 | auto a = getApiResult(); 35 | auto b = getReferenceResult();s 36 | } 37 | } 38 | 39 | SECTION( "validation" ) { 40 | 41 | SECTION( "some way to mess it up" ) { 42 | 43 | REQUIRE_THROWS( someApiFunc(badArgs) ); 44 | } 45 | } 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /quest/include/quest.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * The main QuEST header, exposing the entire API. 3 | * This header is intendedly included by user 4 | * source-code, and is both C11 and C++14 compatible. 5 | * 6 | * @author Tyson Jones 7 | * @author Luc Jaulmes (patching CMake install) 8 | * 9 | * @defgroup api 📋 API 10 | */ 11 | 12 | /** 13 | * @page apilink 📋 API 14 | * The API documentation can be viewed at @ref api. 15 | * 16 | * We're working hard to move that page up one level. 😎 17 | */ 18 | 19 | /** 20 | * @page testlink 🧪 Tests 21 | * 22 | * The unit and integration tests can be viewed at @ref tests. 23 | * 24 | * We're working hard to move that page up one level. 😎 25 | */ 26 | 27 | #ifndef QUEST_H 28 | #define QUEST_H 29 | 30 | // include config.h first to define macros 31 | // consulted by subsequent headers 32 | #include "quest/include/config.h" 33 | 34 | #include "quest/include/modes.h" 35 | #include "quest/include/precision.h" 36 | #include "quest/include/types.h" 37 | #include "quest/include/calculations.h" 38 | #include "quest/include/debug.h" 39 | #include "quest/include/decoherence.h" 40 | #include "quest/include/environment.h" 41 | #include "quest/include/trotterisation.h" 42 | #include "quest/include/initialisations.h" 43 | #include "quest/include/channels.h" 44 | #include "quest/include/multiplication.h" 45 | #include "quest/include/operations.h" 46 | #include "quest/include/paulis.h" 47 | #include "quest/include/qureg.h" 48 | #include "quest/include/matrices.h" 49 | #include "quest/include/wrappers.h" 50 | 51 | 52 | #if INCLUDE_DEPRECATED_FUNCTIONS 53 | #include "quest/include/deprecated.h" 54 | #endif 55 | 56 | 57 | 58 | #endif // QUEST_H 59 | -------------------------------------------------------------------------------- /utils/docs/layout/doxygen-awesome-sidebar-only-darkmode-toggle.css: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | 4 | Doxygen Awesome 5 | https://github.com/jothepro/doxygen-awesome-css 6 | 7 | MIT License 8 | 9 | Copyright (c) 2021 - 2023 jothepro 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | 29 | */ 30 | 31 | @media screen and (min-width: 768px) { 32 | 33 | #MSearchBox { 34 | width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px); 35 | } 36 | 37 | #MSearchField { 38 | width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/utils/measure.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilsmeasure Measure 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities which evaluate measurements upon 8 | * reference qvector and qmatrix states. These are slow, 9 | * serial, un-optimised, defensively-designed routines. 10 | * @{ 11 | */ 12 | 13 | #ifndef MEASURE_HPP 14 | #define MEASURE_HPP 15 | 16 | #include "quest.h" 17 | 18 | #include "qvector.hpp" 19 | #include "qmatrix.hpp" 20 | 21 | 22 | qcomp getReferenceExpectationValue(qvector state, qmatrix observable); 23 | qcomp getReferenceExpectationValue(qmatrix state, qmatrix observable); 24 | 25 | qcomp getReferenceExpectationValue(qvector state, PauliStr str); 26 | qcomp getReferenceExpectationValue(qmatrix state, PauliStr str); 27 | 28 | qcomp getReferenceExpectationValue(qvector state, PauliStrSum sum); 29 | qcomp getReferenceExpectationValue(qmatrix state, PauliStrSum sum); 30 | 31 | qreal getReferenceProbability(qvector state); 32 | qreal getReferenceProbability(qmatrix state); 33 | 34 | qreal getReferenceProbability(qvector state, qindex basisIndex); 35 | qreal getReferenceProbability(qmatrix state, qindex basisIndex); 36 | 37 | qreal getReferenceProbability(qvector state, vector targets, vector outcomes); 38 | qreal getReferenceProbability(qmatrix state, vector targets, vector outcomes); 39 | 40 | vector getAllReferenceProbabilities(qvector state, vector targets); 41 | vector getAllReferenceProbabilities(qmatrix state, vector targets); 42 | 43 | qreal getReferencePurity(qvector state); 44 | qreal getReferencePurity(qmatrix state); 45 | 46 | 47 | #endif // MEASURE_HPP 48 | 49 | /** @} (end defgroup) */ 50 | -------------------------------------------------------------------------------- /tests/utils/compare.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilscompare Compare 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities which compare scalars produced by the 8 | * QuEST API to those produced by other test utilities, and 9 | * Quregs modified by the API to qvector qmatrix references. 10 | * @{ 11 | */ 12 | 13 | #ifndef COMPARE_HPP 14 | #define COMPARE_HPP 15 | 16 | #include "quest.h" 17 | #include "qvector.hpp" 18 | #include "qmatrix.hpp" 19 | 20 | #include 21 | using std::vector; 22 | 23 | 24 | qreal getTestAbsoluteEpsilon(); 25 | qreal getTestRelativeEpsilon(); 26 | 27 | bool doScalarsAgree(qcomp a, qcomp b); 28 | bool doMatricesAgree(qmatrix a, qmatrix b); 29 | 30 | void REQUIRE_AGREE( Qureg qureg, Qureg other ); 31 | 32 | void REQUIRE_AGREE( Qureg qureg, qvector reference ); 33 | void REQUIRE_AGREE( Qureg qureg, qmatrix reference ); 34 | 35 | void REQUIRE_AGREE( qreal scalar, qreal reference ); 36 | void REQUIRE_AGREE( qcomp scalar, qcomp reference ); 37 | 38 | void REQUIRE_AGREE( vector list, vector reference ); 39 | void REQUIRE_AGREE( vector list, vector reference ); 40 | 41 | void REQUIRE_AGREE( qmatrix matrix, qmatrix reference ); 42 | void REQUIRE_AGREE( CompMatr1 matrix, qmatrix reference ); 43 | void REQUIRE_AGREE( CompMatr2 matrix, qmatrix reference ); 44 | void REQUIRE_AGREE( CompMatr matrix, qmatrix reference ); 45 | void REQUIRE_AGREE( DiagMatr1 matrix, qmatrix reference ); 46 | void REQUIRE_AGREE( DiagMatr2 matrix, qmatrix reference ); 47 | void REQUIRE_AGREE( DiagMatr matrix, qmatrix reference ); 48 | void REQUIRE_AGREE( SuperOp matrix, qmatrix reference ); 49 | 50 | 51 | #endif // COMPARE_HPP 52 | 53 | /** @} (end defgroup) */ 54 | -------------------------------------------------------------------------------- /examples/automated/README.md: -------------------------------------------------------------------------------- 1 | # 🔖🤖  Automated examples 2 | 3 | 9 | 10 | This folder contains examples which are compiled and executed by QuEST's `compile` Github Action, on [free runners](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners). 11 | Contributors can include rudimentary testing or demo code in this folder (as standalone `.c` or `.cpp` files) 12 | in their pull requests and preview its output on Github, where it is run with every combination of operating system, compiler and precision. 13 | This is intended for debugging and/or logging purposes, rather than for presenting example codes for users. 14 | 15 | > [!IMPORTANT] 16 | > Beware that the configurations include use of multithreading, distribution and GPU-acceleration (as `OMP`, `MPI` and `CUDA` respectively) though this reflects only their _compilation_. All files are executed serially and locally on the CPU. 17 | 18 | The output can be viewed at the `compile.yml` 19 | [workflow tab](https://github.com/QuEST-Kit/QuEST/actions/workflows/compile.yml), clicking on the PR name, selecting a configuration (such as `Windows [1] OMP`) and expanding the `run automated examples` section. All files within `automated/` will be run in-turn and their outputs sequentially presented. 20 | 21 | > [!IMPORTANT] 22 | > Since these examples are executed at every invocation of the CI, they should _not_ perform intensive, long computations. Such examples are better suited for the [`extended/`](../extended/) folder. 23 | 24 | > [!TIP] 25 | > Files with extensions `.c` or `.cpp` will be respectively compiled in `C11` and `C++17`. An example which uses a facility sensitive to the language can be duplicated as both `file.c` and `file.cpp` so that both versions are tested. 26 | -------------------------------------------------------------------------------- /tests/utils/qmatrix.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilsqmatrix qmatrix 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities which define 'qmatrix', used 8 | * to perform reference complex matrix algebra, and 9 | * as a reference proxy to a quantum density matrix. 10 | * @{ 11 | */ 12 | 13 | #ifndef QMATRIX_HPP 14 | #define QMATRIX_HPP 15 | 16 | #include "quest.h" 17 | #include "qvector.hpp" 18 | 19 | #include 20 | using std::vector; 21 | 22 | 23 | typedef vector> qmatrix; 24 | 25 | 26 | qmatrix getZeroMatrix(size_t dim); 27 | qmatrix getConstantMatrix(size_t dim, qcomp elem); 28 | qmatrix getIdentityMatrix(size_t dim); 29 | qmatrix getDiagonalMatrix(qvector v); 30 | qmatrix getPauliMatrix(int id); 31 | 32 | qmatrix operator * (const qcomp&, const qmatrix& ); 33 | qmatrix operator * (const qmatrix&, const qcomp&); 34 | qmatrix operator * (const qreal&, const qmatrix&); 35 | qmatrix operator * (const qmatrix&, const qreal&); 36 | qmatrix operator *= (qmatrix&, const qcomp&); 37 | qmatrix operator *= (qmatrix&, const qreal&); 38 | 39 | qmatrix operator / (const qmatrix&, const qcomp&); 40 | qmatrix operator / (const qmatrix&, const qreal&) ; 41 | qmatrix operator /= (qmatrix&, const qcomp&); 42 | qmatrix operator /= (qmatrix&, const qreal&); 43 | 44 | qmatrix operator + (const qmatrix&, const qmatrix&); 45 | qmatrix operator += (qmatrix&, const qmatrix&); 46 | 47 | qmatrix operator - (const qmatrix&, const qmatrix&); 48 | qmatrix operator -= (qmatrix&, const qmatrix&); 49 | 50 | qmatrix operator * (const qmatrix&, const qmatrix&); 51 | qmatrix operator *= (qmatrix&, const qmatrix&); 52 | 53 | void setSubMatrix(qmatrix &dest, qmatrix sub, size_t r, size_t c); 54 | void setSubMatrix(qmatrix &dest, qvector sub, size_t flatInd); 55 | void setToDebugState(qmatrix &m); 56 | 57 | qvector getDiagonals(qmatrix m); 58 | 59 | 60 | #endif // QMATRIX_HPP 61 | 62 | /** @} (end defgroup) */ 63 | -------------------------------------------------------------------------------- /quest/src/cpu/cpu_config.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Utility signatures for querying the CPU multithreadng 3 | * configuration, and allocating and copying RAM data. 4 | * 5 | * @author Tyson Jones 6 | */ 7 | 8 | #ifndef CPU_CONFIG_HPP 9 | #define CPU_CONFIG_HPP 10 | 11 | #include "quest/include/types.h" 12 | #include "quest/include/paulis.h" 13 | 14 | #include 15 | 16 | using std::vector; 17 | 18 | 19 | 20 | /* 21 | * OPENMP CONFIG 22 | */ 23 | 24 | bool cpu_isOpenmpCompiled(); 25 | 26 | int cpu_getAvailableNumThreads(); 27 | 28 | int cpu_getNumOpenmpProcessors(); 29 | 30 | 31 | 32 | /* 33 | * OPENMP SUBROUTINES 34 | */ 35 | 36 | int cpu_getOpenmpThreadInd(); 37 | 38 | int cpu_getCurrentNumThreads(); 39 | 40 | 41 | 42 | /* 43 | * MEMORY ALLOCATION 44 | */ 45 | 46 | qcomp* cpu_allocArray(qindex length); 47 | void cpu_deallocArray(qcomp* arr); 48 | 49 | qcomp* cpu_allocNumaArray(qindex length); 50 | void cpu_deallocNumaArray(qcomp* arr, qindex length); 51 | 52 | qcomp** cpu_allocAndInitMatrixWrapper(qcomp* arr, qindex dim); 53 | void cpu_deallocMatrixWrapper(qcomp** wrapper); 54 | 55 | qcomp** cpu_allocMatrix(qindex dim); 56 | void cpu_deallocMatrix(qcomp** matrix, qindex dim); 57 | 58 | qcomp*** cpu_allocMatrixList( qindex numRows, int numMatrices); 59 | void cpu_deallocMatrixList(qcomp*** matrices, qindex numRows, int numMatrices); 60 | 61 | int* cpu_allocHeapFlag(); 62 | void cpu_deallocHeapFlag(int* ptr); 63 | 64 | PauliStr* cpu_allocPauliStrings(qindex numStrings); 65 | void cpu_deallocPauliStrings(PauliStr* strings); 66 | 67 | 68 | long cpu_getPageSize(); 69 | 70 | 71 | /* 72 | * MEMORY MOVEMENT 73 | */ 74 | 75 | void cpu_copyArray(qcomp* dest, qcomp* src, qindex dim); 76 | 77 | void cpu_copyMatrix(qcomp** dest, qcomp** src, qindex dim); 78 | void cpu_copyMatrix(qcomp** dest, vector> src, qindex dim); 79 | 80 | void cpu_copyPauliStrSum(PauliStrSum out, PauliStr* strings, qcomp* coeffs); 81 | 82 | 83 | 84 | #endif // CPU_CONFIG_HPP -------------------------------------------------------------------------------- /tests/utils/config.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Testing utilities for loading environment variables 3 | * which configure the unit tests, independent of QuEST's 4 | * internal environment variable facilities 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using std::string; 14 | 15 | 16 | /* 17 | * PRIVATE 18 | */ 19 | 20 | string getEnvVarValue(string name) { 21 | 22 | // unspecified var returns empty string 23 | const char* ptr = std::getenv(name.c_str()); 24 | return (ptr == nullptr)? "" : std::string(ptr); 25 | } 26 | 27 | int getIntEnvVarValueOrDefault(string name, int defaultValue) { 28 | 29 | string strValue = getEnvVarValue(name); 30 | int intValue = defaultValue; 31 | 32 | // overwrite default only when passed variable is interpretable 33 | try { 34 | intValue = std::stoi(strValue); 35 | } 36 | catch (const std::out_of_range&) { } 37 | catch (const std::invalid_argument&) { } 38 | return intValue; 39 | } 40 | 41 | 42 | /* 43 | * PUBLIC 44 | * 45 | * which each call std::getenv only once 46 | */ 47 | 48 | int getNumQubitsInUnitTestedQuregs() { 49 | 50 | static int value = getIntEnvVarValueOrDefault("TEST_NUM_QUBITS_IN_QUREG", 6); 51 | return value; 52 | } 53 | 54 | int getMaxNumTestedQubitPermutations() { 55 | 56 | static int value = getIntEnvVarValueOrDefault("TEST_MAX_NUM_QUBIT_PERMUTATIONS", 0); 57 | return value; 58 | } 59 | 60 | int getMaxNumTestedSuperoperatorTargets() { 61 | 62 | static int value = getIntEnvVarValueOrDefault("TEST_MAX_NUM_SUPEROP_TARGETS", 4); 63 | return value; 64 | } 65 | 66 | int getNumTestedMixedDeploymentRepetitions() { 67 | 68 | static int value = getIntEnvVarValueOrDefault("TEST_NUM_MIXED_DEPLOYMENT_REPETITIONS", 10); 69 | return value; 70 | } 71 | 72 | bool getWhetherToTestAllDeployments() { 73 | 74 | static bool value = getIntEnvVarValueOrDefault("TEST_ALL_DEPLOYMENTS", 1); 75 | return value; 76 | } 77 | -------------------------------------------------------------------------------- /examples/isolated/setting_errorhandler.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of setting the invalid error input handler in C++14, 3 | * overriding the default behaviour of immediately exiting. 4 | * 5 | * @author Tyson Jones 6 | */ 7 | 8 | #include "quest.h" 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | void myErrorHandlerA(const char* errFunc, const char* errMsg) { 15 | 16 | std::string func(errFunc); 17 | std::string msg(errMsg); 18 | 19 | std::cout 20 | << "an error?? in the '" << errFunc << "' function?? with message '" << msg << "'! " 21 | << "how queer!! ive never seen such a thing - i must throw an exception post-haste!!!" 22 | << std::endl 23 | << std::endl; 24 | 25 | // exception forces control-flow out of QuEST env, safely back to user. 26 | // without this, control-flow would return to the QuEST backend and likely 27 | // cause internal integrity checks to fail, or segmentation faults 28 | throw std::runtime_error(std::string(errFunc) + ": " + std::string(errMsg)); 29 | } 30 | 31 | 32 | void myErrorHandlerB(const char* errFunc, const char* errMsg) { 33 | 34 | std::string func(errFunc); 35 | std::string msg(errMsg); 36 | 37 | std::cout 38 | << "Function '" << func << "' threw '" << msg << "'." 39 | << std::endl 40 | << "We will now exit completely. Good day!" 41 | << std::endl 42 | << std::endl; 43 | 44 | exit(0); 45 | } 46 | 47 | 48 | int main() { 49 | initQuESTEnv(); 50 | 51 | setInputErrorHandler(myErrorHandlerA); 52 | 53 | try { 54 | Qureg qureg = createQureg(-123); 55 | } catch (std::runtime_error& e) { 56 | std::cout 57 | << "Error caught! Function aborted, but execution continues." 58 | << std::endl 59 | << std::endl; 60 | } 61 | 62 | setInputErrorHandler(myErrorHandlerB); 63 | initQuESTEnv(); // illegal to recall 64 | 65 | std::cout << "this will never be reached, because myErrorHandlerB exits!" << std::endl; 66 | 67 | finalizeQuESTEnv(); 68 | } 69 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Contact: tyson.jones.input@gmail.com 4 | 5 | Current team: 6 | Dr Tyson Ray Jones [developer] 7 | algorithms 8 | parallelisation 9 | architecture 10 | interface 11 | testing 12 | documentation 13 | Dr Oliver Thomson Brown [developer] 14 | build 15 | patches 16 | Dr Erich Essmann [developer] 17 | build 18 | patches 19 | Dr Ali Rezaei [developer] 20 | optimisation prototyping 21 | Dr Richard Meister [consultant] 22 | design 23 | patches 24 | previous development 25 | Dr Balint Koczor [consultant] 26 | patches 27 | previous development 28 | Prof Simon C. Benjamin [consultant] 29 | user requirements 30 | 31 | Past members: 32 | Dr Ania (Anna) Brown [developer] 33 | HPC 34 | build 35 | quantum ops 36 | Dr Fergus Cooper [developer] 37 | continuous integration 38 | Mr Jacob Wilkins [developer] 39 | testing 40 | Dr Mihai Duta [developer] 41 | original prototyping 42 | Dr Ian Bush [consultant] 43 | software development 44 | HPC 45 | 46 | External contributors: 47 | Diogo Pratas Maia 48 | added non-unitary Pauli gadget (for unitaryHACK issue #594) 49 | Mai Đức Khang 50 | implemented RAM probe (for unitaryHACK issue #600) 51 | James Richings 52 | patched overflow in bitwise.hpp logic 53 | Luc Jaulmes 54 | patched v4's install process using CMake 55 | Jakub Adamski 56 | optimised distributed communication by sending max-size messages asynchronously 57 | Bruno Villasenor Alvarez on behalf of AMD 58 | ported the GPU backend to HIP, for AMD GPU compatibility 59 | Dr Nicolas Vogt on behalf of HQS Quantum Simulations 60 | implemented mixDamping (CPU) 61 | Kshitij Chhabra 62 | patched validateNumQubitsInQureg 63 | Drew Silcock 64 | patched MacOS OpenMP CMake flags 65 | Zach van Rijn 66 | patched OpenMP on GCC-9 67 | SchineCompton 68 | patched GPU Cmake Release build 69 | Christopher J. Anders 70 | patched Cmake build when multhithreading defaults off 71 | revsied Cmake min version for GPU build 72 | Gleb Struchalin 73 | patched the cmake standalone build 74 | Milos Prokop 75 | implemented serial prototype of initDiagonalOpFromPauliHamil -------------------------------------------------------------------------------- /quest/src/comm/comm_routines.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Signatures for communicating and exchanging amplitudes between compute 3 | * nodes, when running in distributed mode, using the C MPI standard. 4 | * Calling these functions when COMPILE_MPI=0, or when the passed Quregs 5 | * are not distributed, will throw a runtime internal error. 6 | * 7 | * @author Tyson Jones 8 | */ 9 | 10 | #ifndef COMM_ROUTINES_HPP 11 | #define COMM_ROUTINES_HPP 12 | 13 | #include "quest/include/types.h" 14 | #include "quest/include/qureg.h" 15 | #include "quest/include/matrices.h" 16 | 17 | #include 18 | #include 19 | 20 | using std::vector; 21 | 22 | 23 | 24 | /* 25 | * STATE EXCHANGE METHODS 26 | */ 27 | 28 | void comm_exchangeAmpsToBuffers(Qureg qureg, qindex sendInd, qindex recvInd, qindex numAmps, int pairRank); 29 | 30 | void comm_exchangeAmpsToBuffers(Qureg qureg, int pairRank); 31 | 32 | void comm_exchangeSubBuffers(Qureg qureg, qindex numAmpsAndRecvInd, int pairRank); 33 | 34 | void comm_asynchSendSubBuffer(Qureg qureg, qindex numElems, int pairRank); 35 | 36 | void comm_receiveArrayToBuffer(Qureg qureg, qindex numElems, int pairRank); 37 | 38 | void comm_combineAmpsIntoBuffer(Qureg receiver, Qureg sender); 39 | 40 | void comm_combineElemsIntoBuffer(Qureg receiver, FullStateDiagMatr sender); 41 | 42 | 43 | 44 | /* 45 | * MISC COMMUNICATION METHODS 46 | */ 47 | 48 | void comm_broadcastAmp(int sendRank, qcomp* sendAmp); 49 | 50 | void comm_sendAmpsToRoot(int sendRank, qcomp* send, qcomp* recv, qindex numAmps); 51 | 52 | void comm_broadcastIntsFromRoot(int* arr, qindex length); 53 | 54 | void comm_broadcastUnsignedsFromRoot(unsigned* arr, qindex length); 55 | 56 | void comm_combineSubArrays(qcomp* recv, vector globalRecvInds, vector localSendInds, vector numAmpsPerRank); 57 | 58 | 59 | 60 | /* 61 | * REDUCTION METHODS 62 | */ 63 | 64 | void comm_reduceAmp(qcomp* localAmp); 65 | 66 | void comm_reduceReal(qreal* localReal); 67 | 68 | void comm_reduceReals(qreal* localReals, qindex numLocalReals); 69 | 70 | bool comm_isTrueOnAllNodes(bool val); 71 | 72 | bool comm_isTrueOnRootNode(bool val); 73 | 74 | 75 | 76 | /* 77 | * GATHER METHODS 78 | */ 79 | 80 | vector comm_gatherStringsToRoot(char* localChars, int maxNumLocalChars); 81 | 82 | 83 | 84 | #endif // COMM_ROUTINES_HPP -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 📖  Documentation 2 | 3 | 9 | 10 | 11 | > [!IMPORTANT] 12 | > QuEST's `v4` documentation is still under construction. 13 | 14 | QuEST has been overhauled! See 15 | 16 | - 🎉  [`v4.md`](v4.md) for the exciting new features. 17 | 18 | To get started with QuEST, check out 19 | 20 | - 🔧  [`compilers.md`](compilers.md) for a list of compatible compilers. 21 | - 🔗  [`qtechtheory.org`](https://quest.qtechtheory.org/download/) for some help downloading compilers. 22 | - 🛠️  [`compile.md`](compile.md) for instructions on compiling. 23 | - ⚙️  [`cmake.md`](cmake.md) for a list of compiler variables. 24 | - 🚀  [`launch.md`](launch.md) to learn how to run QuEST on laptops to supercomputers. 25 | - 🎓  [`tutorial.md`](tutorial.md) for an introductory tutorial. 26 | - 📋  [API](https://quest-kit.github.io/QuEST/group__api.html) for the documentation of each function. 27 | 28 | Interested in contributing? Then check out: 29 | 30 | - ❤️  [`contributing.md`](contributing.md) to learn how to make a pull request. 31 | - 🏗️  [`architecture.md`](architecture.md) to understand the code structure. 32 | - 🎨  [`styleguide.md`](styleguide.md) for some tips on writing neat code. 33 | 34 | Want to learn how what's under the hood? Read the 35 | - 🏆  [whitepaper](https://www.nature.com/articles/s41598-019-47174-9) which featured in Scientific Report's [Top 100 in Physics](https://www.nature.com/collections/ecehgdfcba/) 36 | - 📝  [preprint](https://arxiv.org/abs/2311.01512) which derives `v4`'s optimised algorithms. 37 | - 🧪  [tests](/tests) which compare QuEST's outputs to non-optimised calculations. 38 | - 📰  [news](news.md) which summarises QuEST's history and accolades. 39 | - 📈  [benchmarks](https://www.youtube.com/watch?v=dQw4w9WgXcQ) which are coming soon! 40 | 41 | 42 | If QuEST is useful to you, feel free to cite 43 | ``` 44 | @article{jones2019quest, 45 | title={QuEST and high performance simulation of quantum computers}, 46 | author={Jones, Tyson and Brown, Anna and Bush, Ian and Benjamin, Simon C}, 47 | journal={Scientific reports}, 48 | volume={9}, 49 | number={1}, 50 | pages={10736}, 51 | year={2019}, 52 | publisher={Nature Publishing Group UK London} 53 | } 54 | ``` -------------------------------------------------------------------------------- /quest/src/core/inliner.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * This file defines INLINE to aggressively force inlining 3 | * of crucial functions (typically bitwise functions which 4 | * get invoked exponentially-many times in hot loops) in a 5 | * compiler agnostic way. Inlined functions may be called 6 | * invoked by OpenMP threads, or CUDA kernels. They never 7 | * cause symbol duplication when multiply-imported. 8 | * 9 | * @author Tyson Jones 10 | * @author Oliver Thomson Brown (patched HIP guards) 11 | */ 12 | 13 | #ifndef INLINER_HPP 14 | #define INLINER_HPP 15 | 16 | 17 | 18 | /* 19 | * We must choose the right INLINE keyword for the user's compiler. 20 | * Note the below logic means all INLINE functions through the entire 21 | * QuEST source will declared __device__ when the user opts to compile 22 | * everything with NVCC. It is ergo important that all INLINE functions 23 | * are CUDA-kernel-compatible (e.g. don't make use of std::vector). 24 | */ 25 | 26 | 27 | #if defined(__NVCC__) 28 | 29 | // CUDA compilers define '__forceinline__'. We declare 30 | // all inlined functions as __device__ so they can be 31 | // invoked by CUDA kernels. Note this means that if the 32 | // user opts to use nvcc to compile the entire QuEST 33 | // source, then every INLINE function will be twice- 34 | // compiled; as a host and device function. That's fine, 35 | // though it constrains us to never use non-kernel 36 | // compatible code inside an INLINE function. 37 | #define INLINE __forceinline__ __device__ __host__ 38 | 39 | #elif defined(__HIP__) 40 | 41 | // HIP has the same syntax as GNU below, but we must also 42 | // declare that all INLINE functions can be invoked by kernels 43 | #define INLINE inline __attribute__((always_inline)) __device__ __host__ 44 | 45 | #elif defined(_MSC_VER) || defined(__INTEL_COMPILER) 46 | 47 | // MSVC and Intel compilers define '__forceinline' 48 | #define INLINE __forceinline 49 | 50 | #elif defined(__GNUC__) 51 | #define INLINE inline __attribute__((always_inline)) 52 | 53 | #else 54 | 55 | // #warning command safe in non-MSVC compiler 56 | #warning "Could not ascertain compiler type in order to choose the correct inline attribute. Assuming GNU and proceeding..." 57 | #define INLINE inline __attribute__((always_inline)) 58 | 59 | #endif 60 | 61 | 62 | 63 | #endif // INLINER_HPP -------------------------------------------------------------------------------- /tests/unit/types.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Unit tests of the types module. 3 | * 4 | * @author Tyson Jones 5 | * 6 | * @defgroup unittypes Types 7 | * @ingroup unittests 8 | */ 9 | 10 | #include "quest.h" 11 | 12 | #include 13 | #include 14 | 15 | #include "tests/utils/qvector.hpp" 16 | #include "tests/utils/qmatrix.hpp" 17 | #include "tests/utils/compare.hpp" 18 | #include "tests/utils/convert.hpp" 19 | #include "tests/utils/evolve.hpp" 20 | #include "tests/utils/linalg.hpp" 21 | #include "tests/utils/lists.hpp" 22 | #include "tests/utils/macros.hpp" 23 | #include "tests/utils/random.hpp" 24 | 25 | using Catch::Matchers::ContainsSubstring; 26 | 27 | 28 | 29 | /* 30 | * UTILITIES 31 | */ 32 | 33 | #define TEST_CATEGORY \ 34 | LABEL_UNIT_TAG "[types]" 35 | 36 | 37 | 38 | /** 39 | * TESTS 40 | * 41 | * @ingroup unittypes 42 | * @{ 43 | */ 44 | 45 | 46 | TEST_CASE( "getQcomp", TEST_CATEGORY ) { 47 | 48 | SECTION( LABEL_CORRECTNESS ) { 49 | 50 | qreal re = getRandomReal(-10, 10); 51 | qreal im = getRandomReal(-10, 10); 52 | 53 | qcomp comp = getQcomp(re, im); 54 | REQUIRE( std::real(comp) == re ); 55 | REQUIRE( std::imag(comp) == im ); 56 | } 57 | 58 | SECTION( LABEL_VALIDATION ) { 59 | 60 | // no validation! 61 | SUCCEED( ); 62 | } 63 | } 64 | 65 | 66 | TEST_CASE( "complex arithmetic", TEST_CATEGORY ) { 67 | 68 | SECTION( LABEL_CORRECTNESS ) { 69 | 70 | qcomp x; 71 | x = 1 + 2_i; 72 | x += 3 - 4_i; 73 | x -= - 5 + 6_i; 74 | x *= - 7 - 8_i; 75 | x /= 9 + 10_i; 76 | 77 | qcomp ref = getQcomp(-1303/181., 1126/181.); 78 | REQUIRE_AGREE( x, ref ); 79 | } 80 | 81 | SECTION( LABEL_VALIDATION ) { 82 | 83 | // no validation! 84 | SUCCEED( ); 85 | } 86 | } 87 | 88 | 89 | /** @} (end defgroup) */ 90 | 91 | 92 | 93 | /** 94 | * @todo 95 | * UNTESTED FUNCTIONS 96 | */ 97 | 98 | void reportStr(const char* label); 99 | void reportStr(std::string str); 100 | 101 | void reportScalar(const char* label, qcomp num); 102 | void reportScalar(const char* label, qreal num); 103 | void reportScalar(std::string label, qcomp num); 104 | void reportScalar(std::string label, qreal num); 105 | -------------------------------------------------------------------------------- /tests/utils/random.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilsrandom Random 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities which generate random objects 8 | * independently of QuEST's internal generators. 9 | * @{ 10 | */ 11 | 12 | #ifndef RANDOM_HPP 13 | #define RANDOM_HPP 14 | 15 | #include "qvector.hpp" 16 | #include "qmatrix.hpp" 17 | #include "macros.hpp" 18 | #include "linalg.hpp" 19 | #include "lists.hpp" 20 | #include "quest.h" 21 | 22 | #include 23 | using std::vector; 24 | 25 | #include 26 | using std::tuple; 27 | 28 | 29 | void setRandomTestStateSeeds(); 30 | 31 | int getRandomInt(int min, int maxExcl); 32 | qreal getRandomReal(qreal min, qreal maxExcl); 33 | qreal getRandomPhase(); 34 | qcomp getRandomComplex(); 35 | qcomp getRandomUnitComplex(); 36 | 37 | listpair getRandomFixedNumCtrlsTargs(int numQubits, int numCtrls, int numTargs); 38 | listtrio getRandomVariNumCtrlsStatesTargs(int numQubits, int minNumTargs, int maxNumTargsIncl); 39 | 40 | qvector getRandomVector(size_t dim); 41 | qmatrix getRandomMatrix(size_t dim); 42 | qmatrix getRandomDiagonalMatrix(size_t dim); 43 | qmatrix getRandomNonSquareMatrix(size_t numRows, size_t numCols); 44 | 45 | qvector getRandomStateVector(int numQb); 46 | qmatrix getRandomDensityMatrix(int numQb); 47 | qmatrix getRandomPureDensityMatrix(int numQb); 48 | 49 | void setToRandomState(qvector& state); 50 | void setToRandomState(qmatrix& state); 51 | 52 | qmatrix getRandomUnitary(int numQb); 53 | qmatrix getRandomDiagonalUnitary(int numQb); 54 | qmatrix getRandomDiagonalHermitian(int numQb); 55 | vector getRandomKrausMap(int numQb, int numOps); 56 | 57 | PauliStr getRandomPauliStr(int numQubits); 58 | PauliStr getRandomPauliStr(vector targs); 59 | PauliStr getRandomDiagPauliStr(int numQubits); 60 | 61 | vector getRandomInts(int min, int maxExcl, int len); 62 | vector getRandomOutcomes(int len); 63 | vector getRandomSubRange(int start, int endExcl, int numElems); 64 | vector getRandomProbabilities(int numProbs); 65 | 66 | vector getRandomOrthonormalVectors(size_t dim, int numVecs); 67 | vector getRandomOrthonormalStateVectors(int numQb, int numStates); 68 | 69 | PauliStrSum createRandomPauliStrSum(int numQubits, int numTerms); 70 | PauliStrSum createRandomNonHermitianPauliStrSum(int numQubits, int numTerms); 71 | 72 | 73 | #endif // RANDOM_HPP 74 | 75 | /** @} (end defgroup) */ 76 | -------------------------------------------------------------------------------- /examples/isolated/reporting_matrices.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of using matrix reporters, specifically 3 | * reportCompMatr, reportDiagMatr, reportFullStateDiagMatr, 4 | * in C++14. We exclude reporting of fixed-size matrices (e.g. 5 | * CompMatr1) which is almost exactly the same as shown here. 6 | * This example is most interested when run distributed over 7 | * up to 64 nodes, spoofed using mpirun --oversubscribe. 8 | * 9 | * @author Tyson Jones 10 | */ 11 | 12 | #include "quest.h" 13 | #include 14 | 15 | 16 | 17 | void rootPrint(qindex num) { 18 | 19 | if (getQuESTEnv().rank != 0) 20 | return; 21 | 22 | std::cout << "\n\n>> set number of reported items to " << num; 23 | 24 | if (num == 0) 25 | std::cout << " (which means report all)"; 26 | 27 | std::cout << "\n" << std::endl; // flush 28 | } 29 | 30 | 31 | 32 | void demo_CompMatr() { 33 | 34 | CompMatr matr = createCompMatr(4); 35 | for (qindex r=0; r 21 | using std::vector; 22 | 23 | int getNumPermutations(int n, int k); 24 | int getLog2(qindex); 25 | int getBitAt(qindex num, int ind); 26 | vector getBits(qindex num, int numBits); 27 | qindex getBitsAt(qindex num, vector inds); 28 | qindex setBitAt(qindex num, int ind, int bit); 29 | qindex setBitsAt(qindex num, vector inds, qindex bits); 30 | qindex getPow2(int); 31 | 32 | qreal getSum(vector vec); 33 | qcomp getSum(qvector); 34 | qvector getNormalised(qvector); 35 | qvector getDisceteFourierTransform(qvector); 36 | qvector getDisceteFourierTransform(qvector in, vector targs); 37 | 38 | qcomp getInnerProduct(qvector bra, qvector ket); 39 | qmatrix getOuterProduct(qvector ket, qvector bra); 40 | 41 | qvector operator * (const qmatrix&, const qvector&); 42 | 43 | bool isDiagonal(qmatrix); 44 | bool isApproxUnitary(qmatrix); 45 | 46 | qcomp getTrace(qmatrix); 47 | qmatrix getTranspose(qmatrix); 48 | qmatrix getConjugate(qmatrix); 49 | qmatrix getConjugateTranspose(qmatrix); 50 | qmatrix getPowerOfDiagonalMatrix(qmatrix diag, qcomp power); 51 | qmatrix getExponentialOfDiagonalMatrix(qmatrix); 52 | qmatrix getExponentialOfPauliMatrix(qcomp arg, qmatrix pauli); 53 | qmatrix getExponentialOfNormalisedPauliVector(qreal arg, qreal x, qreal y, qreal z); 54 | qmatrix getOrthonormalisedRows(qmatrix); 55 | qmatrix getOrthonormalisedRows(qmatrix); 56 | qmatrix getKroneckerProduct(qmatrix, qmatrix); 57 | qmatrix getKroneckerProduct(qmatrix, int count); 58 | qmatrix getKroneckerProduct(vector); 59 | qmatrix getProjector(int outcome); 60 | qmatrix getProjector(vector targets, vector outcomes, int numQubits); 61 | qmatrix getPartialTrace(qmatrix matrix, vector targets); 62 | qmatrix getControlledMatrix(qmatrix matrix, int numCtrls); 63 | qmatrix getMixture(vector statevecs, vector probs); 64 | qmatrix getMixture(vector densmatrs, vector probs); 65 | qmatrix getSuperOperator(vector); 66 | 67 | bool isApproxCPTP(vector); 68 | 69 | 70 | #endif // LINALG_HPP 71 | 72 | /** @} (end defgroup) */ 73 | -------------------------------------------------------------------------------- /docs/styleguide.md: -------------------------------------------------------------------------------- 1 | # 🎨  Style guide 2 | 3 | 9 | 10 | 11 | 12 | Don't agonise about style - write your code as you see fit and we can address major issues in review/PR. 13 | Some encouraged conventions include: 14 | 15 | - use `camelCase` for everything except: 16 | - constants which use `CAPITALS_AND_UNDERSCORES` 17 | - related function prefixes, like `prefix_someFunction()` 18 | - favour clarity over concision, for example 19 | ```cpp 20 | qcomp elem = state[ind][ind]; 21 | qreal prob = std::real(elem); 22 | return prob; 23 | ``` 24 | over 25 | ```cpp 26 | return std::real(state[ind][ind]); 27 | ``` 28 | - never ever do: 29 | ```cpp 30 | using namespace std; 31 | ``` 32 | but _do_ shorten common containers like `vector`: 33 | ```cpp 34 | using std::vector; 35 | 36 | vector mylist; 37 | ``` 38 | - whitespace is free; use it wherever it can improve clarity, like to separate subroutines. 39 | ```cpp 40 | // i000 = nth local index where all suffix bits are 0 41 | qindex i000 = insertThreeZeroBits(n, braQb1, ketQb2, ketQb1); 42 | qindex i0b0 = setBit(i000, ketQb2, braBit2); 43 | qindex i1b1 = flipTwoBits(i0b0, braQb1, ketQb1); 44 | 45 | // j = nth received amp in buffer 46 | qindex j = n + offset; 47 | 48 | // mix pair of amps using buffer 49 | qcomp amp0b0 = qureg.cpuAmps[i0b0]; 50 | qcomp amp1b1 = qureg.cpuAmps[i1b1]; 51 | 52 | qureg.cpuAmps[i0b0] = c1*amp0b0 + c2*(amp1b1 + qureg.cpuCommBuffer[j]); 53 | qureg.cpuAmps[i1b1] = c1*amp1b1 + c2*(amp0b0 + qureg.cpuCommBuffer[j]); 54 | ``` 55 | - use `auto` where it improves readability, discretionarily. Obviously it is better than massive, unimportant types of objects or heavily templated collections, but sometimes knowing the precise type of a primitive is helpful 56 | - It is permissable to avoid superfluous braces around single-line branches: 57 | ```cpp 58 | if (cond) 59 | return x; 60 | ``` 61 | - always prefix calls to mathematical functions like `abs()` with the `std` namespace, i.e. `std::abs()`. This avoids ambiguity with `C` overloads like `abs(int)` which can cause insidious bugs! The full list of functions to prefix are: 62 | - `abs` 63 | - `real` 64 | - `imag` 65 | - `conj` 66 | - `norm` 67 | - `sin` 68 | - `cos` 69 | - `log` 70 | - `log2` 71 | - `exp` 72 | - `pow` 73 | - `sqrt` 74 | - `floor` 75 | - `ceil` 76 | - `atan2` 77 | - `min` 78 | - `max` 79 | -------------------------------------------------------------------------------- /utils/docs/layout/doxygen-awesome-quest.css: -------------------------------------------------------------------------------- 1 | /* 2 | * custom CSS, overriding Doxygen Awesome's 3 | * default styling for the QuEST project. 4 | * @author Tyson Jones 5 | */ 6 | 7 | 8 | html { 9 | 10 | /* light-mode highlighted section text color */ 11 | --primary-color: #d85b0a; 12 | 13 | /* light-mode colour of the left navbar... */ 14 | --side-nav-background: #fffdf1; 15 | 16 | /* navbar width, which must match TREE_WIDTH in Doxyfile */ 17 | --side-nav-fixed-width: 330px; 18 | 19 | /* this defers the placement of the search bar, 20 | * and must be large enough to fit the logo and 21 | * the injected version number beneath it */ 22 | --top-height: 260px; 23 | } 24 | 25 | 26 | /* dark-mode highlighted section text color */ 27 | html.dark-mode { 28 | color-scheme: dark; 29 | --primary-color: #ffaf36; 30 | } 31 | 32 | @media (prefers-color-scheme: dark) { 33 | html:not(.light-mode) { 34 | --primary-color: #ffaf36; 35 | } 36 | } 37 | 38 | 39 | /* set size and padding of logo atop navbar */ 40 | #projectlogo img { 41 | width: 180px; 42 | height: 158px; 43 | max-height: none !important; 44 | padding-top: 12px; 45 | } 46 | 47 | 48 | /* center the QuEST logo atop the navbar */ 49 | #titlearea table { 50 | width: 100%; 51 | } 52 | 53 | /* hide text atop navbar (so only logo remains) */ 54 | #projectalign { 55 | display: none; 56 | } 57 | 58 | 59 | /* hide the strange lil button at bottom of navbar 60 | * (I have no idea what it does hehe) */ 61 | #nav-sync { 62 | display: none; 63 | } 64 | 65 | 66 | /* remove big empty space at page tops */ 67 | @media screen and (min-width: 767px) { 68 | #doc-content { 69 | padding-top: calc(var(--top-height) - 247px); 70 | } 71 | } 72 | 73 | 74 | /* undoing doxygen-awesome's re-colouring of warning ( 75 | * which made it an innocuous yellow, like attention), 76 | * restoring its scarier red colouring! */ 77 | dl.warning { 78 | background: #f8d1cc; 79 | border-left: 8px solid #b61825; 80 | color: #75070f 81 | } 82 | 83 | dl.warning dt { 84 | color: #75070f; 85 | } 86 | 87 | 88 | /* set the version number (below logo on navbar) style */ 89 | @font-face { 90 | font-family: "Computer Modern"; 91 | src: url('http://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunsx.otf'); 92 | font-weight: bold; 93 | } 94 | 95 | #projectversion { 96 | color: #d85b0a; 97 | font-weight: bold; 98 | font-family: "Computer Modern Serif", serif; 99 | text-align: center; 100 | } 101 | -------------------------------------------------------------------------------- /examples/isolated/reporting_paulis.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of using reportPauliStr and 3 | * reportPauliStrSum in C11. 4 | * 5 | * @author Tyson Jones 6 | */ 7 | 8 | #include "quest.h" 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | 15 | /* 16 | * distributed printing 17 | */ 18 | 19 | 20 | void rootPrint(qindex num) { 21 | 22 | if (getQuESTEnv().rank != 0) 23 | return; 24 | 25 | printf("\n\n>> set number of reported items to %lld", num); 26 | 27 | if (num == 0) 28 | printf(" (which means report all)"); 29 | 30 | printf("\n\n"); 31 | } 32 | 33 | 34 | 35 | /* 36 | * PauliStr 37 | */ 38 | 39 | 40 | void demo_PauliStr() { 41 | 42 | // leftmost identities are not printed 43 | reportPauliStr( 44 | getInlinePauliStr("XYZ", {2,1,0}) 45 | ); 46 | reportPauliStr( 47 | getInlinePauliStr("XYZ", {63,62,61}) 48 | ); 49 | } 50 | 51 | 52 | 53 | /* 54 | * PauliStrSum 55 | */ 56 | 57 | 58 | PauliStrSum prepareRandomPauliStrSum(int numQubits, int numTerms) { 59 | 60 | char paulis[64]; 61 | int qubits[64]; 62 | for (int i=0; i 16 | #include 17 | #include 18 | 19 | using std::vector; 20 | 21 | 22 | /* 23 | * CONSTANTS 24 | */ 25 | 26 | static const int MAX_NUM_PAULIS_PER_MASK = sizeof(PAULI_MASK_TYPE) * 8 / 2; 27 | static const int MAX_NUM_PAULIS_PER_STR = MAX_NUM_PAULIS_PER_MASK * 2; 28 | 29 | 30 | /* 31 | * PauliStr 32 | */ 33 | 34 | bool paulis_isIdentity(PauliStr str); 35 | 36 | bool paulis_containsXOrY(PauliStr str); 37 | 38 | int paulis_getPauliAt(PauliStr str, int ind); 39 | 40 | int paulis_getIndOfLefmostNonIdentityPauli(PauliStr str); 41 | int paulis_getIndOfLefmostNonIdentityPauli(PauliStr* strings, qindex numStrings); 42 | 43 | int paulis_getSignOfPauliStrConj(PauliStr str); 44 | 45 | int paulis_getPrefixZSign(Qureg qureg, vector prefixZ); 46 | 47 | qcomp paulis_getPrefixPaulisElem(Qureg qureg, vector prefixY, vector prefixZ); 48 | 49 | vector paulis_getTargetInds(PauliStr str); 50 | 51 | std::array,3> paulis_getSeparateInds(PauliStr str); 52 | 53 | qindex paulis_getTargetBitMask(PauliStr str); 54 | 55 | PauliStr paulis_getShiftedPauliStr(PauliStr str, int pauliShift); 56 | 57 | PauliStr paulis_getKetAndBraPauliStr(PauliStr str, Qureg qureg); 58 | 59 | PAULI_MASK_TYPE paulis_getKeyOfSameMixedAmpsGroup(PauliStr str); 60 | 61 | 62 | // below are not currently used outside of paulilogic.cpp but are natural methods 63 | 64 | PauliStr paulis_getTensorProdOfPauliStr(PauliStr left, PauliStr right, int numQubits); 65 | 66 | std::pair paulis_getPauliStrProd(PauliStr strA, PauliStr strB); 67 | 68 | 69 | /* 70 | * PauliStrSum 71 | */ 72 | 73 | bool paulis_containsXOrY(PauliStrSum sum); 74 | 75 | int paulis_getIndOfLefmostNonIdentityPauli(PauliStrSum sum); 76 | 77 | qindex paulis_getTargetBitMask(PauliStrSum sum); 78 | 79 | 80 | // below are used exclusively by Trotterisation 81 | 82 | qindex paulis_getNumTermsInPauliStrSumProdOfAdjointWithSelf(PauliStrSum in); 83 | 84 | void paulis_setPauliStrSumToScaledTensorProdOfConjWithSelf(PauliStrSum out, qreal factor, PauliStrSum in, int numQubits); 85 | 86 | void paulis_setPauliStrSumToScaledProdOfAdjointWithSelf(PauliStrSum out, qreal factor, PauliStrSum in); 87 | 88 | void paulis_setPauliStrSumToShiftedConj(PauliStrSum out, PauliStrSum in, int numQubits); 89 | 90 | 91 | #endif // PAULILOGIC_HPP -------------------------------------------------------------------------------- /tests/utils/evolve.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @author Tyson Jones 3 | * 4 | * @defgroup testutilsevolve Evolve 5 | * @ingroup testutils 6 | * @brief 7 | * Testing utilities which evolve a reference state 8 | * (qvector or qmatrix) under the action of a 9 | * reference operation. These are slow, serial, 10 | * un-optimised, defensively-designed routines. 11 | * @{ 12 | */ 13 | 14 | #ifndef EVOLVE_HPP 15 | #define EVOLVE_HPP 16 | 17 | #include "qvector.hpp" 18 | #include "qmatrix.hpp" 19 | 20 | #include 21 | using std::vector; 22 | 23 | 24 | void applyReferenceOperator (qvector& state, vector ctrls, vector states, vector targs, qmatrix matrix); 25 | void applyReferenceOperator (qmatrix& state, vector ctrls, vector states, vector targs, qmatrix matrix); 26 | void leftapplyReferenceOperator (qvector& state, vector ctrls, vector states, vector targs, qmatrix matrix); 27 | void leftapplyReferenceOperator (qmatrix& state, vector ctrls, vector states, vector targs, qmatrix matrix); 28 | void rightapplyReferenceOperator(qmatrix& state, vector ctrls, vector states, vector targs, qmatrix matrix); 29 | 30 | void applyReferenceOperator (qvector& state, vector ctrls, vector targs, qmatrix matrix); 31 | void applyReferenceOperator (qmatrix& state, vector ctrls, vector targs, qmatrix matrix); 32 | void leftapplyReferenceOperator (qvector& state, vector ctrls, vector targs, qmatrix matrix); 33 | void leftapplyReferenceOperator (qmatrix& state, vector ctrls, vector targs, qmatrix matrix); 34 | void rightapplyReferenceOperator(qmatrix& state, vector ctrls, vector targs, qmatrix matrix); 35 | 36 | void applyReferenceOperator (qvector& state, vector targs, qmatrix matrix); 37 | void applyReferenceOperator (qmatrix& state, vector targs, qmatrix matrix); 38 | void leftapplyReferenceOperator (qvector& state, vector targs, qmatrix matrix); 39 | void leftapplyReferenceOperator (qmatrix& state, vector targs, qmatrix matrix); 40 | void rightapplyReferenceOperator(qmatrix& state, vector targs, qmatrix matrix); 41 | 42 | void applyReferenceOperator (qvector& state, qmatrix matrix); 43 | void applyReferenceOperator (qmatrix& state, qmatrix matrix); 44 | void leftapplyReferenceOperator (qvector& state, qmatrix matrix); 45 | void leftapplyReferenceOperator (qmatrix& state, qmatrix matrix); 46 | void rightapplyReferenceOperator(qmatrix& state, qmatrix matrix); 47 | 48 | void applyReferenceOperator(qmatrix& state, vector targs, vector matrices); 49 | 50 | 51 | #endif // EVOLVE_HPP 52 | 53 | /** @} (end defgroup) */ 54 | -------------------------------------------------------------------------------- /examples/isolated/complex_arithmetic.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of using QuEST's precision-agnostic 3 | * overloaded arithmetic operators between qcomp 4 | * and other types like ints and floats, in C11. 5 | * MSVC does not support C complex arithmetic. 6 | * 7 | * @author Tyson Jones 8 | */ 9 | 10 | #include "quest.h" 11 | 12 | 13 | int main() { 14 | 15 | initQuESTEnv(); 16 | 17 | #if !defined(_MSC_VER) 18 | 19 | qcomp x = 1.2 + 3.4i; 20 | 21 | // C + R 22 | x = x + (int) 3; 23 | x = x + (qindex) 3; 24 | x = x + (float) 2; 25 | x = x + (double) 2; 26 | x = x + (long double) 2; 27 | 28 | // R + C 29 | x = (int) 3 + x; 30 | x = (qindex) 3 + x; 31 | x = (float) 2 + x; 32 | x = (double) 2 + x; 33 | x = (long double) 2 + x; 34 | 35 | // C - R 36 | x = x - (int) 3; 37 | x = x - (qindex) 3; 38 | x = x - (float) 2; 39 | x = x - (double) 2; 40 | x = x - (long double) 2; 41 | 42 | // R - C 43 | x = (int) 3 - x; 44 | x = (qindex) 3 - x; 45 | x = (float) 2 - x; 46 | x = (double) 2 - x; 47 | x = (long double) 2 - x; 48 | 49 | // C * R 50 | x = x * (int) 3; 51 | x = x * (qindex) 3; 52 | x = x * (float) 2; 53 | x = x * (double) 2; 54 | x = x * (long double) 2; 55 | 56 | // R * C 57 | x = (int) 3 * x; 58 | x = (qindex) 3 * x; 59 | x = (float) 2 * x; 60 | x = (double) 2 * x; 61 | x = (long double) 2 * x; 62 | 63 | // C / R 64 | x = x / (int) 3; 65 | x = x / (qindex) 3; 66 | x = x / (float) 2; 67 | x = x / (double) 2; 68 | x = x / (long double) 2; 69 | 70 | // R / C 71 | x = (int) 3 / x; 72 | x = (qindex) 3 / x; 73 | x = (float) 2 / x; 74 | x = (double) 2 / x; 75 | x = (long double) 2 / x; 76 | 77 | // C += R 78 | x += (int) 3; 79 | x += (qindex) 3; 80 | x += (float) 2; 81 | x += (double) 2; 82 | x += (long double) 2; 83 | 84 | // C -= R 85 | x -= (int) 3; 86 | x -= (qindex) 3; 87 | x -= (float) 2; 88 | x -= (double) 2; 89 | x -= (long double) 2; 90 | 91 | // C *= R 92 | x *= (int) 3; 93 | x *= (qindex) 3; 94 | x *= (float) 2; 95 | x *= (double) 2; 96 | x *= (long double) 2; 97 | 98 | // C /= R 99 | x /= (int) 3; 100 | x /= (qindex) 3; 101 | x /= (float) 2; 102 | x /= (double) 2; 103 | x /= (long double) 2; 104 | 105 | reportScalar("x", x); 106 | #endif 107 | 108 | finalizeQuESTEnv(); 109 | return 0; 110 | } -------------------------------------------------------------------------------- /examples/isolated/reporting_paulis.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of using reportPauliStr and 3 | * reportPauliStrSum in C++14. 4 | * 5 | * @author Tyson Jones 6 | */ 7 | 8 | #include "quest.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using std::cout; 15 | using std::endl; 16 | using std::string; 17 | using std::vector; 18 | 19 | 20 | 21 | /* 22 | * distributed printing 23 | */ 24 | 25 | 26 | void rootPrint(qindex num) { 27 | 28 | if (getQuESTEnv().rank != 0) 29 | return; 30 | 31 | cout << endl << endl << ">> set number of reported items to " << num; 32 | 33 | if (num == 0) 34 | cout << " (which means report all)"; 35 | 36 | cout << endl << endl; 37 | } 38 | 39 | 40 | 41 | /* 42 | * PauliStr 43 | */ 44 | 45 | 46 | void demo_PauliStr() { 47 | 48 | // leftmost identities are not printed 49 | reportPauliStr( 50 | getPauliStr("XYZ", {2,1,0}) 51 | ); 52 | reportPauliStr( 53 | getPauliStr("XYZ", {63,62,61}) 54 | ); 55 | } 56 | 57 | 58 | 59 | /* 60 | * PauliStrSum 61 | */ 62 | 63 | 64 | PauliStrSum prepareRandomPauliStrSum(int numQubits, int numTerms) { 65 | 66 | vector paulis(numQubits); 67 | vector qubits(numQubits); 68 | for (int i=0; i coeffs(numTerms); 72 | vector strings(numTerms); 73 | qreal randMax = static_cast(RAND_MAX); 74 | 75 | for (int i=0; i numReportElems {0, 10, 2}; 98 | 99 | for (int num : numReportElems) { 100 | rootPrint(num); 101 | 102 | setMaxNumReportedItems(num, num); 103 | reportPauliStrSum(sum); 104 | } 105 | 106 | destroyPauliStrSum(sum); 107 | } 108 | 109 | 110 | 111 | /* 112 | * main 113 | */ 114 | 115 | 116 | int main() { 117 | 118 | initQuESTEnv(); 119 | 120 | // seed our RNG (not QuEST's) 121 | srand(time(NULL)); 122 | 123 | demo_PauliStr(); 124 | demo_PauliStrSum(); 125 | 126 | finalizeQuESTEnv(); 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /examples/isolated/complex_arithmetic.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of using QuEST's precision-agnostic 3 | * overloaded arithmetic operators between qcomp 4 | * and other types like ints and floats, in C++14 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | #include "quest.h" 10 | 11 | 12 | int main() { 13 | 14 | initQuESTEnv(); 15 | 16 | // use 1_i instead of 1i to make the complex literal precision agnostic 17 | qcomp x = 1.2 + 3.4_i; 18 | 19 | // C with non-same-prec C (does not change x to keep consistency with arithemtic.c) 20 | qcomp y = 1.5i - 2i - x + 3.5*x / 10.5_i; 21 | 22 | // C + R 23 | x = x + (int) 3; 24 | x = x + (qindex) 3; 25 | x = x + (float) 2; 26 | x = x + (double) 2; 27 | x = x + (long double) 2; 28 | 29 | // R + C 30 | x = (int) 3 + x; 31 | x = (qindex) 3 + x; 32 | x = (float) 2 + x; 33 | x = (double) 2 + x; 34 | x = (long double) 2 + x; 35 | 36 | // C - R 37 | x = x - (int) 3; 38 | x = x - (qindex) 3; 39 | x = x - (float) 2; 40 | x = x - (double) 2; 41 | x = x - (long double) 2; 42 | 43 | // R - C 44 | x = (int) 3 - x; 45 | x = (qindex) 3 - x; 46 | x = (float) 2 - x; 47 | x = (double) 2 - x; 48 | x = (long double) 2 - x; 49 | 50 | // C * R 51 | x = x * (int) 3; 52 | x = x * (qindex) 3; 53 | x = x * (float) 2; 54 | x = x * (double) 2; 55 | x = x * (long double) 2; 56 | 57 | // R * C 58 | x = (int) 3 * x; 59 | x = (qindex) 3 * x; 60 | x = (float) 2 * x; 61 | x = (double) 2 * x; 62 | x = (long double) 2 * x; 63 | 64 | // C / R 65 | x = x / (int) 3; 66 | x = x / (qindex) 3; 67 | x = x / (float) 2; 68 | x = x / (double) 2; 69 | x = x / (long double) 2; 70 | 71 | // R / C 72 | x = (int) 3 / x; 73 | x = (qindex) 3 / x; 74 | x = (float) 2 / x; 75 | x = (double) 2 / x; 76 | x = (long double) 2 / x; 77 | 78 | // C += R 79 | x += (int) 3; 80 | x += (qindex) 3; 81 | x += (float) 2; 82 | x += (double) 2; 83 | x += (long double) 2; 84 | 85 | // C -= R 86 | x -= (int) 3; 87 | x -= (qindex) 3; 88 | x -= (float) 2; 89 | x -= (double) 2; 90 | x -= (long double) 2; 91 | 92 | // C *= R 93 | x *= (int) 3; 94 | x *= (qindex) 3; 95 | x *= (float) 2; 96 | x *= (double) 2; 97 | x *= (long double) 2; 98 | 99 | // C /= R 100 | x /= (int) 3; 101 | x /= (qindex) 3; 102 | x /= (float) 2; 103 | x /= (double) 2; 104 | x /= (long double) 2; 105 | 106 | reportScalar("x", x); 107 | 108 | finalizeQuESTEnv(); 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /tests/utils/qvector.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Testing utilities which define 'qvector', used 3 | * as a reference proxy to a quantum statevector. 4 | * 5 | * @author Tyson Jones 6 | */ 7 | 8 | #include "qvector.hpp" 9 | #include "macros.hpp" 10 | 11 | 12 | /* 13 | * VECTOR CREATION 14 | */ 15 | 16 | qvector getZeroVector(size_t dim) { 17 | // permit dim = 0 18 | 19 | return qvector(dim, 0); 20 | } 21 | 22 | qvector getConstantVector(size_t dim, qcomp elem) { 23 | DEMAND( dim >= 1 ); 24 | 25 | return qvector(dim, elem); 26 | } 27 | 28 | 29 | /* 30 | * SCALAR MULTIPLICATION 31 | */ 32 | 33 | qvector operator * (const qcomp& a, const qvector& v) { 34 | qvector out = v; 35 | 36 | for (auto& x : out) 37 | x *= a; 38 | 39 | return out; 40 | } 41 | 42 | qvector operator * (const qvector& v, const qcomp& a) { 43 | return a * v; 44 | } 45 | 46 | qvector operator *= (qvector& v, const qcomp& a) { 47 | v = a * v; 48 | return v; 49 | } 50 | 51 | qvector operator * (const qreal& a, const qvector& v) { 52 | return qcomp(a,0) * v; 53 | } 54 | 55 | qvector operator * (const qvector& v, const qreal& a) { 56 | return a * v; 57 | } 58 | 59 | qvector operator *= (qvector& v, const qreal& a) { 60 | v = a * v; 61 | return v; 62 | } 63 | 64 | 65 | /* 66 | * SCALAR DIVISION 67 | */ 68 | 69 | qvector operator / (const qvector& v, const qcomp& a) { 70 | DEMAND( std::abs(a) != 0 ); 71 | 72 | return (1/a) * v; 73 | } 74 | 75 | qvector operator /= (qvector& v, const qcomp& a) { 76 | v = v / a; 77 | return v; 78 | } 79 | 80 | qvector operator / (const qvector& v, const qreal& a) { 81 | return v / qcomp(a,0); 82 | } 83 | 84 | qvector operator /= (qvector& v, const qreal& a) { 85 | v = v / a; 86 | return v; 87 | } 88 | 89 | 90 | /* 91 | * VECTOR ADDITION 92 | */ 93 | 94 | qvector operator + (const qvector& v1, const qvector& v2) { 95 | DEMAND( v1.size() == v2.size() ); 96 | 97 | qvector out = v1; 98 | 99 | for (size_t i=0; i 30 | ${{ matrix.os == 'ubuntu-latest' && 'Linux' || matrix.os == 'macos-latest' && 'MacOS' || 'Windows' }} 31 | [${{ matrix.precision }}] 32 | serial 33 | unit v${{ matrix.version }} 34 | 35 | runs-on: ${{ matrix.os }} 36 | 37 | strategy: 38 | # continue other jobs if any fail 39 | fail-fast: false 40 | 41 | # we will compile QuEST with all precisions but no parallelisation 42 | matrix: 43 | os: [ubuntu-latest, macos-latest, windows-latest] 44 | version: [3, 4] 45 | precision: [1, 2, 4] 46 | 47 | # MSVC cannot compile deprecated v3 tests 48 | exclude: 49 | - os: windows-latest 50 | version: 3 51 | 52 | # constants 53 | env: 54 | build_dir: "build" 55 | depr_dir: "build/tests/deprecated" 56 | 57 | # perform the job 58 | steps: 59 | - name: Get QuEST 60 | uses: actions/checkout@main 61 | 62 | # compile serial unit tests, optionally include deprecated test 63 | - name: Configure CMake 64 | run: > 65 | cmake -B ${{ env.build_dir }} 66 | -DENABLE_TESTING=ON 67 | -DENABLE_MULTITHREADING=OFF 68 | -DENABLE_DEPRECATED_API=${{ matrix.version == 3 && 'ON' || 'OFF' }} 69 | -DDISABLE_DEPRECATION_WARNINGS=${{ matrix.version == 3 && 'ON' || 'OFF' }} 70 | -DFLOAT_PRECISION=${{ matrix.precision }} 71 | 72 | # force 'Release' build (needed by MSVC to enable optimisations) 73 | - name: Compile 74 | run: cmake --build ${{ env.build_dir }} --config Release --parallel 75 | 76 | # run v4 unit tests in random order, excluding the integration tests, 77 | # using the default environment variables (e.g. test all permutations) 78 | # TODO: 79 | # ctest currently doesn't know of our Catch2 tags, so we 80 | # are manually excluding each integration test by name 81 | - name: Run v4 tests 82 | if: ${{ matrix.version == 4 }} 83 | run: ctest -j2 --output-on-failure --schedule-random -E "density evolution" 84 | working-directory: ${{ env.build_dir }} 85 | 86 | # run v3 unit tests in random order 87 | - name: Run v3 tests 88 | if: ${{ matrix.version == 3 }} 89 | run: ctest -j2 --output-on-failure --schedule-random 90 | working-directory: ${{ env.depr_dir }} 91 | -------------------------------------------------------------------------------- /quest/src/gpu/gpu_config.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Utility signatures for querying GPU hardware, 3 | * and allocating and copying GPU VRAM data. 4 | * 5 | * Note that this header is included by /core/ and 6 | * parsed by non-CUDA compilers, so must never contain 7 | * any CUDA-specific signatures 8 | * 9 | * @author Tyson Jones 10 | */ 11 | 12 | #ifndef GPU_CONFIG_HPP 13 | #define GPU_CONFIG_HPP 14 | 15 | #include "quest/include/config.h" 16 | #include "quest/include/types.h" 17 | #include "quest/include/qureg.h" 18 | #include "quest/include/matrices.h" 19 | #include "quest/include/channels.h" 20 | 21 | 22 | 23 | /* 24 | * CUDA ERROR HANDLING 25 | */ 26 | 27 | #if COMPILE_CUDA 28 | 29 | #define CUDA_CHECK(cmd) \ 30 | assertCudaCallSucceeded((int) (cmd), #cmd, __func__, __FILE__, __LINE__) 31 | 32 | void assertCudaCallSucceeded(int code, const char* call, const char* caller, const char* file, int line); 33 | 34 | #endif 35 | 36 | 37 | 38 | /* 39 | * HARDWARE AVAILABILITY 40 | */ 41 | 42 | bool gpu_isGpuCompiled(); 43 | 44 | bool gpu_isCuQuantumCompiled(); 45 | 46 | bool gpu_isGpuAvailable(); 47 | 48 | bool gpu_isDirectGpuCommPossible(); 49 | 50 | int gpu_getNumberOfLocalGpus(); 51 | 52 | int gpu_getComputeCapability(); 53 | 54 | size_t gpu_getCurrentAvailableMemoryInBytes(); 55 | 56 | size_t gpu_getTotalMemoryInBytes(); 57 | 58 | bool gpu_doesGpuSupportMemPools(); 59 | 60 | qindex gpu_getMaxNumConcurrentThreads(); 61 | 62 | 63 | 64 | /* 65 | * ENVIRONMENT MANAGEMENT 66 | */ 67 | 68 | void gpu_bindLocalGPUsToNodes(); 69 | 70 | bool gpu_areAnyNodesBoundToSameGpu(); 71 | 72 | void gpu_sync(); 73 | 74 | void gpu_initCuQuantum(); 75 | 76 | void gpu_finalizeCuQuantum(); 77 | 78 | 79 | 80 | /* 81 | * MEMORY MANAGEMENT 82 | */ 83 | 84 | qcomp* gpu_allocArray(qindex numLocalAmps); 85 | void gpu_deallocArray(qcomp* amps); 86 | 87 | void gpu_copyArray(qcomp* dest, qcomp* src, qindex dim); 88 | 89 | void gpu_copyCpuToGpu(qcomp* cpuArr, qcomp* gpuArr, qindex numElems); 90 | void gpu_copyGpuToCpu(qcomp* gpuArr, qcomp* cpuArr, qindex numElems); 91 | 92 | void gpu_copyGpuToCpu(Qureg qureg, qcomp* gpuArr, qcomp* cpuArr, qindex numElems); 93 | void gpu_copyGpuToCpu(Qureg qureg); 94 | 95 | void gpu_copyCpuToGpu(Qureg qureg, qcomp* cpuArr, qcomp* gpuArr, qindex numElems); 96 | void gpu_copyCpuToGpu(Qureg qureg); 97 | 98 | void gpu_copyCpuToGpu(CompMatr matr); 99 | void gpu_copyGpuToCpu(CompMatr matr); 100 | 101 | void gpu_copyCpuToGpu(DiagMatr matr); 102 | void gpu_copyGpuToCpu(DiagMatr matr); 103 | 104 | void gpu_copyCpuToGpu(SuperOp op); 105 | void gpu_copyGpuToCpu(SuperOp op); 106 | 107 | // funnily, there is no need for GPU-to-CPU or FullStateDiagMatr; 108 | // the invoking printer.cpp function uses localiser_fullstatediagamtr_... 109 | // copying to handle the distributed nuisance, which spoofs a Qureg 110 | void gpu_copyCpuToGpu(FullStateDiagMatr matr); 111 | 112 | 113 | /* 114 | * CACHE MANAGEMENT 115 | */ 116 | 117 | qcomp* gpu_getCacheOfSize(qindex numElemsPerThread, qindex numThreads); 118 | 119 | void gpu_clearCache(); 120 | 121 | size_t gpu_getCacheMemoryInBytes(); 122 | 123 | 124 | 125 | #endif // GPU_CONFIG_HPP -------------------------------------------------------------------------------- /quest/src/gpu/cuda_to_hip.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CUDA_TO_HIP_HPP 2 | #define CUDA_TO_HIP_HPP 3 | 4 | #include 5 | #include 6 | 7 | // Set of macros pointing CUDA functions to their analogous HIP function. 8 | 9 | #define WARPSIZE 64 10 | static constexpr int maxWarpsPerBlock = 1024/WARPSIZE; 11 | 12 | #define CUFFT_D2Z HIPFFT_D2Z 13 | #define CUFFT_FORWARD HIPFFT_FORWARD 14 | #define CUFFT_INVERSE HIPFFT_BACKWARD 15 | #define CUFFT_Z2D HIPFFT_Z2D 16 | #define CUFFT_Z2Z HIPFFT_Z2Z 17 | 18 | #define cudaUUID_t hipUUID 19 | #define cudaError hipError_t 20 | #define cudaError_t hipError_t 21 | #define cudaEvent_t hipEvent_t 22 | #define cudaDeviceProp hipDeviceProp_t 23 | 24 | #define cudaDeviceSynchronize hipDeviceSynchronize 25 | #define cudaErrorInsufficientDriver hipErrorInsufficientDriver 26 | #define cudaErrorNoDevice hipErrorNoDevice 27 | #define cudaEventCreate hipEventCreate 28 | #define cudaEventElapsedTime hipEventElapsedTime 29 | #define cudaEventRecord hipEventRecord 30 | #define cudaEventSynchronize hipEventSynchronize 31 | #define cudaFree hipFree 32 | #define cudaFreeHost hipHostFree 33 | #define cudaGetDevice hipGetDevice 34 | #define cudaGetDeviceCount hipGetDeviceCount 35 | #define cudaGetErrorString hipGetErrorString 36 | #define cudaGetLastError hipGetLastError 37 | #define cudaHostAlloc hipHostMalloc 38 | #define cudaHostAllocDefault hipHostMallocDefault 39 | #define cudaMalloc hipMalloc 40 | #define cudaMemcpy hipMemcpy 41 | #define cudaMemcpyAsync hipMemcpyAsync 42 | #define cudaMemcpyDeviceToHost hipMemcpyDeviceToHost 43 | #define cudaMemcpyDeviceToDevice hipMemcpyDeviceToDevice 44 | #define cudaMemcpyHostToDevice hipMemcpyHostToDevice 45 | #define cudaMemGetInfo hipMemGetInfo 46 | #define cudaMemset hipMemset 47 | #define cudaReadModeElementType hipReadModeElementType 48 | #define cudaSetDevice hipSetDevice 49 | #define cudaSuccess hipSuccess 50 | #define cudaGetDeviceProperties hipGetDeviceProperties 51 | #define cudaThreadSynchronize hipDeviceSynchronize 52 | #define cudaErrorMemoryAllocation hipErrorMemoryAllocation 53 | #define cudaDeviceGetAttribute hipDeviceGetAttribute 54 | #define cudaDevAttrMemoryPoolsSupported hipDeviceAttributeMemoryPoolsSupported 55 | #define cudaDevAttrMaxThreadsPerBlock hipDeviceAttributeMaxThreadsPerBlock 56 | #define cudaDevAttrMultiProcessorCount hipDeviceAttributeMultiprocessorCount 57 | 58 | #define cufftDestroy hipfftDestroy 59 | #define cufftDoubleComplex hipfftDoubleComplex 60 | #define cufftDoubleReal hipfftDoubleReal 61 | #define cufftExecD2Z hipfftExecD2Z 62 | #define cufftExecZ2D hipfftExecZ2D 63 | #define cufftExecZ2Z hipfftExecZ2Z 64 | #define cufftHandle hipfftHandle 65 | #define cufftPlan3d hipfftPlan3d 66 | #define cufftPlanMany hipfftPlanMany 67 | 68 | #define cuFloatComplex hipFloatComplex 69 | #define cuDoubleComplex hipDoubleComplex 70 | #define make_cuFloatComplex make_hipFloatComplex 71 | #define make_cuDoubleComplex make_hipDoubleComplex 72 | 73 | 74 | static void __attribute__((unused)) check(const hipError_t err, const char *const file, const int line) 75 | { 76 | if (err == hipSuccess) return; 77 | fprintf(stderr,"HIP ERROR AT LINE %d OF FILE '%s': %s %s\n",line,file,hipGetErrorName(err),hipGetErrorString(err)); 78 | fflush(stderr); 79 | exit(err); 80 | } 81 | 82 | #endif //CUDA_TO_HIP_HPP -------------------------------------------------------------------------------- /examples/isolated/reporting_matrices.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of using matrix reporters, specifically 3 | * reportCompMatr, reportDiagMatr, reportFullStateDiagMatr, 4 | * in C11. We exclude reporting of fixed-size matrices (e.g. 5 | * CompMatr1) which is almost exactly the same as shown here. 6 | * This example is most interested when run distributed over 7 | * up to 64 nodes, spoofed using mpirun --oversubscribe. 8 | * Note MSVC's C11 (which is already weird) doesn't support 9 | * assigning any non-complex literal to complex variables nor 10 | * any complex arithmetic operators, so it doesn't get to play 11 | * with the other children. 12 | * 13 | * @author Tyson Jones 14 | */ 15 | 16 | #include "quest.h" 17 | #include 18 | 19 | #if !defined(_MSC_VER) 20 | 21 | 22 | 23 | void rootPrint(qindex num) { 24 | 25 | if (getQuESTEnv().rank != 0) 26 | return; 27 | 28 | printf("\n\n>> set number of reported items to %lld", num); 29 | 30 | if (num == 0) 31 | printf(" (which means report all)"); 32 | 33 | printf("\n\n"); 34 | } 35 | 36 | 37 | 38 | void demo_CompMatr() { 39 | 40 | CompMatr matr = createCompMatr(4); 41 | for (qindex r=0; r 13 | #include 14 | 15 | 16 | 17 | /* 18 | * environment deployments 19 | */ 20 | 21 | 22 | void demo_serial() { 23 | 24 | int useDistrib = 0; 25 | int useGpuAccel = 0; 26 | int useMultithread = 0; 27 | 28 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 29 | 30 | reportStr("serial"); 31 | reportQuESTEnv(); 32 | } 33 | 34 | 35 | void demo_multithreaded() { 36 | 37 | int useDistrib = 0; 38 | int useGpuAccel = 0; 39 | int useMultithread = 1; 40 | 41 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 42 | 43 | reportStr("multithreaded"); 44 | reportQuESTEnv(); 45 | } 46 | 47 | 48 | void demo_gpuAccelerated() { 49 | 50 | int useDistrib = 0; 51 | int useGpuAccel = 1; 52 | int useMultithread = 0; 53 | 54 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 55 | 56 | reportStr("GPU-accelerated"); 57 | reportQuESTEnv(); 58 | } 59 | 60 | 61 | void demo_distributed() { 62 | 63 | int useDistrib = 1; 64 | int useGpuAccel = 0; 65 | int useMultithread = 0; 66 | 67 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 68 | 69 | reportStr("distributed"); 70 | reportQuESTEnv(); 71 | } 72 | 73 | 74 | void demo_all() { 75 | 76 | int useDistrib = 1; 77 | int useGpuAccel = 1; 78 | int useMultithread = 1; 79 | 80 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 81 | 82 | reportStr("all"); 83 | reportQuESTEnv(); 84 | } 85 | 86 | 87 | void demo_auto() { 88 | 89 | initQuESTEnv(); 90 | 91 | reportStr("auto"); 92 | reportQuESTEnv(); 93 | } 94 | 95 | 96 | 97 | /* 98 | * main 99 | */ 100 | 101 | 102 | int printCmdArgInfo() { 103 | 104 | // we can only initialise the QuEST environment once, so 105 | // we accept command-line arg 1-6 to choose the deployment 106 | 107 | // all nodes must print because we've not yet setup MPI 108 | printf( 109 | "Must pass single cmd-line argument:\n" 110 | " 1 = serial\n" 111 | " 2 = multithreaded\n" 112 | " 3 = GPU-accelerated\n" 113 | " 4 = distributed\n" 114 | " 5 = all\n" 115 | " 6 = auto\n"); 116 | 117 | // process return code, indicate error 118 | return 1; 119 | } 120 | 121 | 122 | int main(int argc, char* argv[]) { 123 | 124 | if (argc != 2) 125 | return printCmdArgInfo(); 126 | 127 | int opt = atoi(argv[1]); 128 | if (opt < 1 || opt > 6) 129 | return printCmdArgInfo(); 130 | 131 | if (opt == 1) demo_serial(); 132 | if (opt == 2) demo_multithreaded(); 133 | if (opt == 3) demo_gpuAccelerated(); 134 | if (opt == 4) demo_distributed(); 135 | if (opt == 5) demo_all(); 136 | if (opt == 6) demo_auto(); 137 | 138 | finalizeQuESTEnv(); 139 | return 0; 140 | } 141 | -------------------------------------------------------------------------------- /examples/isolated/reporting_environments.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of using reportQuESTEnv() in C++14. This example 3 | * is most interesting when compiling to simultaneously 4 | * enable multithreaded, GPU-accelerated and distributed 5 | * deployments. When launching, pass an integer 1-6 as a 6 | * command-line argument to choose a deployment. 7 | * 8 | * @author Tyson Jones 9 | */ 10 | 11 | #include "quest.h" 12 | #include 13 | #include 14 | 15 | 16 | 17 | /* 18 | * environment deployments 19 | */ 20 | 21 | 22 | void demo_serial() { 23 | 24 | int useDistrib = 0; 25 | int useGpuAccel = 0; 26 | int useMultithread = 0; 27 | 28 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 29 | 30 | reportStr("serial"); 31 | reportQuESTEnv(); 32 | } 33 | 34 | 35 | void demo_multithreaded() { 36 | 37 | int useDistrib = 0; 38 | int useGpuAccel = 0; 39 | int useMultithread = 1; 40 | 41 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 42 | 43 | reportStr("multithreaded"); 44 | reportQuESTEnv(); 45 | } 46 | 47 | 48 | void demo_gpuAccelerated() { 49 | 50 | int useDistrib = 0; 51 | int useGpuAccel = 1; 52 | int useMultithread = 0; 53 | 54 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 55 | 56 | reportStr("GPU-accelerated"); 57 | reportQuESTEnv(); 58 | } 59 | 60 | 61 | void demo_distributed() { 62 | 63 | int useDistrib = 1; 64 | int useGpuAccel = 0; 65 | int useMultithread = 0; 66 | 67 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 68 | 69 | reportStr("distributed"); 70 | reportQuESTEnv(); 71 | } 72 | 73 | 74 | void demo_all() { 75 | 76 | int useDistrib = 1; 77 | int useGpuAccel = 1; 78 | int useMultithread = 1; 79 | 80 | initCustomQuESTEnv(useDistrib, useGpuAccel, useMultithread); 81 | 82 | reportStr("all"); 83 | reportQuESTEnv(); 84 | } 85 | 86 | 87 | void demo_auto() { 88 | 89 | initQuESTEnv(); 90 | 91 | reportStr("auto"); 92 | reportQuESTEnv(); 93 | } 94 | 95 | 96 | 97 | /* 98 | * main 99 | */ 100 | 101 | 102 | int printCmdArgInfo() { 103 | 104 | // we can only initialise the QuEST environment once, so 105 | // we accept command-line arg 1-6 to choose the deployment 106 | 107 | // all nodes must print because we've not yet setup MPI 108 | std::cout << ( 109 | "Must pass single cmd-line argument:\n" 110 | " 1 = serial\n" 111 | " 2 = multithreaded\n" 112 | " 3 = GPU-accelerated\n" 113 | " 4 = distributed\n" 114 | " 5 = all\n" 115 | " 6 = auto") << std::endl; 116 | 117 | // process return code, indicate error 118 | return 1; 119 | } 120 | 121 | 122 | int main(int argc, char* argv[]) { 123 | 124 | if (argc != 2) 125 | return printCmdArgInfo(); 126 | 127 | int opt = std::stoi(argv[1]); 128 | if (opt < 1 || opt > 6) 129 | return printCmdArgInfo(); 130 | 131 | if (opt == 1) demo_serial(); 132 | if (opt == 2) demo_multithreaded(); 133 | if (opt == 3) demo_gpuAccelerated(); 134 | if (opt == 4) demo_distributed(); 135 | if (opt == 5) demo_all(); 136 | if (opt == 6) demo_auto(); 137 | 138 | finalizeQuESTEnv(); 139 | return 0; 140 | } 141 | -------------------------------------------------------------------------------- /docs/architecture.md: -------------------------------------------------------------------------------- 1 | # 🏗️  Architecture 2 | 3 | 9 | 10 | > [!TIP] 11 | > See [PR #615](https://github.com/QuEST-Kit/QuEST/pull/615) for an illustration of integrating 12 | > new functions into the QuEST software architecture. 13 | 14 | All user-visible API signatures are contained in `include/`, divided into semantic submodules (like `calculations.h` and `qureg.h`), but all exposed by `quest.h`. They are all strictly `C` _and_ `C++` compatible, hence their `.h` file extension. 15 | 16 | The source code within `src/` is divided between five subdirectories, listed below in order of increasing control flow depth. All code is parsed strictly by `C++`, hence all files have `.cpp` and `.hpp` extensions. 17 | - `api/` 18 | > contains definitions of the API, directly callable by users (in `C` _or_ `C++`, so it contains de-mangling guards). Functions are divided between files therein similarly to `include/`, and they call only `core/` functions. 19 | - `core/` 20 | > contains internal non-simulation functions like user-input validaters, non-accelerated maths, and dispatchers to hardware-accelerated backends. 21 | - `comm/` 22 | > contains functions needed for exchanging data between distributed nodes, as invoked by the `core/` layer before hardware-accelerated backends. 23 | - `cpu/` 24 | > constitutes the multithreaded CPU backend, containing OpenMP-accelerated subroutines and (potentially) AVX intrinsics. 25 | - `gpu/` 26 | > constitutes the GPU backend, containing CUDA-accelerated subroutines, GPU hardware queriers, interfaces to CUDA libraries (like Thrust and cuQuantum), and wrappers for AMD/HIP compatibility. Note that some files therein have suffix `.cpp` in lieu of `.cu`, because they are permittedly parsed by non-CUDA compilers when disabling GPU-acceleration at compile-time. 27 | 28 | The control flow from the user interface (`quest.h`) to the hardware-accelerated simulation subroutines is mostly captured by: 29 | 30 | - `include/quest.h` 31 | - `api/*` 32 | - `core/validation` 33 | - `core/memory` 34 | - `gpu/gpu_config` 35 | - `comm/comm_config` 36 | - `core/utilities` 37 | - `core/localiser` 38 | - `comm/comm_routines` 39 | - `core/accelerator` 40 | - `cpu/cpu_subroutines` 41 | - `gpu/gpu_subroutines` 42 | - `gpu/gpu_kernels` 43 | - `gpu/gpu_thrust` 44 | - `gpu/gpu_cuquantum` 45 | 46 | 47 | Every API function first validates the user given inputs via `core/validation.cpp`, which in-turn may consult hardware facilities like available RAM (via `core/memory.cpp`) and VRAM (via `gpu/gpu_config.cpp`), or the distributed configuration (via `comm/comm_config.cpp`). Simulation API functions will then invoke `core/localiser.cpp` which checks whether distributed data exchange is necessary in order for all subsequently needed data to become locally available. If so, it invokes functions of `comm/comm_routines.cpp`, then proceeds. Stage `core/accelerator.cpp` chooses whether to process the (potentially just received) data using the CPU (accelerating with `OpenMP`) or the GPU (accelerating with `CUDA`). GPU-acceleration can involve dispatching to custom kernels (in `gpu/cpu_kernels.cpp`), or Thrust routines (in `gpu/gpu_thrust.hpp`), or alternatively to a cuQuantum routine (in `gpu/gpu_cuquantum.hpp`) if optionally compiled. At any call depth, functions within `core/errors.cpp` will be called to confirm preconditions. -------------------------------------------------------------------------------- /utils/docs/layout/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $projectname: $title 10 | $title 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | $treeview 26 | $search 27 | $mathjax 28 | $darkmode 29 | 30 | $extrastylesheet 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 | 46 |
47 | 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 62 | 63 | 64 | 65 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |
58 |
$projectname $projectnumber 59 |
60 |
$projectbrief
61 |
66 |
$projectbrief
67 |
$searchbox
$searchbox
85 |
86 | 87 | 88 | -------------------------------------------------------------------------------- /tests/utils/config.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Testing utilities for loading environment variables 3 | * which configure the unit tests, independent of QuEST's 4 | * internal environment variable facilities 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | 10 | /** @file 11 | * @author Tyson Jones 12 | * 13 | * @defgroup testutilsconfig Config 14 | * @ingroup testutils 15 | * @brief 16 | * Testing utilities for loading environment variables 17 | * which configure the unit tests, independent of QuEST's 18 | * internal environment variable facilities 19 | * @{ 20 | */ 21 | 22 | #ifndef CONFIG_HPP 23 | #define CONFIG_HPP 24 | 25 | 26 | /* 27 | * SPECIFYING ENV-VARS 28 | */ 29 | 30 | // spoofing as macros to doc; beware that the values below 31 | // merely duplicate but do not change the default values 32 | // which are hardcoded in config.cpp 33 | #if 0 34 | 35 | /// @envvardoc 36 | const int TEST_NUM_QUBITS_IN_QUREG = 6; 37 | 38 | /** @envvardoc 39 | * 40 | * Specifies the maximum number of control and target qubit permutations for which to unit test each relevant 41 | * API function. 42 | * 43 | * Many QuEST functions accept a varying number of target qubits (like applyCompMatr()) and/or control qubits 44 | * (like applyMultiControlledCompMatr()). The unit tests will run these functions, passing every possible number 45 | * of target qubits (alongside every possible number of control qubits, if possible), from one (zero) up to the 46 | * number contained within the tested `Qureg` (minus the number of target qubits). 47 | * 48 | * For each of these tested number-of-targets and number-of-controls combinations, there are factorially-many 49 | * possible choices of the arbitrarily-ordered qubit indices, i.e. sub-permutations of all Qureg qubits. 50 | * By default, the unit tests deterministically check every permutation in-turn. This can become prohibitively 51 | * slow when the tested `Qureg` are large. For example, there are `604,800` unique, non-overlapping choices of 52 | * `4` targets and `3` controls in a Qureg containing `10` qubits. 53 | * 54 | * When this environment variable is set to a non-zero value, the unit tests will forego testing every permutation 55 | * and instead perform only the number specified, randomising the involved qubits. This can significantly speed up the 56 | * tests though risks missing esoteric edge-cases. The runtime of the tests are approximately linearly proportional 57 | * to the specified number of permutations. When the specified non-zero value exceeds the number of unique 58 | * permutations, the tests will revert to deterministically evaluating each once. 59 | * 60 | * @envvarvalues 61 | * 62 | * - set to `0` (default) to systematically test all permutations. 63 | * - set to a positive integer (e.g. `50`) to test (at most) that many random permutations and accelerate the tests. 64 | * 65 | * @author Tyson Jones 66 | */ 67 | const int TEST_MAX_NUM_QUBIT_PERMUTATIONS = 0; 68 | 69 | /// @envvardoc 70 | const int TEST_MAX_NUM_SUPEROP_TARGETS = 4; 71 | 72 | /// @envvardoc 73 | const int TEST_ALL_DEPLOYMENTS = 1; 74 | 75 | /// @envvardoc 76 | const int TEST_NUM_MIXED_DEPLOYMENT_REPETITIONS = 10; 77 | 78 | #endif 79 | 80 | 81 | /* 82 | * ACCESSING ENV-VARS 83 | */ 84 | 85 | int getNumQubitsInUnitTestedQuregs(); 86 | int getMaxNumTestedQubitPermutations(); 87 | int getMaxNumTestedSuperoperatorTargets(); 88 | int getNumTestedMixedDeploymentRepetitions(); 89 | bool getWhetherToTestAllDeployments(); 90 | 91 | 92 | #endif // CONFIG_PP 93 | 94 | /** @} (end defgroup) */ 95 | -------------------------------------------------------------------------------- /quest/include/wrappers.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * C-compatible functions which are alternatives to C++-only API 3 | * functions, ultimately providing an identical interface. This is 4 | * necessary because these functions otherwise return qcomps by-value 5 | * which is prohibited between C and C++ compiled binaries (because 6 | * complex numbers are not agreed upon in their ABI, despite having 7 | * identical memory layouts in the C and C++ standard libraries). 8 | * Ergo this file defines no new API functions as far as the user/ 9 | * documentation is aware, but secretly ensures the backend C++ 10 | * binaries return qcomps to the user's C code only by pointer. 11 | * 12 | * (( _passing_ qcomps by value to a function seems to be okay, 13 | * although I am not entirely sure why )) 14 | * 15 | * Note that matrix getters and setters (like getCompMatr1()) are 16 | * excluded, and instead defined directly in matrices.h/.cpp . 17 | * 18 | * An unimportant by-product of this method of achieving interoperability 19 | * is that the internal wrapped functions are exposed to the C user; so 20 | * we prefix them with "_wrap_" to imply privacy. Note the "extern" 21 | * declarations are superfluous (the behaviour is default), but used 22 | * to explicitly distinguish the intendedly-private internal functions 23 | * from the C API functions herein defined. 24 | * 25 | * @author Tyson Jones 26 | * 27 | * (no doxygen doc) 28 | */ 29 | 30 | #ifndef WRAPPERS_H 31 | #define WRAPPERS_H 32 | 33 | #include "quest/include/types.h" 34 | #include "quest/include/qureg.h" 35 | #include "quest/include/paulis.h" 36 | #include "quest/include/matrices.h" 37 | 38 | /// @cond EXCLUDE_FROM_DOXYGEN 39 | 40 | // these definitions are only exposed to C, 41 | // since they duplicate existing C++ functions 42 | #ifndef __cplusplus 43 | 44 | 45 | 46 | extern void _wrap_calcInnerProduct(Qureg bra, Qureg ket, qcomp* out); 47 | 48 | qcomp calcInnerProduct(Qureg bra, Qureg ket) { 49 | 50 | qcomp out; 51 | _wrap_calcInnerProduct(bra, ket, &out); 52 | return out; 53 | } 54 | 55 | 56 | extern void _wrap_calcExpecNonHermitianPauliStrSum(qcomp*, Qureg, PauliStrSum); 57 | 58 | qcomp calcExpecNonHermitianPauliStrSum(Qureg qureg, PauliStrSum sum) { 59 | 60 | qcomp out; 61 | _wrap_calcExpecNonHermitianPauliStrSum(&out, qureg, sum); 62 | return out; 63 | } 64 | 65 | 66 | extern void _wrap_calcExpecNonHermitianFullStateDiagMatr(qcomp*, Qureg, FullStateDiagMatr); 67 | 68 | qcomp calcExpecNonHermitianFullStateDiagMatr(Qureg qureg, FullStateDiagMatr matr) { 69 | 70 | qcomp out; 71 | _wrap_calcExpecNonHermitianFullStateDiagMatr(&out, qureg, matr); 72 | return out; 73 | } 74 | 75 | 76 | extern void _wrap_calcExpecNonHermitianFullStateDiagMatrPower(qcomp*, Qureg, FullStateDiagMatr, qcomp); 77 | 78 | qcomp calcExpecNonHermitianFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr matr, qcomp expo) { 79 | 80 | qcomp out; 81 | _wrap_calcExpecNonHermitianFullStateDiagMatrPower(&out, qureg, matr, expo); 82 | return out; 83 | } 84 | 85 | 86 | extern void _wrap_getQuregAmp(qcomp* out, Qureg qureg, qindex index); 87 | 88 | qcomp getQuregAmp(Qureg qureg, qindex index) { 89 | 90 | qcomp out; 91 | _wrap_getQuregAmp(&out, qureg, index); 92 | return out; 93 | } 94 | 95 | 96 | extern void _wrap_getDensityQuregAmp(qcomp* out, Qureg qureg, qindex row, qindex column); 97 | 98 | qcomp getDensityQuregAmp(Qureg qureg, qindex row, qindex column) { 99 | 100 | qcomp out; 101 | _wrap_getDensityQuregAmp(&out, qureg, row, column); 102 | return out; 103 | } 104 | 105 | 106 | 107 | #endif // !__cplusplus 108 | 109 | /// @endcond // EXCLUDE_FROM_DOXYGEN 110 | 111 | #endif // WRAPPERS_H -------------------------------------------------------------------------------- /quest/src/core/memory.hpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Internal signatures which query available CPU memory (in an 3 | * attemptedly OS-agnostic way), and provide needed memory 4 | * querents. Note GPU memory querying is performed by 5 | * the dedicated GPU backend, though this file is always 6 | * compiled (even in GPU mode) because GPU-acceleration still 7 | * requires accompanying CPU memory arrays. This file does not 8 | * perform any allocation of memory; that is instead performed 9 | * by cpu_config.cpp, to be symmetric with the GPU-memory 10 | * allocators in gpu_config.cpp, and use NUMA strategies. 11 | * 12 | * @author Tyson Jones 13 | */ 14 | 15 | #ifndef MEMORY_HPP 16 | #define MEMORY_HPP 17 | 18 | #include "quest/include/types.h" 19 | #include "quest/include/qureg.h" 20 | #include "quest/include/paulis.h" 21 | 22 | 23 | 24 | /* 25 | * HARDWARE QUERYING 26 | */ 27 | 28 | 29 | namespace mem { typedef bool COULD_NOT_QUERY_RAM; } 30 | 31 | qindex mem_tryGetLocalRamCapacityInBytes(); 32 | 33 | 34 | 35 | /* 36 | * MEMORY USAGE 37 | */ 38 | 39 | 40 | int mem_getEffectiveNumStateVecQubitsPerNode(int numQubits, bool isDensMatr, int numNodes); 41 | 42 | qindex mem_getTotalGlobalMemoryUsed(Qureg qureg); 43 | 44 | 45 | 46 | /* 47 | * MEMORY REQUIRED 48 | */ 49 | 50 | size_t mem_getLocalQuregMemoryRequired(int numQubits, bool isDensityMatr, int numNodes); 51 | size_t mem_getLocalQuregMemoryRequired(qindex numAmpsPerNode); 52 | 53 | size_t mem_getLocalMatrixMemoryRequired(int numQubits, bool isDenseMatrix, int numNodes); 54 | 55 | size_t mem_getLocalSuperOpMemoryRequired(int numQubits); 56 | 57 | 58 | 59 | /* 60 | * QUBIT BOUNDS 61 | */ 62 | 63 | 64 | int mem_getMaxNumQuregQubitsWhichCanFitInMemory(bool isDensityMatrix, int numNodes, qindex memBytesPerNode); 65 | 66 | int mem_getMaxNumMatrixQubitsWhichCanFitInMemory(bool isDenseMatrix, int numNodes, qindex memBytesPerNode); 67 | 68 | int mem_getMaxNumSuperOpQubitsWhichCanFitInMemory(qindex memBytesPerNode); 69 | 70 | 71 | int mem_getMinNumQubitsForDistribution(int numNodes); 72 | 73 | 74 | int mem_getMaxNumQuregQubitsBeforeIndexOverflow(bool isDensityMatrix); 75 | 76 | int mem_getMaxNumMatrixQubitsBeforeIndexOverflow(bool isDenseMatrix); 77 | 78 | int mem_getMaxNumSuperOpQubitsBeforeIndexOverflow(); 79 | 80 | qindex mem_getMaxNumKrausMapMatricesBeforeIndexOverflow(int numQubits); 81 | 82 | 83 | int mem_getMaxNumQuregQubitsBeforeGlobalMemSizeofOverflow(bool isDensityMatrix, int numNodes); 84 | 85 | int mem_getMaxNumMatrixQubitsBeforeGlobalMemSizeofOverflow(bool isDenseMatrix, int numNodes); 86 | 87 | int mem_getMaxNumSuperOpQubitsBeforeGlobalMemSizeofOverflow(); 88 | 89 | qindex mem_getMaxNumKrausMapMatricesBeforeLocalMemSizeofOverflow(int numQubits); 90 | 91 | 92 | 93 | /* 94 | * SUFFICIENT MEMORY QUERYING 95 | */ 96 | 97 | 98 | bool mem_canQuregFitInMemory(int numQubits, bool isDensMatr, int numNodes, qindex memBytesPerNode); 99 | 100 | bool mem_canMatrixFitInMemory(int numQubits, bool isDense, int numNodes, qindex memBytesPerNode); 101 | 102 | bool mem_canSuperOpFitInMemory(int numQubits, qindex numBytesPerNode); 103 | 104 | bool mem_canPauliStrSumFitInMemory(qindex numTerms, qindex numBytesPerNode); 105 | 106 | 107 | 108 | /* 109 | * MEMORY ALLOCATION SUCCESS 110 | */ 111 | 112 | 113 | bool mem_isAllocated(int* heapflag); 114 | bool mem_isAllocated(PauliStr* array); 115 | bool mem_isAllocated(qcomp* array); 116 | bool mem_isAllocated(qcomp** matrix, qindex numRows); 117 | bool mem_isAllocated(qcomp*** matrixList, qindex numRows, int numMatrices); 118 | 119 | bool mem_isOuterAllocated(qcomp* ptr); 120 | bool mem_isOuterAllocated(qcomp** ptr); 121 | bool mem_isOuterAllocated(qcomp*** ptr); 122 | 123 | 124 | 125 | #endif // MEMORY_HPP -------------------------------------------------------------------------------- /quest/include/modes.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Constants related to configuring QuEST runtime modes, 3 | * and documentation of environment variables 4 | * 5 | * @author Tyson Jones 6 | * 7 | * @defgroup modes Modes 8 | * @ingroup api 9 | * @brief Constants and environment variables for controlling QuEST execution. 10 | * @{ 11 | */ 12 | 13 | #ifndef MODES_H 14 | #define MODES_H 15 | 16 | 17 | 18 | // document environment variables 19 | 20 | // spoof env-vars as consts to doc (hackily and hopefully temporarily) 21 | #if 0 22 | 23 | 24 | /** @envvardoc 25 | * 26 | * Specifies whether to permit multiple MPI processes to deploy to the same GPU. 27 | * 28 | * @attention 29 | * This environment variable has no effect when either (or both) of distribution or 30 | * GPU-acceleration are disabled. 31 | * 32 | * In multi-GPU execution, which combines distribution with GPU-acceleration, it is 33 | * prudent to assign each GPU to at most one MPI process in order to avoid superfluous 34 | * slowdown. Hence by default, initQuESTEnv() will forbid assigning multiple MPI processes 35 | * to the same GPU. This environment variable can be set to `1` to disable this validation, 36 | * permitting sharing of a single GPU, as is often useful for debugging or unit testing 37 | * (for example, testing multi-GPU execution when only a single GPU is available). 38 | * 39 | * @warning 40 | * Permitting GPU sharing may cause unintended behaviour when additionally using cuQuantum. 41 | * 42 | * @envvarvalues 43 | * - forbid sharing: @p 0, @p '0', @p '', @p , (unspecified) 44 | * - permit sharing: @p 1, @p '1' 45 | * 46 | * @author Tyson Jones 47 | */ 48 | const int PERMIT_NODES_TO_SHARE_GPU = 0; 49 | 50 | 51 | /** @envvardoc 52 | * 53 | * Specifies the default validation epsilon. 54 | * 55 | * Specifying `DEFAULT_VALIDATION_EPSILON` to a positive, real number overrides the 56 | * precision-specific default (`1E-5`, `1E-12`, `1E-13` for single, double and quadruple 57 | * precision respectively). The specified epsilon is used by QuEST for numerical validation 58 | * unless overriden at runtime via setValidationEpsilon(), in which case it can be 59 | * restored to that specified by this environment variable using setValidationEpsilonToDefault(). 60 | * 61 | * @envvarvalues 62 | * - setting @p DEFAULT_VALIDATION_EPSILON=0 disables numerical validation, as if the value 63 | * were instead infinity. 64 | * - setting @p DEFAULT_VALIDATION_EPSILON='' is equivalent to _not_ specifying the variable, 65 | * adopting instead the precision-specific default above. 66 | * - setting @p DEFAULT_VALIDATION_EPSILON=x where `x` is a positive, valid `qreal` in any 67 | * format accepted by `C` or `C++` (e.g. `0.01`, `1E-2`, `+1e-2`) will use `x` as the 68 | * default validation epsilon. 69 | * 70 | * @constraints 71 | * The function initQuESTEnv() will throw a validation error if: 72 | * - The specified epsilon must be `0` or positive. 73 | * - The specified epsilon must not exceed that maximum or minimum value which can be stored 74 | * in a `qreal`, which is specific to its precision. 75 | * 76 | * @author Tyson Jones 77 | */ 78 | const qreal DEFAULT_VALIDATION_EPSILON = 0; 79 | 80 | 81 | #endif 82 | 83 | 84 | 85 | // user flags for choosing automatic deployment; only accessible by C++ 86 | // backend and C++ users; C users must hardcode -1 87 | 88 | #ifdef __cplusplus 89 | 90 | namespace modeflag { 91 | 92 | extern int USE_AUTO; 93 | } 94 | 95 | #endif // __cplusplus 96 | 97 | 98 | 99 | #endif // MODES_H 100 | 101 | /** @} */ // (end file-wide doxygen defgroup) 102 | -------------------------------------------------------------------------------- /utils/docs/layout/doxygen-awesome-sidebar-only.css: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Doxygen Awesome 4 | https://github.com/jothepro/doxygen-awesome-css 5 | 6 | MIT License 7 | 8 | Copyright (c) 2021 - 2023 jothepro 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | */ 29 | 30 | html { 31 | /* side nav width. MUST be = `TREEVIEW_WIDTH`. 32 | * Make sure it is wide enough to contain the page title (logo + title + version) 33 | */ 34 | 35 | --side-nav-fixed-width: 335px; 36 | --menu-display: none; 37 | 38 | --top-height: 120px; 39 | --toc-sticky-top: -25px; 40 | --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px); 41 | } 42 | 43 | #projectname { 44 | white-space: nowrap; 45 | } 46 | 47 | 48 | @media screen and (min-width: 768px) { 49 | html { 50 | --searchbar-background: var(--page-background-color); 51 | } 52 | 53 | #side-nav { 54 | min-width: var(--side-nav-fixed-width); 55 | max-width: var(--side-nav-fixed-width); 56 | top: var(--top-height); 57 | overflow: visible; 58 | } 59 | 60 | #nav-tree, #side-nav { 61 | height: calc(100vh - var(--top-height)) !important; 62 | } 63 | 64 | #nav-tree { 65 | padding: 0; 66 | } 67 | 68 | #top { 69 | display: block; 70 | border-bottom: none; 71 | height: var(--top-height); 72 | margin-bottom: calc(0px - var(--top-height)); 73 | max-width: var(--side-nav-fixed-width); 74 | overflow: hidden; 75 | background: var(--side-nav-background); 76 | } 77 | #main-nav { 78 | float: left; 79 | padding-right: 0; 80 | } 81 | 82 | .ui-resizable-handle { 83 | cursor: default; 84 | width: 1px !important; 85 | background: var(--separator-color); 86 | box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color); 87 | } 88 | 89 | #nav-path { 90 | position: fixed; 91 | right: 0; 92 | left: var(--side-nav-fixed-width); 93 | bottom: 0; 94 | width: auto; 95 | } 96 | 97 | #doc-content { 98 | height: calc(100vh - 31px) !important; 99 | padding-bottom: calc(3 * var(--spacing-large)); 100 | padding-top: calc(var(--top-height) - 80px); 101 | box-sizing: border-box; 102 | margin-left: var(--side-nav-fixed-width) !important; 103 | } 104 | 105 | #MSearchBox { 106 | width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium))); 107 | } 108 | 109 | #MSearchField { 110 | width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px); 111 | } 112 | 113 | #MSearchResultsWindow { 114 | left: var(--spacing-medium) !important; 115 | right: auto; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /examples/isolated/initialising_superoperators.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of initialising a SuperOp in C++14. 3 | * Note that when compiling QuEST in C++ with 'double' 4 | * or 'long double' precision, you can freely use 's 5 | * double-precision literals, e.g. 6 | * 7 | * qcomp x = 1.3i 8 | * 9 | * However, such literals are forbidden when compiling in 'single' 10 | * precision; the compiler will not allow the double-precision 11 | * literal to be autocast to a float. If you want to use 12 | * precision-agnostic complex literals, you can use "_i", e.g. 13 | * 14 | * qcomp x = 1.3_i 15 | * 16 | * This file will use the latter literal. 17 | * 18 | * @author Tyson Jones 19 | */ 20 | 21 | #include "quest.h" 22 | #include 23 | #include 24 | 25 | using std::vector; 26 | 27 | 28 | 29 | void demo_createInlineSuperOp() { 30 | 31 | // inline literal 32 | SuperOp a = createInlineSuperOp(1, { 33 | {1,2,3,4}, 34 | {5,0.0000000006-(10E-11) * 3.14_i,7,8}, 35 | {9,10,11,12}, 36 | {13,14,15,16+1.23_i} 37 | }); 38 | reportSuperOp(a); 39 | destroySuperOp(a); 40 | 41 | // existing vector (C++ only) 42 | vector> elems(16, vector(16,5_i)); 43 | SuperOp b = createInlineSuperOp(2, elems); 44 | reportSuperOp(b); 45 | destroySuperOp(b); 46 | } 47 | 48 | 49 | void demo_setInlineSuperOp() { 50 | 51 | // inline literal; achieves the same as setSuperOp(), and exists for consistencty with C API 52 | SuperOp a = createSuperOp(1); 53 | setInlineSuperOp(a, 1, { 54 | {1,2,3,4}, 55 | {5,0.0000000006-(10E-11) * 3.14_i,7,8}, 56 | {9,10,11,12}, 57 | {13,14,15,16+1.23_i} 58 | }); 59 | reportSuperOp(a); 60 | destroySuperOp(a); 61 | } 62 | 63 | 64 | void demo_setSuperOp() { 65 | 66 | // inline literal (C++ only) 67 | SuperOp a = createSuperOp(1); 68 | setSuperOp(a, { 69 | {1,2,3,4}, 70 | {5,0.0000000006-(10E-11) * 3.14_i,7,8}, 71 | {9,10,11,12}, 72 | {13,14,15,16+1.23_i}}); 73 | reportSuperOp(a); 74 | destroySuperOp(a); 75 | 76 | // 2D vector (C++ only) 77 | vector> vec { 78 | {-9,-8, -8, -9}, 79 | {7, 7, 6, 6}, 80 | {0, -1, -2, -3}, 81 | {-4_i, -5_i, 0, 0} 82 | }; 83 | SuperOp b = createSuperOp(1); 84 | setSuperOp(b, vec); 85 | reportSuperOp(b); 86 | destroySuperOp(b); 87 | 88 | // nested pointers 89 | int n = 3; 90 | int d = 1 << (2*n); 91 | qcomp** ptrs = (qcomp**) malloc(d * sizeof *ptrs); 92 | for (int i=0; i 12 | 13 | 14 | 15 | /* 16 | * Qureg deployments 17 | */ 18 | 19 | 20 | void demo_serial() { 21 | 22 | reportStr("\n[serial]"); 23 | 24 | int numQubits = 10; 25 | int isDensMatr = 0; 26 | 27 | int useDistrib = 0; 28 | int useGpuAccel = 0; 29 | int useMultithread = 0; 30 | 31 | Qureg qureg = createCustomQureg( 32 | numQubits, isDensMatr, 33 | useDistrib, useGpuAccel, useMultithread); 34 | 35 | reportQuregParams(qureg); 36 | reportQureg(qureg); 37 | destroyQureg(qureg); 38 | } 39 | 40 | 41 | void demo_multithreaded() { 42 | 43 | reportStr("\n[multithreaded]"); 44 | 45 | int numQubits = 10; 46 | int isDensMatr = 0; 47 | 48 | int useDistrib = 0; 49 | int useGpuAccel = 0; 50 | int useMultithread = getQuESTEnv().isMultithreaded; 51 | 52 | Qureg qureg = createCustomQureg( 53 | numQubits, isDensMatr, 54 | useDistrib, useGpuAccel, useMultithread); 55 | 56 | reportQuregParams(qureg); 57 | reportQureg(qureg); 58 | destroyQureg(qureg); 59 | } 60 | 61 | 62 | void demo_gpuAccelerated() { 63 | 64 | reportStr("\n[GPU-accelerated]"); 65 | 66 | int numQubits = 10; 67 | int isDensMatr = 0; 68 | 69 | int useDistrib = 0; 70 | int useGpuAccel = getQuESTEnv().isGpuAccelerated; 71 | int useMultithread = 0; 72 | 73 | Qureg qureg = createCustomQureg( 74 | numQubits, isDensMatr, 75 | useDistrib, useGpuAccel, useMultithread); 76 | 77 | reportQuregParams(qureg); 78 | reportQureg(qureg); 79 | destroyQureg(qureg); 80 | } 81 | 82 | 83 | void demo_distributed() { 84 | 85 | reportStr("\n[distributed]"); 86 | 87 | int numQubits = 10; 88 | int isDensMatr = 0; 89 | 90 | int useDistrib = getQuESTEnv().isDistributed; 91 | int useGpuAccel = 0; 92 | int useMultithread = 0; 93 | 94 | Qureg qureg = createCustomQureg( 95 | numQubits, isDensMatr, 96 | useDistrib, useGpuAccel, useMultithread); 97 | 98 | reportQuregParams(qureg); 99 | reportQureg(qureg); 100 | destroyQureg(qureg); 101 | } 102 | 103 | 104 | void demo_auto() { 105 | 106 | reportStr("\n[auto (statevector)]"); 107 | 108 | Qureg pure = createQureg(10); 109 | reportQuregParams(pure); 110 | reportQureg(pure); 111 | destroyQureg(pure); 112 | 113 | reportStr("\n[auto (density matrix)]"); 114 | 115 | Qureg mixed = createDensityQureg(10); 116 | reportQuregParams(mixed); 117 | reportQureg(mixed); 118 | destroyQureg(mixed); 119 | } 120 | 121 | 122 | void demo_all() { 123 | 124 | reportStr("\n[all]"); 125 | 126 | int numQubits = 10; 127 | int isDensMatr = 0; 128 | 129 | int useDistrib = getQuESTEnv().isDistributed; 130 | int useGpuAccel = getQuESTEnv().isGpuAccelerated; 131 | int useMultithread = getQuESTEnv().isMultithreaded; 132 | 133 | // throws if both GPU and multithreaded 134 | Qureg qureg = createCustomQureg( 135 | numQubits, isDensMatr, 136 | useDistrib, useGpuAccel, useMultithread); 137 | 138 | reportQuregParams(qureg); 139 | reportQureg(qureg); 140 | destroyQureg(qureg); 141 | } 142 | 143 | 144 | 145 | /* 146 | * main 147 | */ 148 | 149 | 150 | int main() { 151 | 152 | initQuESTEnv(); 153 | QuESTEnv env = getQuESTEnv(); 154 | 155 | demo_serial(); 156 | 157 | if (env.isMultithreaded) 158 | demo_multithreaded(); 159 | 160 | if (env.isGpuAccelerated) 161 | demo_gpuAccelerated(); 162 | 163 | if (env.isDistributed) 164 | demo_distributed(); 165 | 166 | demo_auto(); 167 | demo_all(); // may throw 168 | 169 | finalizeQuESTEnv(); 170 | return 0; 171 | } 172 | -------------------------------------------------------------------------------- /examples/isolated/reporting_quregs.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of using reportQureg in C++14. This 3 | * example is most interesting when using 4 | * simultaneously multithreaded, GPU-accelerated 5 | * and distributed deployments 6 | * 7 | * @author Tyson Jones 8 | */ 9 | 10 | #include "quest.h" 11 | #include 12 | #include 13 | 14 | 15 | 16 | /* 17 | * Qureg deployments 18 | */ 19 | 20 | 21 | void demo_serial() { 22 | 23 | reportStr("\n[serial]"); 24 | 25 | int numQubits = 10; 26 | int isDensMatr = 0; 27 | 28 | int useDistrib = 0; 29 | int useGpuAccel = 0; 30 | int useMultithread = 0; 31 | 32 | Qureg qureg = createCustomQureg( 33 | numQubits, isDensMatr, 34 | useDistrib, useGpuAccel, useMultithread); 35 | 36 | reportQuregParams(qureg); 37 | reportQureg(qureg); 38 | destroyQureg(qureg); 39 | } 40 | 41 | 42 | void demo_multithreaded() { 43 | 44 | reportStr("\n[multithreaded]"); 45 | 46 | int numQubits = 10; 47 | int isDensMatr = 0; 48 | 49 | int useDistrib = 0; 50 | int useGpuAccel = 0; 51 | int useMultithread = getQuESTEnv().isMultithreaded; 52 | 53 | Qureg qureg = createCustomQureg( 54 | numQubits, isDensMatr, 55 | useDistrib, useGpuAccel, useMultithread); 56 | 57 | reportQuregParams(qureg); 58 | reportQureg(qureg); 59 | destroyQureg(qureg); 60 | } 61 | 62 | 63 | void demo_gpuAccelerated() { 64 | 65 | reportStr("\n[GPU-accelerated]"); 66 | 67 | int numQubits = 10; 68 | int isDensMatr = 0; 69 | 70 | int useDistrib = 0; 71 | int useGpuAccel = getQuESTEnv().isGpuAccelerated; 72 | int useMultithread = 0; 73 | 74 | Qureg qureg = createCustomQureg( 75 | numQubits, isDensMatr, 76 | useDistrib, useGpuAccel, useMultithread); 77 | 78 | reportQuregParams(qureg); 79 | reportQureg(qureg); 80 | destroyQureg(qureg); 81 | } 82 | 83 | 84 | void demo_distributed() { 85 | 86 | reportStr("\n[distributed]"); 87 | 88 | int numQubits = 10; 89 | int isDensMatr = 0; 90 | 91 | int useDistrib = getQuESTEnv().isDistributed; 92 | int useGpuAccel = 0; 93 | int useMultithread = 0; 94 | 95 | Qureg qureg = createCustomQureg( 96 | numQubits, isDensMatr, 97 | useDistrib, useGpuAccel, useMultithread); 98 | 99 | reportQuregParams(qureg); 100 | reportQureg(qureg); 101 | destroyQureg(qureg); 102 | } 103 | 104 | 105 | void demo_auto() { 106 | 107 | reportStr("\n[auto (statevector)]"); 108 | 109 | Qureg pure = createQureg(10); 110 | reportQuregParams(pure); 111 | reportQureg(pure); 112 | destroyQureg(pure); 113 | 114 | reportStr("\n[auto (density matrix)]"); 115 | 116 | Qureg mixed = createDensityQureg(10); 117 | reportQuregParams(mixed); 118 | reportQureg(mixed); 119 | destroyQureg(mixed); 120 | } 121 | 122 | 123 | void demo_all() { 124 | 125 | reportStr("\n[all]"); 126 | 127 | int numQubits = 10; 128 | int isDensMatr = 0; 129 | 130 | int useDistrib = getQuESTEnv().isDistributed; 131 | int useGpuAccel = getQuESTEnv().isGpuAccelerated; 132 | int useMultithread = getQuESTEnv().isMultithreaded; 133 | 134 | // throws if both GPU and multithreaded 135 | Qureg qureg = createCustomQureg( 136 | numQubits, isDensMatr, 137 | useDistrib, useGpuAccel, useMultithread); 138 | 139 | reportQuregParams(qureg); 140 | reportQureg(qureg); 141 | destroyQureg(qureg); 142 | } 143 | 144 | 145 | 146 | /* 147 | * main 148 | */ 149 | 150 | 151 | int main() { 152 | 153 | initQuESTEnv(); 154 | QuESTEnv env = getQuESTEnv(); 155 | 156 | demo_serial(); 157 | 158 | if (env.isMultithreaded) 159 | demo_multithreaded(); 160 | 161 | if (env.isGpuAccelerated) 162 | demo_gpuAccelerated(); 163 | 164 | if (env.isDistributed) 165 | demo_distributed(); 166 | 167 | demo_auto(); 168 | demo_all(); // may throw 169 | 170 | finalizeQuESTEnv(); 171 | return 0; 172 | } 173 | -------------------------------------------------------------------------------- /cmake/FindCUQUANTUM.cmake: -------------------------------------------------------------------------------- 1 | #[=======================================================================[.rst: 2 | FindCuQuantum 3 | ------------- 4 | 5 | Attempts to find NVIDIA's cuQuantum library. 6 | Use CUQUANTUM_ROOT or CUQUANTUM_DIR to specify the prefix path. 7 | @author Oliver Thomson Brown 8 | 9 | 10 | Result Variables 11 | ^^^^^^^^^^^^^^^^ 12 | 13 | This will define the following variables: 14 | 15 | ``CUQUANTUM_FOUND`` 16 | True if libcuquantum is found. 17 | ``CUQUANTUM_INCLUDE_DIRS`` 18 | Include directories needed to use cuQuantum. 19 | ``CUQUANTUM_LIBRARIES`` 20 | Libraries needed to link to cuQuantum. 21 | ``CUQUANTUM_LIBRARY_DIRS`` 22 | Location of libraries needed to link to cuQuantum. 23 | 24 | #]=======================================================================] 25 | 26 | include(FindPackageHandleStandardArgs) 27 | 28 | find_package(PkgConfig QUIET) 29 | 30 | # CUQUANTUM_DIR is the CMake standard, but cuQuantum uses CUQUANTUM_ROOT 31 | # so we'll check if that's defined first 32 | # A user supplied CUQUANTUM_DIR always takes precedence 33 | if(NOT DEFINED CUQUANTUM_DIR) 34 | if(DEFINED ENV{CUQUANTUM_ROOT}) 35 | set(CUQUANTUM_DIR $ENV{CUQUANTUM_ROOT}) 36 | else() 37 | set(CUQUANTUM_DIR $ENV{CUQUANTUM_DIR}) 38 | endif() 39 | endif() 40 | 41 | if (NOT CUQUANTUM_FOUND) 42 | # Until cuQuantum exports pkgconfig files or a CMake target 43 | # we're going to have to do this the hard way... 44 | 45 | # Look for custatevec.h in an include directory below CUQUANTUM_DIR 46 | # (or CUQUANTUM_ROOT) 47 | find_path(CUQUANTUM_INCLUDE_PATH 48 | NAMES 49 | custatevec.h 50 | cudensitymat.h 51 | cutensornet.h 52 | PATHS 53 | ${CUQUANTUM_DIR}/include 54 | ) 55 | 56 | set(CUQUANTUM_INCLUDE_DIRS "${CUQUANTUM_INCLUDE_PATH}") 57 | 58 | find_path(CUQUANTUM_LIBRARY_DIRS 59 | NAMES 60 | libcustatevec.so 61 | libcudensitymat.so 62 | libcutensornet.so 63 | PATHS 64 | ${CUQUANTUM_DIR}/lib 65 | ${CUQUANTUM_DIR}/lib64 66 | ) 67 | 68 | if(CUQUANTUM_LIBRARY_DIRS) 69 | set(CUQUANTUM_LIBRARIES "custatevec;cudensitymat;cutensornet") 70 | endif() 71 | endif() 72 | 73 | find_package_handle_standard_args(CUQUANTUM 74 | REQUIRED_VARS 75 | CUQUANTUM_INCLUDE_DIRS 76 | CUQUANTUM_LIBRARIES 77 | CUQUANTUM_LIBRARY_DIRS 78 | REASON_FAILURE_MESSAGE 79 | "Try setting CUQUANTUM_DIR or CUQUANTUM_ROOT. Current values shown below. 80 | CUQUANTUM_DIR=${CUQUANTUM_DIR} 81 | CUQUANTUM_ROOT=${CUQUANTUM_ROOT}" 82 | ) 83 | 84 | if(CUQUANTUM_FOUND AND NOT TARGET CUQUANTUM::cuQuantum) 85 | add_library(CUQUANTUM::cuQuantum INTERFACE IMPORTED) 86 | target_include_directories(CUQUANTUM::cuQuantum INTERFACE ${CUQUANTUM_INCLUDE_DIRS}) 87 | target_link_libraries(CUQUANTUM::cuQuantum INTERFACE ${CUQUANTUM_LIBRARIES}) 88 | target_link_directories(CUQUANTUM::cuQuantum INTERFACE ${CUQUANTUM_LIBRARY_DIRS}) 89 | 90 | if(NOT TARGET CUQUANTUM::cuStateVec) 91 | add_library(CUQUANTUM::cuStateVec INTERFACE IMPORTED) 92 | target_include_directories(CUQUANTUM::cuStateVec INTERFACE ${CUQUANTUM_INCLUDE_DIRS}) 93 | target_link_directories(CUQUANTUM::cuStateVec INTERFACE ${CUQUANTUM_LIBRARY_DIRS}) 94 | target_link_libraries(CUQUANTUM::cuStateVec INTERFACE custatevec) 95 | endif() 96 | 97 | if(NOT TARGET CUQUANTUM::cuDensityMat) 98 | add_library(CUQUANTUM::cuDensityMat INTERFACE IMPORTED) 99 | target_include_directories(CUQUANTUM::cuDensityMat INTERFACE ${CUQUANTUM_INCLUDE_DIRS}) 100 | target_link_directories(CUQUANTUM::cuDensityMat INTERFACE ${CUQUANTUM_LIBRARY_DIRS}) 101 | target_link_libraries(CUQUANTUM::cuDensityMat INTERFACE cudensitymat) 102 | endif() 103 | 104 | if(NOT TARGET CUQUANTUM::cuTensorNet) 105 | add_library(CUQUANTUM::cuTensorNet INTERFACE IMPORTED) 106 | target_include_directories(CUQUANTUM::cuTensorNet INTERFACE ${CUQUANTUM_INCLUDE_DIRS}) 107 | target_link_directories(CUQUANTUM::cuTensorNet INTERFACE ${CUQUANTUM_LIBRARY_DIRS}) 108 | target_link_libraries(CUQUANTUM::cuTensorNet INTERFACE cutensornet) 109 | endif() 110 | endif() 111 | -------------------------------------------------------------------------------- /examples/isolated/initialising_superoperators.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of initialising a SuperOp in C11. Note that 3 | * MSVC's C11 (which is already weird) doesn't support 4 | * assigning any non-complex literal to complex variables 5 | * nor any complex arithmetic operators, so it doesn't 6 | * get to play with the other children. 7 | * 8 | * @author Tyson Jones 9 | */ 10 | 11 | #include "quest.h" 12 | #include 13 | 14 | #if !defined(_MSC_VER) 15 | 16 | 17 | 18 | void demo_createInlineSuperOp() { 19 | 20 | // inline literal without gross C99 compound-literal syntax (non-MSVC only) 21 | SuperOp a = createInlineSuperOp(1, { 22 | {1,2,3,4}, 23 | {5,0.0000000006-(10E-11) * 3.14i,7,8}, 24 | {9,10,11,12}, 25 | {13,14,15,16+1.23i} 26 | }); 27 | reportSuperOp(a); 28 | destroySuperOp(a); 29 | 30 | // unspecified elements default to 0 (C only) 31 | SuperOp b = createInlineSuperOp(3, { 32 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}, 33 | {5}, 34 | {7,8,9} 35 | }); 36 | reportSuperOp(b); 37 | destroySuperOp(b); 38 | } 39 | 40 | 41 | void demo_setInlineSuperOp() { 42 | 43 | // inline literal without gross C99 compound-literal syntax (non-MSVC only) 44 | SuperOp a = createSuperOp(1); 45 | setInlineSuperOp(a, 1, { 46 | {1,2,3,4}, 47 | {5,0.0000000006-(10E-11) * 3.14i,7,8}, 48 | {9,10,11,12}, 49 | {13,14,15,16+1.23i} 50 | }); 51 | reportSuperOp(a); 52 | destroySuperOp(a); 53 | 54 | // unspecified elements default to 0 (non-MSVC C only) 55 | SuperOp b = createSuperOp(3); 56 | setInlineSuperOp(b, 3, { 57 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}, 58 | {5}, 59 | {7,8,9} 60 | }); 61 | reportSuperOp(b); 62 | destroySuperOp(b); 63 | } 64 | 65 | 66 | void demo_setSuperOp() { 67 | 68 | // 2D compile-time array passed to VLA arg (non-MSVC C only) 69 | qcomp arr[4][4] = { 70 | {1,2,3,4}, 71 | {5,6,7,8}, 72 | {9,8,7,6}, 73 | {5,4,3,2} 74 | }; 75 | SuperOp a = createSuperOp(1); 76 | setSuperOp(a, arr); 77 | reportSuperOp(a); 78 | destroySuperOp(a); 79 | 80 | // 2D VLA (non-MSVC C only) 81 | int n = 2; 82 | int d = 1 << (2*n); 83 | qcomp elems[d][d]; 84 | for (int i=0; i VLA (non-MSVC only) 118 | SuperOp f = createSuperOp(1); 119 | setSuperOp(f, (qcomp[4][4]) { 120 | {1,2,3,4}, 121 | {1,2,3}, 122 | {1,2}, 123 | {1} 124 | }); 125 | reportSuperOp(f); 126 | destroySuperOp(f); 127 | 128 | // cleanup 129 | for (int i=0; i 17 | #include 18 | 19 | using std::string; 20 | 21 | 22 | 23 | /* 24 | * FIXED ENV-VAR NAMES 25 | */ 26 | 27 | 28 | namespace envvar_names { 29 | string PERMIT_NODES_TO_SHARE_GPU = "PERMIT_NODES_TO_SHARE_GPU"; 30 | string DEFAULT_VALIDATION_EPSILON = "DEFAULT_VALIDATION_EPSILON"; 31 | } 32 | 33 | 34 | 35 | /* 36 | * USER-OVERRIDABLE DEFAULT ENV-VAR VALUES 37 | */ 38 | 39 | 40 | namespace envvar_values { 41 | 42 | // by default, do not permit GPU sharing since it sabotages performance 43 | // and should only ever be carefully, deliberately enabled 44 | bool PERMIT_NODES_TO_SHARE_GPU = false; 45 | 46 | // by default, the initial validation epsilon (before being overriden 47 | // by users at runtime) should depend on qreal (i.e. FLOAT_PRECISION) 48 | qreal DEFAULT_VALIDATION_EPSILON = UNSPECIFIED_DEFAULT_VALIDATION_EPSILON; 49 | } 50 | 51 | 52 | // indicates whether envvars_validateAndLoadEnvVars() has been called 53 | bool global_areEnvVarsLoaded = false; 54 | 55 | 56 | 57 | /* 58 | * PRIVATE UTILITIES 59 | */ 60 | 61 | 62 | bool isEnvVarSpecified(string name) { 63 | 64 | // note var="" is considered unspecified, but var=" " is specified 65 | const char* ptr = std::getenv(name.c_str()); 66 | return (ptr != nullptr) && (ptr[0] != '\0'); 67 | } 68 | 69 | 70 | string getSpecifiedEnvVarValue(string name) { 71 | 72 | // assumes isEnvVarSpecified returned true 73 | // (calling getenv() a second time is fine) 74 | return std::string(std::getenv(name.c_str())); 75 | } 76 | 77 | 78 | void assertEnvVarsAreLoaded() { 79 | 80 | if (!global_areEnvVarsLoaded) 81 | error_envVarsNotYetLoaded(); 82 | } 83 | 84 | 85 | 86 | /* 87 | * PRIVATE BESPOKE ENV-VAR LOADERS 88 | * 89 | * which we have opted to not-yet make generic 90 | * (e.g. for each type) since YAGNI 91 | */ 92 | 93 | 94 | void validateAndSetWhetherGpuSharingIsPermitted(const char* caller) { 95 | 96 | // permit unspecified, falling back to default value 97 | string name = envvar_names::PERMIT_NODES_TO_SHARE_GPU; 98 | if (!isEnvVarSpecified(name)) 99 | return; 100 | 101 | // otherwise ensure value == '0' or '1' precisely (no whitespace) 102 | string value = getSpecifiedEnvVarValue(name); 103 | validate_envVarPermitNodesToShareGpu(value, caller); 104 | 105 | // overwrite default env-var value 106 | envvar_values::PERMIT_NODES_TO_SHARE_GPU = (value[0] == '1'); 107 | } 108 | 109 | 110 | void validateAndSetDefaultValidationEpsilon(const char* caller) { 111 | 112 | // permit unspecified, falling back to the hardcoded precision-specific default 113 | string name = envvar_names::DEFAULT_VALIDATION_EPSILON; 114 | if (!isEnvVarSpecified(name)) 115 | return; 116 | 117 | // otherwise, validate user passed a positive real integer (or zero) 118 | string value = getSpecifiedEnvVarValue(name); 119 | validate_envVarDefaultValidationEpsilon(value, caller); 120 | 121 | // overwrite default env-var value 122 | envvar_values::DEFAULT_VALIDATION_EPSILON = parser_parseReal(value); 123 | } 124 | 125 | 126 | 127 | /* 128 | * PUBLIC 129 | */ 130 | 131 | 132 | void envvars_validateAndLoadEnvVars(const char* caller) { 133 | 134 | // error if loaded twice since this indicates spaghetti 135 | if (global_areEnvVarsLoaded) 136 | error_envVarsAlreadyLoaded(); 137 | 138 | // load all env-vars 139 | validateAndSetWhetherGpuSharingIsPermitted(caller); 140 | validateAndSetDefaultValidationEpsilon(caller); 141 | 142 | // ensure no re-loading 143 | global_areEnvVarsLoaded = true; 144 | } 145 | 146 | 147 | bool envvars_getWhetherGpuSharingIsPermitted() { 148 | assertEnvVarsAreLoaded(); 149 | 150 | return envvar_values::PERMIT_NODES_TO_SHARE_GPU; 151 | } 152 | 153 | 154 | qreal envvars_getDefaultValidationEpsilon() { 155 | assertEnvVarsAreLoaded(); 156 | 157 | return envvar_values::DEFAULT_VALIDATION_EPSILON; 158 | } 159 | -------------------------------------------------------------------------------- /tests/utils/measure.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Testing utilities which evaluate measurements upon 3 | * reference qvector and qmatrix states. These are slow, 4 | * serial, un-optimised, defensively-designed routines. 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | #include "quest.h" 10 | 11 | #include "qvector.hpp" 12 | #include "qmatrix.hpp" 13 | #include "convert.hpp" 14 | #include "linalg.hpp" 15 | #include "macros.hpp" 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | using std::vector; 22 | 23 | 24 | 25 | /* 26 | * EXPECTATION VALUES 27 | */ 28 | 29 | 30 | qcomp getReferenceExpectationValue(qvector state, qmatrix observable) { 31 | DEMAND( state.size() == observable.size() ); 32 | 33 | return getInnerProduct(state, observable * state); 34 | } 35 | 36 | qcomp getReferenceExpectationValue(qmatrix state, qmatrix observable) { 37 | DEMAND( state.size() == observable.size() ); 38 | 39 | return getTrace(observable * state); 40 | } 41 | 42 | 43 | qcomp getRefExpecValInner(auto state, auto paulis) { 44 | 45 | int numQubits = getLog2(state.size()); 46 | qmatrix observable = getMatrix(paulis, numQubits); 47 | return getReferenceExpectationValue(state, observable); 48 | } 49 | qcomp getReferenceExpectationValue(qvector state, PauliStr str) { return getRefExpecValInner(state, str); } 50 | qcomp getReferenceExpectationValue(qmatrix state, PauliStr str) { return getRefExpecValInner(state, str); } 51 | qcomp getReferenceExpectationValue(qvector state, PauliStrSum sum) { return getRefExpecValInner(state, sum); } 52 | qcomp getReferenceExpectationValue(qmatrix state, PauliStrSum sum) { return getRefExpecValInner(state, sum); } 53 | 54 | 55 | 56 | /* 57 | * PROBABILITIES 58 | */ 59 | 60 | 61 | qreal getRefProbInner(auto& state, vector targets, vector outcomes) { 62 | DEMAND( getLog2(state.size()) > *std::max_element(targets.begin(), targets.end()) ); 63 | DEMAND( targets.size() == outcomes.size() ); 64 | 65 | // = Tr( (|o> targets, vector outcomes) { return getRefProbInner(state, targets, outcomes); } 72 | qreal getReferenceProbability(qmatrix state, vector targets, vector outcomes) { return getRefProbInner(state, targets, outcomes); } 73 | 74 | 75 | qreal getReferenceProbability(qvector state, qindex basisIndex) { 76 | DEMAND( basisIndex < (qindex) state.size() ); 77 | 78 | qcomp elem = state[basisIndex]; 79 | qreal prob = std::norm(elem); 80 | return prob; 81 | } 82 | 83 | qreal getReferenceProbability(qmatrix state, qindex basisIndex) { 84 | DEMAND( basisIndex < (qindex) state.size() ); 85 | 86 | qcomp elem = state[basisIndex][basisIndex]; 87 | qreal prob = std::real(elem); 88 | return prob; 89 | } 90 | 91 | 92 | vector getAllRefProbsInner(auto& state, vector targets) { 93 | 94 | vector out(getPow2(targets.size())); 95 | vector outcomes(targets.size()); 96 | 97 | for (size_t i=0; i getAllReferenceProbabilities(qvector state, vector targets) { return getAllRefProbsInner(state, targets); } 108 | vector getAllReferenceProbabilities(qmatrix state, vector targets) { return getAllRefProbsInner(state, targets); } 109 | 110 | 111 | qreal getReferenceProbability(qvector state) { 112 | 113 | qreal out = 0; 114 | for (auto& elem : state) 115 | out += std::norm(elem); 116 | 117 | return out; 118 | } 119 | 120 | qreal getReferenceProbability(qmatrix state) { 121 | 122 | qreal out = 0; 123 | for (size_t i=0; i's double-precision 5 | * literals, e.g. 6 | * 7 | * qcomp x = 1.3i 8 | * 9 | * However, such literals are forbidden when compiling in 'single' 10 | * precision; the compiler will not allow the double-precision 11 | * literal to be autocast to a float. If you want to use 12 | * precision-agnostic complex literals, you can use "_i", e.g. 13 | * 14 | * qcomp x = 1.3_i 15 | * 16 | * This file will use the latter literal. 17 | * 18 | * @author Tyson Jones 19 | */ 20 | 21 | #include "quest.h" 22 | #include 23 | #include 24 | 25 | using std::vector; 26 | 27 | 28 | 29 | void demo_createInlineKrausMap() { 30 | 31 | // inline literal 32 | KrausMap a = createInlineKrausMap(1, 3, { 33 | {{1,2},{3,4}}, 34 | {{5,5},{6,6}}, 35 | {{1_i,2_i},{-3_i,-4_i}} 36 | }); 37 | reportKrausMap(a); 38 | destroyKrausMap(a); 39 | 40 | // existing vector (C++ only) 41 | vector>> elems = { 42 | {{1,2},{3,4}}, 43 | {{5,5},{6,6}}, 44 | {{1_i,2_i},{-3_i,-4_i}} 45 | }; 46 | KrausMap b = createInlineKrausMap(1, 3, elems); 47 | reportKrausMap(b); 48 | destroyKrausMap(b); 49 | 50 | // must specify every element (unlike in C) otherwise runtime validation is triggered 51 | } 52 | 53 | 54 | void demo_setInlineKrausMap() { 55 | 56 | // inline literal; equivalent to to setKrausMap() but needed for consistencty with C API 57 | KrausMap a = createKrausMap(1, 3); 58 | setInlineKrausMap(a, 1, 3, { 59 | {{1,2_i},{3,4}}, 60 | {{5,5},{6_i,6}}, 61 | {{1_i,2_i},{-3_i,-4_i}} 62 | }); 63 | reportKrausMap(a); 64 | destroyKrausMap(a); 65 | 66 | // must specify every element (unlike in C) otherwise runtime validation is triggered 67 | } 68 | 69 | 70 | void demo_setKrausMap() { 71 | 72 | // inline literal (C++ only) 73 | KrausMap a = createKrausMap(1, 3); 74 | setKrausMap(a, { 75 | {{1,2},{3,4}}, 76 | {{5,5},{6,6}}, 77 | {{1_i,2_i},{-3_i,-4_i}} 78 | }); 79 | reportKrausMap(a); 80 | destroyKrausMap(a); 81 | 82 | // 3D vector (C++ only) 83 | vector>> vec { 84 | { 85 | {-9,-8, -8, -9}, 86 | {7, 7, 6, 6}, 87 | {0, -1, -2, -3}, 88 | {-4_i, -5_i, 0, 0} 89 | }, { 90 | {1,2,3,4}, 91 | {5,6,7,8}, 92 | {1,1,1,1}, 93 | {2,2,2,2} 94 | } 95 | }; 96 | KrausMap b = createKrausMap(2, 2); 97 | setKrausMap(b, vec); 98 | reportKrausMap(b); 99 | destroyKrausMap(b); 100 | 101 | // 3D nested pointers 102 | int nQb = 2; 103 | int nOps = 4; 104 | int dim = 1 << nQb; 105 | qcomp*** ptrs = (qcomp***) malloc(nOps * sizeof *ptrs); 106 | for (int n=0; n 13 | #include 14 | 15 | #include "tests/utils/qvector.hpp" 16 | #include "tests/utils/qmatrix.hpp" 17 | #include "tests/utils/compare.hpp" 18 | #include "tests/utils/convert.hpp" 19 | #include "tests/utils/evolve.hpp" 20 | #include "tests/utils/linalg.hpp" 21 | #include "tests/utils/lists.hpp" 22 | #include "tests/utils/macros.hpp" 23 | #include "tests/utils/random.hpp" 24 | 25 | using Catch::Matchers::ContainsSubstring; 26 | 27 | 28 | 29 | /* 30 | * UTILITIES 31 | */ 32 | 33 | #define TEST_CATEGORY \ 34 | LABEL_UNIT_TAG "[environment]" 35 | 36 | 37 | 38 | /** 39 | * TESTS 40 | * 41 | * @ingroup unitenv 42 | * @{ 43 | */ 44 | 45 | 46 | TEST_CASE( "initQuESTEnv", TEST_CATEGORY ) { 47 | 48 | SECTION( LABEL_CORRECTNESS ) { 49 | 50 | // cannot be meaningfully tested since env already active 51 | SUCCEED( ); 52 | } 53 | 54 | SECTION( LABEL_VALIDATION ) { 55 | 56 | REQUIRE_THROWS_WITH( initQuESTEnv(), ContainsSubstring( "already been initialised") ); 57 | 58 | // cannot automatically check other validations, such as: 59 | // - has env been previously initialised then finalised? 60 | // - is env distributed over power-of-2 nodes? 61 | // - are environment-variables valid? 62 | // - is max 1 MPI process bound to each GPU? 63 | // - is GPU compatible with cuQuantum (if enabled)? 64 | } 65 | } 66 | 67 | 68 | TEST_CASE( "initCustomQuESTEnv", TEST_CATEGORY ) { 69 | 70 | SECTION( LABEL_CORRECTNESS ) { 71 | 72 | // cannot be meaningfully tested since env already active 73 | SUCCEED( ); 74 | } 75 | 76 | SECTION( LABEL_VALIDATION ) { 77 | 78 | REQUIRE_THROWS_WITH( initCustomQuESTEnv(0,0,0), ContainsSubstring( "already been initialised") ); 79 | 80 | // cannot check arguments since env-already-initialised 81 | // validation is performed first 82 | } 83 | } 84 | 85 | 86 | TEST_CASE( "finalizeQuESTEnv", TEST_CATEGORY ) { 87 | 88 | SECTION( LABEL_CORRECTNESS ) { 89 | 90 | // cannot be meaningfully tested since calling 91 | // mid-tests will break subsequent testing 92 | SUCCEED( ); 93 | } 94 | 95 | SECTION( LABEL_VALIDATION ) { 96 | 97 | // cannot be validated since calling it once 98 | // is always valid but would break subsequent tests 99 | SUCCEED( ); 100 | } 101 | } 102 | 103 | 104 | TEST_CASE( "syncQuESTEnv", TEST_CATEGORY ) { 105 | 106 | SECTION( LABEL_CORRECTNESS ) { 107 | 108 | // always legal to call 109 | REQUIRE_NOTHROW( syncQuESTEnv() ); 110 | } 111 | 112 | SECTION( LABEL_VALIDATION ) { 113 | 114 | // cannot test validation (that env is already 115 | // created) since we cannot call before initQuESTEnv 116 | SUCCEED( ); 117 | } 118 | } 119 | 120 | 121 | TEST_CASE( "isQuESTEnvInit", TEST_CATEGORY ) { 122 | 123 | SECTION( LABEL_CORRECTNESS ) { 124 | 125 | // cannot test for other outcome 126 | REQUIRE( isQuESTEnvInit() == 1 ); 127 | } 128 | 129 | SECTION( LABEL_VALIDATION ) { 130 | 131 | // performs no validation 132 | SUCCEED( ); 133 | } 134 | } 135 | 136 | 137 | TEST_CASE( "getQuESTEnv", TEST_CATEGORY ) { 138 | 139 | SECTION( LABEL_CORRECTNESS ) { 140 | 141 | QuESTEnv env = getQuESTEnv(); 142 | 143 | REQUIRE( (env.isMultithreaded == 0 || env.isMultithreaded == 1) ); 144 | REQUIRE( (env.isGpuAccelerated == 0 || env.isGpuAccelerated == 1) ); 145 | REQUIRE( (env.isDistributed == 0 || env.isDistributed == 1) ); 146 | REQUIRE( (env.isCuQuantumEnabled == 0 || env.isCuQuantumEnabled == 1) ); 147 | REQUIRE( (env.isGpuSharingEnabled == 0 || env.isGpuSharingEnabled == 1) ); 148 | 149 | REQUIRE( env.rank >= 0 ); 150 | REQUIRE( env.numNodes >= 0 ); 151 | 152 | if (!env.isDistributed) { 153 | REQUIRE( env.rank == 0 ); 154 | REQUIRE( env.numNodes == 1 ); 155 | } 156 | 157 | bool isNumNodesPow2 = ((env.numNodes & (env.numNodes - 1)) == 0); 158 | REQUIRE( isNumNodesPow2 ); 159 | } 160 | 161 | SECTION( LABEL_VALIDATION ) { 162 | 163 | // performs no validation 164 | SUCCEED( ); 165 | } 166 | } 167 | 168 | 169 | /** @} (end defgroup) */ 170 | 171 | 172 | 173 | /** 174 | * @todo 175 | * UNTESTED FUNCTIONS 176 | */ 177 | 178 | void reportQuESTEnv(); 179 | -------------------------------------------------------------------------------- /tests/utils/convert.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Testing utilities for converting QuEST API structures 3 | * (like Qureg, CompMatr, PauliStr) to/from testing types 4 | * (like qvector and qmatrix). 5 | * 6 | * @author Tyson Jones 7 | */ 8 | 9 | #include "qvector.hpp" 10 | #include "qmatrix.hpp" 11 | #include "linalg.hpp" 12 | #include "macros.hpp" 13 | #include "lists.hpp" 14 | 15 | #include "quest.h" 16 | 17 | #include 18 | using std::is_same_v; 19 | 20 | #include 21 | using std::vector; 22 | 23 | 24 | 25 | /* 26 | * INTERNAL QUEST FUNCTIONS 27 | */ 28 | 29 | extern int paulis_getPauliAt(PauliStr str, int ind); 30 | extern int paulis_getIndOfLefmostNonIdentityPauli(PauliStr str); 31 | extern int paulis_getIndOfLefmostNonIdentityPauli(PauliStrSum sum); 32 | 33 | 34 | 35 | /* 36 | * TO QUREG 37 | */ 38 | 39 | 40 | void setQuregToReference(Qureg qureg, qvector vector) { 41 | DEMAND( !qureg.isDensityMatrix ); 42 | DEMAND( qureg.numAmps == (qindex) vector.size() ); 43 | 44 | setQuregAmps(qureg, 0, vector.data(), vector.size()); 45 | } 46 | 47 | 48 | void setQuregToReference(Qureg qureg, qmatrix matrix) { 49 | DEMAND( qureg.isDensityMatrix ); 50 | DEMAND( getPow2(qureg.numQubits) == (qindex) matrix.size() ); 51 | 52 | qindex numRows = 1; 53 | qindex numCols = getPow2(qureg.numQubits); 54 | 55 | for (size_t r=0; r 101 | qcomp getElem(T m, size_t r, size_t c) { 102 | 103 | if constexpr (is_same_v || is_same_v) 104 | return m.cpuElems[r][c]; 105 | 106 | if constexpr (is_same_v || is_same_v) 107 | return m.elems[r][c]; 108 | 109 | if constexpr (is_same_v) 110 | return (r==c)? m.cpuElems[r] : 0; 111 | 112 | if constexpr (is_same_v || is_same_v) 113 | return (r==c)? m.elems[r] : 0; 114 | } 115 | 116 | 117 | template 118 | qmatrix getMatrixInner(T m) { 119 | 120 | qindex dim = (is_same_v)? 121 | getPow2(2*m.numQubits): 122 | getPow2( m.numQubits); 123 | 124 | qmatrix out = getZeroMatrix(dim); 125 | 126 | for (size_t r=0; r(m, r, c); 129 | 130 | return out; 131 | } 132 | 133 | 134 | qmatrix getMatrix(CompMatr1 m) { return getMatrixInner(m); } 135 | qmatrix getMatrix(CompMatr2 m) { return getMatrixInner(m); } 136 | qmatrix getMatrix(CompMatr m) { return getMatrixInner(m); } 137 | qmatrix getMatrix(DiagMatr1 m) { return getMatrixInner(m); } 138 | qmatrix getMatrix(DiagMatr2 m) { return getMatrixInner(m); } 139 | qmatrix getMatrix(DiagMatr m) { return getMatrixInner(m); } 140 | qmatrix getMatrix(SuperOp m) { return getMatrixInner(m); } 141 | 142 | 143 | 144 | /* 145 | * FROM PAULI STRING 146 | */ 147 | 148 | 149 | qmatrix getMatrix(PauliStr str, vector targs) { 150 | DEMAND( targs.size() >= 1 ); 151 | 152 | qmatrix out = getIdentityMatrix(1); 153 | 154 | for (auto t : targs) { 155 | int ind = paulis_getPauliAt(str, t); 156 | qmatrix matr = getPauliMatrix(ind); 157 | out = getKroneckerProduct(matr, out); 158 | } 159 | 160 | return out; 161 | } 162 | 163 | 164 | qmatrix getMatrix(PauliStr str, int numQubits) { 165 | DEMAND( numQubits >= paulis_getIndOfLefmostNonIdentityPauli(str) ); 166 | 167 | return getMatrix(str, getRange(numQubits)); 168 | } 169 | 170 | 171 | qmatrix getMatrix(PauliStrSum sum, int numQubits) { 172 | DEMAND( sum.numTerms > 0 ); 173 | DEMAND( numQubits >= paulis_getIndOfLefmostNonIdentityPauli(sum) ); 174 | 175 | qmatrix out = getZeroMatrix(getPow2(numQubits)); 176 | 177 | for (qindex i=0; i 9 | 10 | 11 | ## 🧭  Development 12 | 13 | 14 | ### 2025 15 | 16 | - Oliver Brown of EPCC leads QuEST development (`v4.3`+) 17 | 18 | 19 | ### 2018 20 | 21 | - Tyson Jones of QTechTheory leads QuEST development (`v1.1` - `v4.2`) 22 | 23 | 24 | ### 2017 25 | 26 | - Mihai Duta and Simon Benjamin begin QuEST development (`v0.1` - `v0.9`) 27 | - Anna (Ania) Brown leads QuEST development (`v0.9` - `v1.0`) 28 | 29 | 30 | 31 | ## 🏆  Recognitions 32 | 33 | 34 | ### 2025 35 | 36 | - QuEST is an invited project to [unitaryHACK 2025](https://unitaryhack.dev/) with challenges [#600](https://github.com/QuEST-Kit/QuEST/issues/600), [#594](https://github.com/QuEST-Kit/QuEST/issues/594), [#599](https://github.com/QuEST-Kit/QuEST/issues/599), [#598](https://github.com/QuEST-Kit/QuEST/issues/598), [#596](https://github.com/QuEST-Kit/QuEST/issues/596) and [#595](https://github.com/QuEST-Kit/QuEST/issues/595) 37 | - QuEST is a highlighted integration on the NVIDIA [cuQuantum site](https://developer.nvidia.com/cuquantum-sdk) 38 | 39 | 40 | ### 2024 41 | 42 | - QuEST ranks 3rd in Quantum Insider's [Top 63 Quantum Computer Simulators for 2024](https://thequantuminsider.com/2022/06/14/top-63-quantum-computer-simulators-for-2022/) 43 | 44 | 45 | ### 2023 46 | 47 | - QuESTlink wins a [Wolfram Innovator Award](https://blog.wolfram.com/2023/11/02/announcing-the-2023-wolfram-innovator-award-winners/) 48 | 49 | 50 | ### 2021 51 | 52 | - QuEST features in the final challenge of the [ASC20-21 Student Supercomputer Challenge](https://www.businesswire.com/news/home/20210127005355/en/28-University-Teams-from-Around-the-World-Advance-to-the-Finals-of-the-ASC20-21-Student-Supercomputer-Challenge) 53 | 54 | 55 | ### 2020 56 | 57 | - QuEST's [whitepaper](https://www.nature.com/articles/s41598-019-47174-9) ranks 11th in Scientific Reports' [Top 100 in Physics](https://www.nature.com/collections/ecehgdfcba) 58 | 59 | 60 | 61 | ## 💪  Major features 62 | 63 | 64 | ### 2025 65 | 66 | #### [v4.2](https://github.com/QuEST-Kit/QuEST/releases/tag/v4.2.0) 67 | 68 | - multi-controlled Trotter circuits 69 | - non-unitary Trotter circuits (permitting e.g. imaginary-time evolution) 70 | - noisy time evolution via the Lindbladian 71 | - customisation environment variables 72 | - restored NUMA awareness (woops) 73 | 74 | #### [v4.0](https://github.com/QuEST-Kit/QuEST/releases/tag/v4.0.0) 75 | 76 | - multi-GPU deployment 77 | - automatic deployment 78 | - partial tracing 79 | - multi-qubit projectors 80 | - distance measures 81 | - numerical tolerance control 82 | 83 | ### 2023 84 | 85 | #### [v3.7](https://github.com/QuEST-Kit/QuEST/releases/tag/v3.7.0) 86 | 87 | - cuQuantum integration 88 | 89 | #### [v3.6](https://github.com/QuEST-Kit/QuEST/releases/tag/v3.6.0) 90 | 91 | - AMD GPU support 92 | - diagonal matrices 93 | 94 | 95 | ### 2021 96 | 97 | #### [v3.4](https://github.com/QuEST-Kit/QuEST/releases/tag/v3.4.0) 98 | 99 | - MSVC (Windows) support 100 | 101 | #### [v3.3](https://github.com/QuEST-Kit/QuEST/releases/tag/v3.3.0) 102 | 103 | - all-outcome probabilities 104 | - multi-controlled Pauli rotations 105 | - custom phase functions 106 | - QFT 107 | 108 | 109 | ### 2020 110 | 111 | #### [v3.2](https://github.com/QuEST-Kit/QuEST/releases/tag/v3.2.0) 112 | 113 | - Trotter-Suzuki circuits 114 | - full-state diagonal operators 115 | 116 | #### [v3.1](https://github.com/QuEST-Kit/QuEST/releases/tag/v3.1.0) 117 | 118 | - unit tests 119 | - continuous integration 120 | 121 | #### [v3.0](https://github.com/QuEST-Kit/QuEST/releases/tag/3.0.0) 122 | 123 | - general any-sized matrices 124 | - general any-sized Kraus maps 125 | - inhomogeneous Pauli channels 126 | - multi-Pauli expectation values 127 | - multi-target Pauli rotations 128 | - any-controlled operations 129 | - density-matrix inner products 130 | - custom error handling 131 | 132 | 133 | ### 2019 134 | 135 | #### [v2.1](https://github.com/QuEST-Kit/QuEST/releases/tag/2.1.0) 136 | 137 | - CMake build 138 | - amplitude damping channel 139 | 140 | 141 | ### 2018 142 | 143 | #### [v2.0](https://github.com/QuEST-Kit/QuEST/releases/tag/v2.0.0) 144 | 145 | - density matrices 146 | - dephasing channels 147 | - depolarising channels 148 | - purity calculation 149 | - fidelity calculation 150 | - QASM generation 151 | - input validation 152 | 153 | #### [v1.1](https://github.com/QuEST-Kit/QuEST/releases/tag/v1.1.0) 154 | 155 | - `C` and `C++` agnosticism 156 | - unification of CPU and GPU backends 157 | 158 | #### [v1.0](https://github.com/QuEST-Kit/QuEST/releases/tag/v1.0.0) 159 | 160 | - controlled axis rotations -------------------------------------------------------------------------------- /.github/scripts/setup_cuda.ps1: -------------------------------------------------------------------------------- 1 | # @file 2 | # A script to download CUDA and install it upon a Windows 3 | # virtual machine, as an alternative to the cuda-toolkit 4 | # github action (https://github.com/Jimver/cuda-toolkit) 5 | # which experienced a regression in v12 as documented 6 | # here: https://github.com/Jimver/cuda-toolkit/issues/382 7 | # 8 | # This file was taken from repository Vibe, written by 9 | # @author thewh1teagle (github.com/thewh1teagle) 10 | 11 | 12 | $CUDA_VERSION_FULL = $env:INPUT_CUDA_VERSION # v12.5.0 or v11.8.0 13 | 14 | # Make sure CUDA_VERSION_FULL is set and valid, otherwise error. 15 | # Validate CUDA version, extracting components via regex 16 | $cuda_ver_matched = $CUDA_VERSION_FULL -match "^(?[1-9][0-9]*)\.(?[0-9]+)\.(?[0-9]+)$" 17 | if(-not $cuda_ver_matched){ 18 | Write-Output "Invalid CUDA version specified, .. required. '$CUDA_VERSION_FULL'." 19 | exit 1 20 | } 21 | $CUDA_MAJOR=$Matches.major 22 | $CUDA_MINOR=$Matches.minor 23 | $CUDA_PATCH=$Matches.patch 24 | 25 | Write-Output "Selected CUDA version: $CUDA_VERSION_FULL" 26 | 27 | $src = "cuda" 28 | $dst = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$($CUDA_MAJOR).$($CUDA_MINOR)" 29 | $installer = "cuda.exe" 30 | 31 | if ($CUDA_VERSION_FULL -eq "12.5.0") { 32 | $downloadUrl = "https://developer.download.nvidia.com/compute/cuda/12.5.0/local_installers/cuda_12.5.0_555.85_windows.exe" 33 | } elseif ($CUDA_VERSION_FULL -eq "11.8.0") { 34 | $downloadUrl = "https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda_11.8.0_522.06_windows.exe" 35 | } else { 36 | Write-Output "Unsupported CUDA version specified" 37 | exit 1 38 | } 39 | 40 | # Download cuda 41 | Write-Output "Downloading CUDA from: $downloadUrl" 42 | if (-not (Test-Path -Path $installer)) { 43 | Write-Output "Downloading CUDA installer..." 44 | # If the file does not exist, download it 45 | & "C:\msys64\usr\bin\wget" $downloadUrl -O $installer -q 46 | } 47 | 48 | # Extract cuda 49 | if (-not (Test-Path -Path $src -Type Container)) { 50 | # Extract CUDA using 7-Zip 51 | Write-Output "Extracting CUDA using 7-Zip..." 52 | mkdir "$src" 53 | & 'C:\Program Files\7-Zip\7z' x $installer -o"$src" 54 | } 55 | 56 | # Create destination directory if it doesn't exist 57 | if (-Not (Test-Path -Path $dst)) { 58 | Write-Output "Creating destination directory: $dst" 59 | New-Item -Path $dst -ItemType Directory 60 | } 61 | 62 | # Get directories to process from the source path 63 | $directories = Get-ChildItem -Directory -Path $src 64 | $whitelist = @("CUDA_Toolkit_Release_Notes.txt", "DOCS", "EULA.txt", "LICENSE", "README", "version.json") 65 | 66 | foreach ($dir in $directories) { 67 | # Get all subdirectories and files in the current directory 68 | $items = Get-ChildItem -Path (Join-Path $src $dir.Name) 69 | 70 | foreach ($item in $items) { 71 | if ($item.PSIsContainer) { 72 | # If the item is a directory, copy its contents 73 | Write-Output "Copying contents of directory $($item.FullName) to $dst" 74 | Copy-Item -Path "$($item.FullName)\*" -Destination $dst -Recurse -Force 75 | } else { 76 | if ($whitelist -contains $item.Name) { 77 | Write-Output "Copying file $($item.FullName) to $dst" 78 | Copy-Item -Path $item.FullName -Destination $dst -Force 79 | } 80 | } 81 | } 82 | } 83 | 84 | # Add msbuild cuda extensions 85 | $msBuildExtensions = (Get-ChildItem "$src\visual_studio_integration\CUDAVisualStudioIntegration\extras\visual_studio_integration\MSBuildExtensions").fullname 86 | (Get-ChildItem 'C:\Program Files\Microsoft Visual Studio\2022\*\MSBuild\Microsoft\VC\*\BuildCustomizations').FullName | ForEach-Object { 87 | $destination = $_ 88 | $msBuildExtensions | ForEach-Object { 89 | $extension = $_ 90 | Copy-Item $extension -Destination $destination -Force 91 | Write-Output "Copied $extension to $destination" 92 | } 93 | } 94 | 95 | # Add to Github env 96 | Write-Output "Setting environment variables for GitHub Actions..." 97 | 98 | Write-Output "CUDA_PATH=$dst" 99 | Write-Output "CUDA_PATH_V$($CUDA_MAJOR)_$($CUDA_MINOR)=$dst" 100 | Write-Output "CUDA_PATH_VX_Y=CUDA_PATH_V$($CUDA_MAJOR)_$($CUDA_MINOR)" 101 | Write-Output "CUDA_VERSION=$CUDA_VERSION_FULL" 102 | 103 | Write-Output "CUDA_PATH=$dst" >> $env:GITHUB_ENV 104 | Write-Output "CUDA_PATH_V$($CUDA_MAJOR)_$($CUDA_MINOR)=$dst" >> $env:GITHUB_ENV 105 | Write-Output "CUDA_PATH_VX_Y=CUDA_PATH_V$($CUDA_MAJOR)_$($CUDA_MINOR)" >> $env:GITHUB_ENV 106 | Write-Output "CudaToolkitDir=$dst" >> $env:GITHUB_ENV 107 | Write-Output "CMAKE_CUDA_COMPILER=$dst\bin\nvcc.exe" >> $env:GITHUB_ENV 108 | Write-Output "NVCC_APPEND_FLAGS=-allow-unsupported-compiler" >> $env:GITHUB_ENV 109 | 110 | Write-Output "CUDA_VERSION=$CUDA_VERSION_FULL" >> $env:GITHUB_ENV 111 | Write-Output "Setup completed." -------------------------------------------------------------------------------- /quest/include/precision.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * The precision of QuEST's numerical types, some of which 3 | * are overridable and others of which are intendedly fixed. 4 | * 5 | * @author Tyson Jones 6 | * @author Milos Prokop (patched trig overloads in v3) 7 | * 8 | * @defgroup precision Precision 9 | * @ingroup api 10 | * @brief Macros for controlling QuEST's numerical precision. 11 | * @{ 12 | */ 13 | 14 | #ifndef PRECISION_H 15 | #define PRECISION_H 16 | 17 | #include "quest/include/config.h" 18 | 19 | 20 | 21 | /* 22 | * STATE-INDEXING TYPE 23 | */ 24 | 25 | // can be (for example) int, long, long long, unsigned, long unsigned, long long unsigned. 26 | // We make sure that the backend never relies upon being able to represent negative 27 | // indices (e.g. as flags) since that would require a strictly signed type. Note this precision 28 | // determines qindex which is user-facing so using unsigned types opens the users to the 29 | // risks of underflowing. Since we never store large collections of this type, there is little 30 | // benefit in shrinking the type size and facing the associated precision risks. Similarly, 31 | // there is little benefit in making it larger since a 'long long int' can represent 62 qubits, 32 | // which is already well beyond simulability, requiring 64 EiB total at double precision. 33 | // Still, we use a #define, rather than a typedef, so that the value can be compile-time overridden. 34 | 35 | /// @neverdoced 36 | #define INDEX_TYPE long long int 37 | 38 | // spoofing above macro as const to doc 39 | #if 0 40 | 41 | /// @notyetdoced 42 | /// @macrodoc 43 | typedef long long int INDEX_TYPE; 44 | 45 | #endif 46 | 47 | 48 | 49 | /* 50 | * PAULI STRING INDEXING TYPE 51 | */ 52 | 53 | // should never be changed; it is unsigned due to its use in extensive bitwise processing 54 | // (no overflow risks since the API does not use this type), and its precision constrains 55 | // the number of Paulis which can be specified in a PauliStr. Specifically, PauliStr stores 56 | // two PAULI_MASK_TYPE instances, each of which are interpreted as half the digits of a 57 | // base-4 numeral encoding the Pauli string. A single 64-bit 'long long unsigned' can ergo 58 | // specify only 32 qubits, whereas two can specify more qubits (64) than we can simulate. 59 | // This type is defined purely to avoid littering the source with explicit typing. 60 | 61 | /// @neverdoced 62 | #define PAULI_MASK_TYPE long long unsigned int 63 | 64 | // spoofing above macro as typedef to doc 65 | #if 0 66 | 67 | /// @notyetdoced 68 | /// @macrodoc 69 | typedef long long unsigned int PAULI_MASK_TYPE; 70 | 71 | #endif 72 | 73 | 74 | 75 | /* 76 | * RE-CONFIGURABLE FLOATING-POINT PRECISION 77 | */ 78 | 79 | // validate precision is 1 (float), 2 (double) or 4 (long double) 80 | #if ! (FLOAT_PRECISION == 1 || FLOAT_PRECISION == 2 || FLOAT_PRECISION == 4) 81 | #error "FLOAT_PRECISION must be 1 (float), 2 (double) or 4 (long double)" 82 | #endif 83 | 84 | // infer floating-point type from precision 85 | #if FLOAT_PRECISION == 1 86 | #define FLOAT_TYPE float 87 | #elif FLOAT_PRECISION == 2 88 | #define FLOAT_TYPE double 89 | #elif FLOAT_PRECISION == 4 90 | #define FLOAT_TYPE long double 91 | #endif 92 | 93 | // spoofing above macros as typedefs and consts to doc 94 | #if 0 95 | 96 | /// @notyetdoced 97 | /// @macrodoc 98 | /// 99 | /// (note this macro is informed by the FLOAT_PRECISION CMake variable) 100 | const int FLOAT_PRECISION = 2; 101 | 102 | /// @notyetdoced 103 | /// @macrodoc 104 | /// 105 | /// (note this macro is informed by the FLOAT_PRECISION CMake variable) 106 | typedef double int FLOAT_TYPE; 107 | 108 | #endif 109 | 110 | 111 | 112 | /* 113 | * CHECK PRECISION TYPES ARE COMPATIBLE WITH DEPLOYMENT 114 | */ 115 | 116 | #if COMPILE_CUDA && (FLOAT_PRECISION == 4) 117 | #error "A quad floating-point precision (FLOAT_PRECISION=4, i.e. long double) is not supported by GPU deployment" 118 | #endif 119 | 120 | 121 | 122 | /* 123 | * DEFAULT VALIDATION PRECISION 124 | * 125 | * which is pre-run-time overridable by specifying the corresponding environment variable. 126 | */ 127 | 128 | #if FLOAT_PRECISION == 1 129 | #define UNSPECIFIED_DEFAULT_VALIDATION_EPSILON 1E-5 130 | 131 | #elif FLOAT_PRECISION == 2 132 | #define UNSPECIFIED_DEFAULT_VALIDATION_EPSILON 1E-12 133 | 134 | #elif FLOAT_PRECISION == 4 135 | #define UNSPECIFIED_DEFAULT_VALIDATION_EPSILON 1E-13 136 | 137 | #endif 138 | 139 | 140 | 141 | /* 142 | * PRECISION-AGNOSTIC CONVENIENCE MACROS 143 | */ 144 | 145 | #if FLOAT_PRECISION == 1 146 | #define QREAL_FORMAT_SPECIFIER "%.8g" 147 | 148 | #elif FLOAT_PRECISION == 2 149 | #define QREAL_FORMAT_SPECIFIER "%.14g" 150 | 151 | #elif FLOAT_PRECISION == 4 152 | #define QREAL_FORMAT_SPECIFIER "%.17Lg" 153 | 154 | #endif 155 | 156 | // spoofing above macros as typedefs and consts to doc 157 | #if 0 158 | 159 | /// @notyetdoced 160 | /// @macrodoc 161 | const char* QREAL_FORMAT_SPECIFIER = "%.14g"; 162 | 163 | #endif 164 | 165 | 166 | 167 | #endif // PRECISION_H 168 | 169 | /** @} */ // (end file-wide doxygen defgroup) 170 | -------------------------------------------------------------------------------- /quest/src/comm/comm_config.cpp: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Functions for querying the distributed configuration 3 | * using the MPI interface, agnostically to the specific 4 | * implementation (like OpenMPI vs MPICH). These functions 5 | * are callable even when MPI has not been compiled/linked. 6 | * 7 | * Note that even when COMPILE_MPI=1, the user may have 8 | * disabled distribution when creating the QuEST environment 9 | * at runtime. Ergo we use comm_isInit() to determine whether 10 | * functions should invoke the MPI API. 11 | * 12 | * @author Tyson Jones 13 | */ 14 | 15 | #include "quest/include/config.h" 16 | #include "quest/include/types.h" 17 | 18 | #include "quest/src/comm/comm_config.hpp" 19 | #include "quest/src/core/errors.hpp" 20 | 21 | #if COMPILE_MPI 22 | #include 23 | #endif 24 | 25 | 26 | 27 | /* 28 | * WARN ABOUT CUDA-AWARENESS 29 | */ 30 | 31 | #if COMPILE_MPI && COMPILE_CUDA 32 | 33 | // this check is OpenMPI specific 34 | #ifdef OPEN_MPI 35 | #include 36 | 37 | // #warning command is always recognised (OpenMPI is not Windows compatible) 38 | #ifndef MPIX_CUDA_AWARE_SUPPORT 39 | #warning "Could not ascertain whether MPI is CUDA-aware, so we will assume it is not. This means inter-GPU communication will be slowly routed through the CPU/RAM." 40 | #elif !MPIX_CUDA_AWARE_SUPPORT 41 | #warning "MPI compiler is not CUDA-aware, so inter-GPU communication will be slowly routed through the CPU/RAM" 42 | #endif 43 | #endif 44 | 45 | /// @todo check whether MPICH is CUDA-aware 46 | /// beware MSVC cannot parse #warning, and 47 | /// Intel MPI would crash (but not MSMPI?) 48 | 49 | #endif 50 | 51 | 52 | 53 | /* 54 | * MPI ENVIRONMENT MANAGEMENT 55 | * all of which is safely callable in non-distributed mode 56 | */ 57 | 58 | 59 | bool comm_isMpiCompiled() { 60 | return (bool) COMPILE_MPI; 61 | } 62 | 63 | 64 | bool comm_isMpiGpuAware() { 65 | 66 | /// @todo these checks may be OpenMPI specific, so that 67 | /// non-OpenMPI MPI compilers are always dismissed as 68 | /// not being CUDA-aware. Check e.g. MPICH method! 69 | 70 | // definitely not GPU-aware if compiler declares it is not 71 | #if defined(MPIX_CUDA_AWARE_SUPPORT) && ! MPIX_CUDA_AWARE_SUPPORT 72 | return false; 73 | #endif 74 | 75 | // check CUDA-awareness at run-time if we know it's principally supported 76 | #if defined(MPIX_CUDA_AWARE_SUPPORT) 77 | return (bool) MPIX_Query_cuda_support(); 78 | #endif 79 | 80 | // if we can't ascertain CUDA-awareness, just assume no to avoid seg-fault 81 | return false; 82 | } 83 | 84 | 85 | bool comm_isInit() { 86 | #if COMPILE_MPI 87 | 88 | // safely callable before MPI initialisation, but NOT after comm_end() 89 | int isInit; 90 | MPI_Initialized(&isInit); 91 | return (bool) isInit; 92 | 93 | #else 94 | 95 | // obviously MPI is never initialised if not even compiled 96 | return false; 97 | #endif 98 | } 99 | 100 | 101 | void comm_init() { 102 | #if COMPILE_MPI 103 | 104 | // error if attempting re-initialisation 105 | if (comm_isInit()) 106 | error_commAlreadyInit(); 107 | 108 | MPI_Init(NULL, NULL); 109 | 110 | #endif 111 | } 112 | 113 | 114 | void comm_end() { 115 | #if COMPILE_MPI 116 | 117 | // gracefully permit comm_end() before comm_init(), as input validation can trigger 118 | if (!comm_isInit()) 119 | return; 120 | 121 | MPI_Barrier(MPI_COMM_WORLD); 122 | MPI_Finalize(); 123 | 124 | #endif 125 | } 126 | 127 | 128 | int comm_getRank() { 129 | #if COMPILE_MPI 130 | 131 | // if distribution was not runtime enabled (or a validation error was 132 | // triggered), every node (if many MPI processes were launched) 133 | // believes it is the root rank 134 | if (!comm_isInit()) 135 | return ROOT_RANK; 136 | 137 | int rank; 138 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 139 | return rank; 140 | 141 | #else 142 | 143 | // if MPI isn't compiled, we're definitely non-distributed; return main rank 144 | return ROOT_RANK; 145 | #endif 146 | } 147 | 148 | 149 | bool comm_isRootNode(int rank) { 150 | return rank == ROOT_RANK; 151 | } 152 | bool comm_isRootNode() { 153 | return comm_isRootNode(comm_getRank()); 154 | } 155 | 156 | 157 | int comm_getNumNodes() { 158 | #if COMPILE_MPI 159 | 160 | // if distribution was not runtime enabled (or a validation error was 161 | // triggered), every node (if many MPI processes were launched) 162 | // believes it is the one and only node 163 | if (!comm_isInit()) 164 | return 1; 165 | 166 | int numNodes; 167 | MPI_Comm_size(MPI_COMM_WORLD, &numNodes); 168 | return numNodes; 169 | 170 | #else 171 | 172 | // if MPI isn't compiled, we're definitely non-distributed; return single node 173 | return 1; 174 | #endif 175 | } 176 | 177 | 178 | void comm_sync() { 179 | #if COMPILE_MPI 180 | 181 | // gracefully handle when not distributed, needed by e.g. pre-MPI-setup validation 182 | if (!comm_isInit()) 183 | return; 184 | 185 | MPI_Barrier(MPI_COMM_WORLD); 186 | #endif 187 | } 188 | -------------------------------------------------------------------------------- /examples/isolated/initialising_krausmaps.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Examples of initialising KrausMaps in C11. Note that 3 | * MSVC's C11 (which is already weird) doesn't support 4 | * assigning any non-complex literal to complex variables 5 | * nor any complex arithmetic operators, so it doesn't 6 | * get to play with the other children. 7 | * 8 | * @author Tyson Jones 9 | */ 10 | 11 | #include "quest.h" 12 | #include 13 | 14 | #if !defined(_MSC_VER) 15 | 16 | 17 | 18 | void demo_createInlineKrausMap() { 19 | 20 | // inline literal without C99 compound-literal syntax (non-MSVC only) 21 | KrausMap a = createInlineKrausMap(1, 3, { 22 | {{1,2},{3,4}}, 23 | {{5,5},{6,6}}, 24 | {{1i,2i},{-3i,-4i}} 25 | }); 26 | reportKrausMap(a); 27 | destroyKrausMap(a); 28 | 29 | // unspecified elements/rows/matrices will be defaulted to all 0 (non-MSVC C only) 30 | KrausMap b = createInlineKrausMap(2, 5, { 31 | { 32 | {1,2,3,4}, 33 | {1i,2i,3i}, 34 | {4i,5i}, 35 | {6} 36 | }, { 37 | {6,7,8,9}, 38 | {9,8,7,6}, 39 | }, { 40 | {1} 41 | } 42 | }); 43 | reportKrausMap(b); 44 | destroyKrausMap(b); 45 | } 46 | 47 | 48 | void demo_setInlineKrausMap() { 49 | 50 | // inline literal without C99 compound-literal syntax (non-MSVC only) 51 | KrausMap a = createKrausMap(1, 3); 52 | setInlineKrausMap(a, 1, 3, { 53 | {{1,2},{3,4}}, 54 | {{5,5},{6,6}}, 55 | {{1i,2i},{-3i,-4i}} 56 | }); 57 | reportKrausMap(a); 58 | destroyKrausMap(a); 59 | 60 | // unspecified elements/rows/matrices will be defaulted to all 0 (non-MSVC C only) 61 | KrausMap b = createKrausMap(2, 5); 62 | setInlineKrausMap(b, 2, 5, { 63 | { 64 | {1,2,3,4}, 65 | {1i,2i,3i}, 66 | {4i,5i}, 67 | {6} 68 | }, { 69 | {6,7,8,9}, 70 | {9,8,7,6}, 71 | }, { 72 | {1} 73 | } 74 | }); 75 | reportKrausMap(b); 76 | destroyKrausMap(b); 77 | } 78 | 79 | 80 | void demo_setKrausMap() { 81 | 82 | // 3D compile-time array passed to VLA arg (non-MSVC C only) 83 | qcomp arr[2][4][4] = { 84 | { 85 | {1,2,3,4}, 86 | {5,6,7,8}, 87 | {9,8,7,6}, 88 | {5,4,3,2}, 89 | }, { 90 | {1i,2i,3i}, 91 | {5i} 92 | } 93 | }; 94 | KrausMap a = createKrausMap(2, 2); 95 | setKrausMap(a, arr); 96 | reportKrausMap(a); 97 | destroyKrausMap(a); 98 | 99 | // 3D VLA (non-MSVC C only) 100 | int nQb = 2; 101 | int nOps = 3; 102 | int dim = 1 << nQb; 103 | qcomp elems[nOps][dim][dim]; 104 | for (int n=0; n VLA (non-MSVC C only) 141 | KrausMap e = createKrausMap(1, 3); 142 | setKrausMap(e, (qcomp[3][2][2]) { 143 | {{1,2},{3,4}}, 144 | {{5,6},{7,8}}, 145 | {{9}} 146 | }); 147 | reportKrausMap(e); 148 | destroyKrausMap(e); 149 | 150 | // cleanup 151 | for (int n=0; n